All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
@ 2018-04-19 16:27 ` Peter Rosin
  0 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-19 16:27 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, David Airlie, Rob Herring, Mark Rutland,
	Nicolas Ferre, Alexandre Belloni, Boris Brezillon, Daniel Vetter,
	Gustavo Padovan, Sean Paul, Russell King, Laurent Pinchart,
	Jacopo Mondi, dri-devel, devicetree, linux-arm-kernel

Hi!

I naively thought that since there was support for both nxp,tda19988 (in
the tda998x driver) and the atmel-hlcdc, things would be a smooth ride.
But it wasn't, so I started looking around and realized I had to fix
things.

In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
component, but now in v3 I fix things by making the tda998x driver
a bridge instead. This was after a suggestion from Boris Brezillion
(the atmel-hlcdc maintainer), so there was some risk of bias ... but
after comparing what was needed, I too find the bridge approach better.

In addition to the above, our PCB interface between the SAMA5D3 and the
HDMI encoder is only using 16 bits, and this has to be described
somewhere, or the atmel-hlcdc driver have no chance of selecting the
correct output mode. Since I have similar problems with a ds90c185 lvds
encoder I added patches to override the atmel-hlcdc output format via
DT properties compatible with the media video-interface binding and
things start to play together.

Since this series superseeds the bridge series [1], I have included the
leftover bindings patch for the ti,ds90c185 here.

Anyway, this series solves some real issues for my HW.

Cheers,
Peter

Changes since v2   https://lkml.org/lkml/2018/4/17/385
- patch 2/7 fixed spelling and added an example
- patch 4/7 parse the DT up front and store the result indexed by encoder
- old patch 5/6 and 6/6 dropped
- patch 5-7/7 are new and makes the tda998x driver a drm_bridge

Changes since v1   https://lkml.org/lkml/2018/4/9/294
- added reviewed-by from Rob to patch 1/6
- patch 2/6 changed so that the bus format override is in the endpoint
  DT node, and follows the binding of media video-interfaces.
- patch 3/6 is new, it adds drm_of_media_bus_fmt which parses above
  media video-interface binding (partially).
- patch 4/6 now makes use of the above helper (and also fixes problems
  with the 3/5 patch from v1 when no override was specified).
- do not mention unrelated connector display_info details in the cover
  letter and commit messages.

[1]
"Bridge" series v2   https://lkml.org/lkml/2018/3/26/610
"Bridge" series v1   https://lkml.org/lkml/2018/3/17/221

Peter Rosin (7):
  dt-bindings: display: bridge: lvds-transmitter: add ti,ds90c185
  dt-bindings: display: atmel: optional video-interface of endpoints
  drm: of: introduce drm_of_media_bus_fmt
  drm/atmel-hlcdc: support bus-width (12/16/18/24) in endpoint nodes
  drm/i2c: tda998x: find the drm_device via the drm_connector
  drm/i2c: tda998x: split encoder and component functions from the work
  drm/i2c: tda998x: register as a drm bridge

 .../devicetree/bindings/display/atmel/hlcdc-dc.txt |  26 +++
 .../bindings/display/bridge/lvds-transmitter.txt   |   8 +-
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c     |  71 ++++++--
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h       |   2 +
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c   |  40 +++-
 drivers/gpu/drm/drm_of.c                           |  38 ++++
 drivers/gpu/drm/i2c/tda998x_drv.c                  | 201 ++++++++++++++++++---
 include/drm/drm_of.h                               |   7 +
 8 files changed, 342 insertions(+), 51 deletions(-)

-- 
2.11.0

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

* [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
@ 2018-04-19 16:27 ` Peter Rosin
  0 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-19 16:27 UTC (permalink / raw)
  To: linux-arm-kernel

Hi!

I naively thought that since there was support for both nxp,tda19988 (in
the tda998x driver) and the atmel-hlcdc, things would be a smooth ride.
But it wasn't, so I started looking around and realized I had to fix
things.

In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
component, but now in v3 I fix things by making the tda998x driver
a bridge instead. This was after a suggestion from Boris Brezillion
(the atmel-hlcdc maintainer), so there was some risk of bias ... but
after comparing what was needed, I too find the bridge approach better.

In addition to the above, our PCB interface between the SAMA5D3 and the
HDMI encoder is only using 16 bits, and this has to be described
somewhere, or the atmel-hlcdc driver have no chance of selecting the
correct output mode. Since I have similar problems with a ds90c185 lvds
encoder I added patches to override the atmel-hlcdc output format via
DT properties compatible with the media video-interface binding and
things start to play together.

Since this series superseeds the bridge series [1], I have included the
leftover bindings patch for the ti,ds90c185 here.

Anyway, this series solves some real issues for my HW.

Cheers,
Peter

Changes since v2   https://lkml.org/lkml/2018/4/17/385
- patch 2/7 fixed spelling and added an example
- patch 4/7 parse the DT up front and store the result indexed by encoder
- old patch 5/6 and 6/6 dropped
- patch 5-7/7 are new and makes the tda998x driver a drm_bridge

Changes since v1   https://lkml.org/lkml/2018/4/9/294
- added reviewed-by from Rob to patch 1/6
- patch 2/6 changed so that the bus format override is in the endpoint
  DT node, and follows the binding of media video-interfaces.
- patch 3/6 is new, it adds drm_of_media_bus_fmt which parses above
  media video-interface binding (partially).
- patch 4/6 now makes use of the above helper (and also fixes problems
  with the 3/5 patch from v1 when no override was specified).
- do not mention unrelated connector display_info details in the cover
  letter and commit messages.

[1]
"Bridge" series v2   https://lkml.org/lkml/2018/3/26/610
"Bridge" series v1   https://lkml.org/lkml/2018/3/17/221

Peter Rosin (7):
  dt-bindings: display: bridge: lvds-transmitter: add ti,ds90c185
  dt-bindings: display: atmel: optional video-interface of endpoints
  drm: of: introduce drm_of_media_bus_fmt
  drm/atmel-hlcdc: support bus-width (12/16/18/24) in endpoint nodes
  drm/i2c: tda998x: find the drm_device via the drm_connector
  drm/i2c: tda998x: split encoder and component functions from the work
  drm/i2c: tda998x: register as a drm bridge

 .../devicetree/bindings/display/atmel/hlcdc-dc.txt |  26 +++
 .../bindings/display/bridge/lvds-transmitter.txt   |   8 +-
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c     |  71 ++++++--
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h       |   2 +
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c   |  40 +++-
 drivers/gpu/drm/drm_of.c                           |  38 ++++
 drivers/gpu/drm/i2c/tda998x_drv.c                  | 201 ++++++++++++++++++---
 include/drm/drm_of.h                               |   7 +
 8 files changed, 342 insertions(+), 51 deletions(-)

-- 
2.11.0

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

* [PATCH v3 1/7] dt-bindings: display: bridge: lvds-transmitter: add ti,ds90c185
  2018-04-19 16:27 ` Peter Rosin
@ 2018-04-19 16:27   ` Peter Rosin
  -1 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-19 16:27 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, David Airlie, Rob Herring, Mark Rutland,
	Nicolas Ferre, Alexandre Belloni, Boris Brezillon, Daniel Vetter,
	Gustavo Padovan, Sean Paul, Russell King, Laurent Pinchart,
	Jacopo Mondi, dri-devel, devicetree, linux-arm-kernel

Start list of actual chips compatible with "lvds-encoder".

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Peter Rosin <peda@axentia.se>
---
 .../devicetree/bindings/display/bridge/lvds-transmitter.txt       | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt
index fd39ad34c383..50220190c203 100644
--- a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt
+++ b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt
@@ -22,7 +22,13 @@ among others.
 
 Required properties:
 
-- compatible: Must be "lvds-encoder"
+- compatible: Must be one or more of the following
+  - "ti,ds90c185" for the TI DS90C185 FPD-Link Serializer
+  - "lvds-encoder" for a generic LVDS encoder device
+
+  When compatible with the generic version, nodes must list the
+  device-specific version corresponding to the device first
+  followed by the generic version.
 
 Required nodes:
 
-- 
2.11.0

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

* [PATCH v3 1/7] dt-bindings: display: bridge: lvds-transmitter: add ti, ds90c185
@ 2018-04-19 16:27   ` Peter Rosin
  0 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-19 16:27 UTC (permalink / raw)
  To: linux-arm-kernel

Start list of actual chips compatible with "lvds-encoder".

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Peter Rosin <peda@axentia.se>
---
 .../devicetree/bindings/display/bridge/lvds-transmitter.txt       | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt
index fd39ad34c383..50220190c203 100644
--- a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt
+++ b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt
@@ -22,7 +22,13 @@ among others.
 
 Required properties:
 
-- compatible: Must be "lvds-encoder"
+- compatible: Must be one or more of the following
+  - "ti,ds90c185" for the TI DS90C185 FPD-Link Serializer
+  - "lvds-encoder" for a generic LVDS encoder device
+
+  When compatible with the generic version, nodes must list the
+  device-specific version corresponding to the device first
+  followed by the generic version.
 
 Required nodes:
 
-- 
2.11.0

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

* [PATCH v3 2/7] dt-bindings: display: atmel: optional video-interface of endpoints
  2018-04-19 16:27 ` Peter Rosin
@ 2018-04-19 16:27   ` Peter Rosin
  -1 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-19 16:27 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, David Airlie, Rob Herring, Mark Rutland,
	Nicolas Ferre, Alexandre Belloni, Boris Brezillon, Daniel Vetter,
	Gustavo Padovan, Sean Paul, Russell King, Laurent Pinchart,
	Jacopo Mondi, dri-devel, devicetree, linux-arm-kernel

With bus-type/bus-width properties in the endpoint nodes, the video-
interface of the connection can be specified for cases where the
heuristic fails to select the correct output mode. This can happen
e.g. if not all RGB pins are routed on the PCB; the driver has no
way of knowing this, and needs to be told explicitly.

This is critical for the devices that have the "conflicting output
formats" issue (SAM9N12, SAM9X5, SAMA5D3), since the most significant
RGB bits move around depending on the selected output mode. For
devices that do not have the "conflicting output formats" issue
(SAMA5D2, SAMA5D4), this is completely irrelevant.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 .../devicetree/bindings/display/atmel/hlcdc-dc.txt | 26 ++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt b/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt
index 82f2acb3d374..9de434a8f523 100644
--- a/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt
+++ b/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt
@@ -15,6 +15,14 @@ Required children nodes:
  to external devices using the OF graph reprensentation (see ../graph.txt).
  At least one port node is required.
 
+Optional properties in grandchild nodes:
+ Any endpoint grandchild node may specify a desired video interface
+ according to ../../media/video-interfaces.txt, specifically
+ - bus-type: must be <0>.
+ - bus-width: recognized values are <12>, <16>, <18> and <24>, and
+   override any output mode selection heuristic, forcing "rgb444",
+   "rgb565", "rgb666" and "rgb888" respectively.
+
 Example:
 
 	hlcdc: hlcdc@f0030000 {
@@ -50,3 +58,21 @@ Example:
 			#pwm-cells = <3>;
 		};
 	};
+
+
+Example 2: With a video interface override to force rgb565; as above
+but with these changes/additions:
+
+	&hlcdc {
+		hlcdc-display-controller {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb565>;
+
+			port@0 {
+				hlcdc_panel_output: endpoint@0 {
+					bus-type = <0>;
+					bus-width = <16>;
+				};
+			};
+		};
+	};
-- 
2.11.0

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

* [PATCH v3 2/7] dt-bindings: display: atmel: optional video-interface of endpoints
@ 2018-04-19 16:27   ` Peter Rosin
  0 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-19 16:27 UTC (permalink / raw)
  To: linux-arm-kernel

With bus-type/bus-width properties in the endpoint nodes, the video-
interface of the connection can be specified for cases where the
heuristic fails to select the correct output mode. This can happen
e.g. if not all RGB pins are routed on the PCB; the driver has no
way of knowing this, and needs to be told explicitly.

This is critical for the devices that have the "conflicting output
formats" issue (SAM9N12, SAM9X5, SAMA5D3), since the most significant
RGB bits move around depending on the selected output mode. For
devices that do not have the "conflicting output formats" issue
(SAMA5D2, SAMA5D4), this is completely irrelevant.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 .../devicetree/bindings/display/atmel/hlcdc-dc.txt | 26 ++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt b/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt
index 82f2acb3d374..9de434a8f523 100644
--- a/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt
+++ b/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt
@@ -15,6 +15,14 @@ Required children nodes:
  to external devices using the OF graph reprensentation (see ../graph.txt).
  At least one port node is required.
 
+Optional properties in grandchild nodes:
+ Any endpoint grandchild node may specify a desired video interface
+ according to ../../media/video-interfaces.txt, specifically
+ - bus-type: must be <0>.
+ - bus-width: recognized values are <12>, <16>, <18> and <24>, and
+   override any output mode selection heuristic, forcing "rgb444",
+   "rgb565", "rgb666" and "rgb888" respectively.
+
 Example:
 
 	hlcdc: hlcdc at f0030000 {
@@ -50,3 +58,21 @@ Example:
 			#pwm-cells = <3>;
 		};
 	};
+
+
+Example 2: With a video interface override to force rgb565; as above
+but with these changes/additions:
+
+	&hlcdc {
+		hlcdc-display-controller {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb565>;
+
+			port at 0 {
+				hlcdc_panel_output: endpoint at 0 {
+					bus-type = <0>;
+					bus-width = <16>;
+				};
+			};
+		};
+	};
-- 
2.11.0

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

* [PATCH v3 3/7] drm: of: introduce drm_of_media_bus_fmt
  2018-04-19 16:27 ` Peter Rosin
@ 2018-04-19 16:27   ` Peter Rosin
  -1 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-19 16:27 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, David Airlie, Rob Herring, Mark Rutland,
	Nicolas Ferre, Alexandre Belloni, Boris Brezillon, Daniel Vetter,
	Gustavo Padovan, Sean Paul, Russell King, Laurent Pinchart,
	Jacopo Mondi, dri-devel, devicetree, linux-arm-kernel

Add a central function to parse a node according to the video
interface binding and get a media bus format.

Start with only supporting a very limited set of a few basic media
bus formats.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/gpu/drm/drm_of.c | 38 ++++++++++++++++++++++++++++++++++++++
 include/drm/drm_of.h     |  7 +++++++
 2 files changed, 45 insertions(+)

diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c
index 4c191c050e7d..f9473edb60a7 100644
--- a/drivers/gpu/drm/drm_of.c
+++ b/drivers/gpu/drm/drm_of.c
@@ -212,6 +212,44 @@ int drm_of_encoder_active_endpoint(struct device_node *node,
 EXPORT_SYMBOL_GPL(drm_of_encoder_active_endpoint);
 
 /*
+ * drm_of_media_bus_fmt - return the media bus format described in the node
+ * @node: device tree node containing the media bus format
+ *
+ * @node is presumably an of-graph endpoint node.
+ *
+ * Return the media bus format, or zero if none is described. Or one of the
+ * standard error codes.
+ */
+int drm_of_media_bus_fmt(struct device_node *node)
+{
+	s32 bus_type;
+	u32 bus_width = 0;
+
+	if (!node)
+		return -EINVAL;
+
+	if (of_property_read_u32(node, "bus-type", &bus_type))
+		return 0;
+	if (bus_type != 0)
+		return -EINVAL;
+
+	of_property_read_u32(node, "bus-width", &bus_width);
+	switch (bus_width) {
+	case 12:
+		return MEDIA_BUS_FMT_RGB444_1X12;
+	case 16:
+		return MEDIA_BUS_FMT_RGB565_1X16;
+	case 18:
+		return MEDIA_BUS_FMT_RGB666_1X18;
+	case 24:
+		return MEDIA_BUS_FMT_RGB888_1X24;
+	default:
+		return -EINVAL;
+	}
+}
+EXPORT_SYMBOL_GPL(drm_of_media_bus_fmt);
+
+/*
  * drm_of_find_panel_or_bridge - return connected panel or bridge device
  * @np: device tree node containing encoder output ports
  * @panel: pointer to hold returned drm_panel
diff --git a/include/drm/drm_of.h b/include/drm/drm_of.h
index b93c239afb60..f86f0098b21e 100644
--- a/include/drm/drm_of.h
+++ b/include/drm/drm_of.h
@@ -29,6 +29,7 @@ int drm_of_component_probe(struct device *dev,
 int drm_of_encoder_active_endpoint(struct device_node *node,
 				   struct drm_encoder *encoder,
 				   struct of_endpoint *endpoint);
+int drm_of_media_bus_fmt(struct device_node *node);
 int drm_of_find_panel_or_bridge(const struct device_node *np,
 				int port, int endpoint,
 				struct drm_panel **panel,
@@ -62,6 +63,12 @@ static inline int drm_of_encoder_active_endpoint(struct device_node *node,
 {
 	return -EINVAL;
 }
+
+static inline int drm_of_media_bus_fmt(struct device_node *node)
+{
+	return -EINVAL;
+}
+
 static inline int drm_of_find_panel_or_bridge(const struct device_node *np,
 					      int port, int endpoint,
 					      struct drm_panel **panel,
-- 
2.11.0

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

* [PATCH v3 3/7] drm: of: introduce drm_of_media_bus_fmt
@ 2018-04-19 16:27   ` Peter Rosin
  0 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-19 16:27 UTC (permalink / raw)
  To: linux-arm-kernel

Add a central function to parse a node according to the video
interface binding and get a media bus format.

Start with only supporting a very limited set of a few basic media
bus formats.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/gpu/drm/drm_of.c | 38 ++++++++++++++++++++++++++++++++++++++
 include/drm/drm_of.h     |  7 +++++++
 2 files changed, 45 insertions(+)

diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c
index 4c191c050e7d..f9473edb60a7 100644
--- a/drivers/gpu/drm/drm_of.c
+++ b/drivers/gpu/drm/drm_of.c
@@ -212,6 +212,44 @@ int drm_of_encoder_active_endpoint(struct device_node *node,
 EXPORT_SYMBOL_GPL(drm_of_encoder_active_endpoint);
 
 /*
+ * drm_of_media_bus_fmt - return the media bus format described in the node
+ * @node: device tree node containing the media bus format
+ *
+ * @node is presumably an of-graph endpoint node.
+ *
+ * Return the media bus format, or zero if none is described. Or one of the
+ * standard error codes.
+ */
+int drm_of_media_bus_fmt(struct device_node *node)
+{
+	s32 bus_type;
+	u32 bus_width = 0;
+
+	if (!node)
+		return -EINVAL;
+
+	if (of_property_read_u32(node, "bus-type", &bus_type))
+		return 0;
+	if (bus_type != 0)
+		return -EINVAL;
+
+	of_property_read_u32(node, "bus-width", &bus_width);
+	switch (bus_width) {
+	case 12:
+		return MEDIA_BUS_FMT_RGB444_1X12;
+	case 16:
+		return MEDIA_BUS_FMT_RGB565_1X16;
+	case 18:
+		return MEDIA_BUS_FMT_RGB666_1X18;
+	case 24:
+		return MEDIA_BUS_FMT_RGB888_1X24;
+	default:
+		return -EINVAL;
+	}
+}
+EXPORT_SYMBOL_GPL(drm_of_media_bus_fmt);
+
+/*
  * drm_of_find_panel_or_bridge - return connected panel or bridge device
  * @np: device tree node containing encoder output ports
  * @panel: pointer to hold returned drm_panel
diff --git a/include/drm/drm_of.h b/include/drm/drm_of.h
index b93c239afb60..f86f0098b21e 100644
--- a/include/drm/drm_of.h
+++ b/include/drm/drm_of.h
@@ -29,6 +29,7 @@ int drm_of_component_probe(struct device *dev,
 int drm_of_encoder_active_endpoint(struct device_node *node,
 				   struct drm_encoder *encoder,
 				   struct of_endpoint *endpoint);
+int drm_of_media_bus_fmt(struct device_node *node);
 int drm_of_find_panel_or_bridge(const struct device_node *np,
 				int port, int endpoint,
 				struct drm_panel **panel,
@@ -62,6 +63,12 @@ static inline int drm_of_encoder_active_endpoint(struct device_node *node,
 {
 	return -EINVAL;
 }
+
+static inline int drm_of_media_bus_fmt(struct device_node *node)
+{
+	return -EINVAL;
+}
+
 static inline int drm_of_find_panel_or_bridge(const struct device_node *np,
 					      int port, int endpoint,
 					      struct drm_panel **panel,
-- 
2.11.0

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

* [PATCH v3 4/7] drm/atmel-hlcdc: support bus-width (12/16/18/24) in endpoint nodes
  2018-04-19 16:27 ` Peter Rosin
@ 2018-04-19 16:27   ` Peter Rosin
  -1 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-19 16:27 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, David Airlie, Rob Herring, Mark Rutland,
	Nicolas Ferre, Alexandre Belloni, Boris Brezillon, Daniel Vetter,
	Gustavo Padovan, Sean Paul, Russell King, Laurent Pinchart,
	Jacopo Mondi, dri-devel, devicetree, linux-arm-kernel

This beats the heuristic that the connector is involved in what format
should be output for cases where this fails.

E.g. if there is a bridge that changes format between the encoder and the
connector, or if some of the RGB pins between the lcd controller and the
encoder are not routed on the PCB.

This is critical for the devices that have the "conflicting output
formats" issue (SAM9N12, SAM9X5, SAMA5D3), since the most significant
RGB bits move around depending on the selected output mode. For
devices that do not have the "conflicting output formats" issue
(SAMA5D2, SAMA5D4), this is completely irrelevant.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c   | 71 +++++++++++++++++-------
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h     |  2 +
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 40 ++++++++++++-
 3 files changed, 92 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
index d73281095fac..b4e7f5b6f497 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
@@ -226,6 +226,56 @@ static void atmel_hlcdc_crtc_atomic_enable(struct drm_crtc *c,
 #define ATMEL_HLCDC_RGB888_OUTPUT	BIT(3)
 #define ATMEL_HLCDC_OUTPUT_MODE_MASK	GENMASK(3, 0)
 
+static int atmel_hlcdc_connector_output_mode(struct drm_connector_state *state)
+{
+	struct drm_connector *connector = state->connector;
+	struct atmel_hlcdc_dc *dc = connector->dev->dev_private;
+	struct drm_encoder *encoder;
+	struct drm_display_info *info = &connector->display_info;
+	unsigned int supported_fmts = 0;
+	int j;
+
+	encoder = state->best_encoder;
+	if (!encoder)
+		encoder = connector->encoder;
+
+	switch (dc->bus_fmt[encoder->index]) {
+	case 0:
+		break;
+	case MEDIA_BUS_FMT_RGB444_1X12:
+		return ATMEL_HLCDC_RGB444_OUTPUT;
+	case MEDIA_BUS_FMT_RGB565_1X16:
+		return ATMEL_HLCDC_RGB565_OUTPUT;
+	case MEDIA_BUS_FMT_RGB666_1X18:
+		return ATMEL_HLCDC_RGB666_OUTPUT;
+	case MEDIA_BUS_FMT_RGB888_1X24:
+		return ATMEL_HLCDC_RGB888_OUTPUT;
+	default:
+		return -EINVAL;
+	}
+
+	for (j = 0; j < info->num_bus_formats; j++) {
+		switch (info->bus_formats[j]) {
+		case MEDIA_BUS_FMT_RGB444_1X12:
+			supported_fmts |= ATMEL_HLCDC_RGB444_OUTPUT;
+			break;
+		case MEDIA_BUS_FMT_RGB565_1X16:
+			supported_fmts |= ATMEL_HLCDC_RGB565_OUTPUT;
+			break;
+		case MEDIA_BUS_FMT_RGB666_1X18:
+			supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT;
+			break;
+		case MEDIA_BUS_FMT_RGB888_1X24:
+			supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT;
+			break;
+		default:
+			break;
+		}
+	}
+
+	return supported_fmts;
+}
+
 static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state)
 {
 	unsigned int output_fmts = ATMEL_HLCDC_OUTPUT_MODE_MASK;
@@ -238,31 +288,12 @@ static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state)
 	crtc = drm_crtc_to_atmel_hlcdc_crtc(state->crtc);
 
 	for_each_new_connector_in_state(state->state, connector, cstate, i) {
-		struct drm_display_info *info = &connector->display_info;
 		unsigned int supported_fmts = 0;
-		int j;
 
 		if (!cstate->crtc)
 			continue;
 
-		for (j = 0; j < info->num_bus_formats; j++) {
-			switch (info->bus_formats[j]) {
-			case MEDIA_BUS_FMT_RGB444_1X12:
-				supported_fmts |= ATMEL_HLCDC_RGB444_OUTPUT;
-				break;
-			case MEDIA_BUS_FMT_RGB565_1X16:
-				supported_fmts |= ATMEL_HLCDC_RGB565_OUTPUT;
-				break;
-			case MEDIA_BUS_FMT_RGB666_1X18:
-				supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT;
-				break;
-			case MEDIA_BUS_FMT_RGB888_1X24:
-				supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT;
-				break;
-			default:
-				break;
-			}
-		}
+		supported_fmts = atmel_hlcdc_connector_output_mode(cstate);
 
 		if (crtc->dc->desc->conflicting_output_formats)
 			output_fmts &= supported_fmts;
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
index ab32d5b268d2..be2d180dd169 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
@@ -365,6 +365,7 @@ struct atmel_hlcdc_plane_properties {
  * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
  * @fbdev: framebuffer device attached to the Display Controller
  * @crtc: CRTC provided by the display controller
+ * @bus_fmt: Array of bus format overrides, per connector.
  * @planes: instantiated planes
  * @layers: active HLCDC layers
  * @wq: display controller workqueue
@@ -376,6 +377,7 @@ struct atmel_hlcdc_dc {
 	struct dma_pool *dscrpool;
 	struct atmel_hlcdc *hlcdc;
 	struct drm_crtc *crtc;
+	int *bus_fmt;
 	struct atmel_hlcdc_layer *layers[ATMEL_HLCDC_MAX_LAYERS];
 	struct workqueue_struct *wq;
 	struct {
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
index 8db51fb131db..8787e2890c93 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
@@ -77,10 +77,48 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint)
 
 int atmel_hlcdc_create_outputs(struct drm_device *dev)
 {
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	struct device_node *ep;
+	int count = of_graph_get_endpoint_count(dev->dev->of_node);
 	int endpoint, ret = 0;
 
-	for (endpoint = 0; !ret; endpoint++)
+	/*
+	 * Assume that each endpoint will create a single encoder
+	 * so that the encoder index can be used as index into
+	 * this bus_fmt array.
+	 */
+	dc->bus_fmt = devm_kzalloc(dev->dev, count * sizeof(*dc->bus_fmt),
+				   GFP_KERNEL);
+	if (!dc->bus_fmt)
+		return -ENOMEM;
+
+	for (endpoint = 0; !ret; endpoint++) {
+		ep = of_graph_get_endpoint_by_regs(dev->dev->of_node, 0,
+						   endpoint);
+		if (!ep) {
+			ret = -ENODEV;
+			break;
+		}
+
+		dc->bus_fmt[endpoint] = drm_of_media_bus_fmt(ep);
+
+		switch (dc->bus_fmt[endpoint]) {
+		case 0:
+		case MEDIA_BUS_FMT_RGB444_1X12:
+		case MEDIA_BUS_FMT_RGB565_1X16:
+		case MEDIA_BUS_FMT_RGB666_1X18:
+		case MEDIA_BUS_FMT_RGB888_1X24:
+			break;
+		default:
+			ret = dc->bus_fmt[endpoint];
+			if (ret > 0)
+				ret = -EINVAL;
+		}
+		if (ret < 0)
+			break;
+
 		ret = atmel_hlcdc_attach_endpoint(dev, endpoint);
+	}
 
 	/* At least one device was successfully attached.*/
 	if (ret == -ENODEV && endpoint)
-- 
2.11.0

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

* [PATCH v3 4/7] drm/atmel-hlcdc: support bus-width (12/16/18/24) in endpoint nodes
@ 2018-04-19 16:27   ` Peter Rosin
  0 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-19 16:27 UTC (permalink / raw)
  To: linux-arm-kernel

This beats the heuristic that the connector is involved in what format
should be output for cases where this fails.

E.g. if there is a bridge that changes format between the encoder and the
connector, or if some of the RGB pins between the lcd controller and the
encoder are not routed on the PCB.

This is critical for the devices that have the "conflicting output
formats" issue (SAM9N12, SAM9X5, SAMA5D3), since the most significant
RGB bits move around depending on the selected output mode. For
devices that do not have the "conflicting output formats" issue
(SAMA5D2, SAMA5D4), this is completely irrelevant.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c   | 71 +++++++++++++++++-------
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h     |  2 +
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 40 ++++++++++++-
 3 files changed, 92 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
index d73281095fac..b4e7f5b6f497 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
@@ -226,6 +226,56 @@ static void atmel_hlcdc_crtc_atomic_enable(struct drm_crtc *c,
 #define ATMEL_HLCDC_RGB888_OUTPUT	BIT(3)
 #define ATMEL_HLCDC_OUTPUT_MODE_MASK	GENMASK(3, 0)
 
+static int atmel_hlcdc_connector_output_mode(struct drm_connector_state *state)
+{
+	struct drm_connector *connector = state->connector;
+	struct atmel_hlcdc_dc *dc = connector->dev->dev_private;
+	struct drm_encoder *encoder;
+	struct drm_display_info *info = &connector->display_info;
+	unsigned int supported_fmts = 0;
+	int j;
+
+	encoder = state->best_encoder;
+	if (!encoder)
+		encoder = connector->encoder;
+
+	switch (dc->bus_fmt[encoder->index]) {
+	case 0:
+		break;
+	case MEDIA_BUS_FMT_RGB444_1X12:
+		return ATMEL_HLCDC_RGB444_OUTPUT;
+	case MEDIA_BUS_FMT_RGB565_1X16:
+		return ATMEL_HLCDC_RGB565_OUTPUT;
+	case MEDIA_BUS_FMT_RGB666_1X18:
+		return ATMEL_HLCDC_RGB666_OUTPUT;
+	case MEDIA_BUS_FMT_RGB888_1X24:
+		return ATMEL_HLCDC_RGB888_OUTPUT;
+	default:
+		return -EINVAL;
+	}
+
+	for (j = 0; j < info->num_bus_formats; j++) {
+		switch (info->bus_formats[j]) {
+		case MEDIA_BUS_FMT_RGB444_1X12:
+			supported_fmts |= ATMEL_HLCDC_RGB444_OUTPUT;
+			break;
+		case MEDIA_BUS_FMT_RGB565_1X16:
+			supported_fmts |= ATMEL_HLCDC_RGB565_OUTPUT;
+			break;
+		case MEDIA_BUS_FMT_RGB666_1X18:
+			supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT;
+			break;
+		case MEDIA_BUS_FMT_RGB888_1X24:
+			supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT;
+			break;
+		default:
+			break;
+		}
+	}
+
+	return supported_fmts;
+}
+
 static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state)
 {
 	unsigned int output_fmts = ATMEL_HLCDC_OUTPUT_MODE_MASK;
@@ -238,31 +288,12 @@ static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state)
 	crtc = drm_crtc_to_atmel_hlcdc_crtc(state->crtc);
 
 	for_each_new_connector_in_state(state->state, connector, cstate, i) {
-		struct drm_display_info *info = &connector->display_info;
 		unsigned int supported_fmts = 0;
-		int j;
 
 		if (!cstate->crtc)
 			continue;
 
-		for (j = 0; j < info->num_bus_formats; j++) {
-			switch (info->bus_formats[j]) {
-			case MEDIA_BUS_FMT_RGB444_1X12:
-				supported_fmts |= ATMEL_HLCDC_RGB444_OUTPUT;
-				break;
-			case MEDIA_BUS_FMT_RGB565_1X16:
-				supported_fmts |= ATMEL_HLCDC_RGB565_OUTPUT;
-				break;
-			case MEDIA_BUS_FMT_RGB666_1X18:
-				supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT;
-				break;
-			case MEDIA_BUS_FMT_RGB888_1X24:
-				supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT;
-				break;
-			default:
-				break;
-			}
-		}
+		supported_fmts = atmel_hlcdc_connector_output_mode(cstate);
 
 		if (crtc->dc->desc->conflicting_output_formats)
 			output_fmts &= supported_fmts;
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
index ab32d5b268d2..be2d180dd169 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
@@ -365,6 +365,7 @@ struct atmel_hlcdc_plane_properties {
  * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
  * @fbdev: framebuffer device attached to the Display Controller
  * @crtc: CRTC provided by the display controller
+ * @bus_fmt: Array of bus format overrides, per connector.
  * @planes: instantiated planes
  * @layers: active HLCDC layers
  * @wq: display controller workqueue
@@ -376,6 +377,7 @@ struct atmel_hlcdc_dc {
 	struct dma_pool *dscrpool;
 	struct atmel_hlcdc *hlcdc;
 	struct drm_crtc *crtc;
+	int *bus_fmt;
 	struct atmel_hlcdc_layer *layers[ATMEL_HLCDC_MAX_LAYERS];
 	struct workqueue_struct *wq;
 	struct {
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
index 8db51fb131db..8787e2890c93 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
@@ -77,10 +77,48 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint)
 
 int atmel_hlcdc_create_outputs(struct drm_device *dev)
 {
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	struct device_node *ep;
+	int count = of_graph_get_endpoint_count(dev->dev->of_node);
 	int endpoint, ret = 0;
 
-	for (endpoint = 0; !ret; endpoint++)
+	/*
+	 * Assume that each endpoint will create a single encoder
+	 * so that the encoder index can be used as index into
+	 * this bus_fmt array.
+	 */
+	dc->bus_fmt = devm_kzalloc(dev->dev, count * sizeof(*dc->bus_fmt),
+				   GFP_KERNEL);
+	if (!dc->bus_fmt)
+		return -ENOMEM;
+
+	for (endpoint = 0; !ret; endpoint++) {
+		ep = of_graph_get_endpoint_by_regs(dev->dev->of_node, 0,
+						   endpoint);
+		if (!ep) {
+			ret = -ENODEV;
+			break;
+		}
+
+		dc->bus_fmt[endpoint] = drm_of_media_bus_fmt(ep);
+
+		switch (dc->bus_fmt[endpoint]) {
+		case 0:
+		case MEDIA_BUS_FMT_RGB444_1X12:
+		case MEDIA_BUS_FMT_RGB565_1X16:
+		case MEDIA_BUS_FMT_RGB666_1X18:
+		case MEDIA_BUS_FMT_RGB888_1X24:
+			break;
+		default:
+			ret = dc->bus_fmt[endpoint];
+			if (ret > 0)
+				ret = -EINVAL;
+		}
+		if (ret < 0)
+			break;
+
 		ret = atmel_hlcdc_attach_endpoint(dev, endpoint);
+	}
 
 	/* At least one device was successfully attached.*/
 	if (ret == -ENODEV && endpoint)
-- 
2.11.0

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

* [PATCH v3 5/7] drm/i2c: tda998x: find the drm_device via the drm_connector
  2018-04-19 16:27 ` Peter Rosin
@ 2018-04-19 16:27   ` Peter Rosin
  -1 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-19 16:27 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, David Airlie, Rob Herring, Mark Rutland,
	Nicolas Ferre, Alexandre Belloni, Boris Brezillon, Daniel Vetter,
	Gustavo Padovan, Sean Paul, Russell King, Laurent Pinchart,
	Jacopo Mondi, dri-devel, devicetree, linux-arm-kernel

This prepares for being a drm_bridge which will not register the
encoder. That makes the connector the better choice.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/gpu/drm/i2c/tda998x_drv.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index cd3f0873bbdd..8f6e013f2b87 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -630,7 +630,7 @@ static void tda998x_detect_work(struct work_struct *work)
 {
 	struct tda998x_priv *priv =
 		container_of(work, struct tda998x_priv, detect_work);
-	struct drm_device *dev = priv->encoder.dev;
+	struct drm_device *dev = priv->connector.dev;
 
 	if (dev)
 		drm_kms_helper_hotplug_event(dev);
-- 
2.11.0

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

* [PATCH v3 5/7] drm/i2c: tda998x: find the drm_device via the drm_connector
@ 2018-04-19 16:27   ` Peter Rosin
  0 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-19 16:27 UTC (permalink / raw)
  To: linux-arm-kernel

This prepares for being a drm_bridge which will not register the
encoder. That makes the connector the better choice.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/gpu/drm/i2c/tda998x_drv.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index cd3f0873bbdd..8f6e013f2b87 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -630,7 +630,7 @@ static void tda998x_detect_work(struct work_struct *work)
 {
 	struct tda998x_priv *priv =
 		container_of(work, struct tda998x_priv, detect_work);
-	struct drm_device *dev = priv->encoder.dev;
+	struct drm_device *dev = priv->connector.dev;
 
 	if (dev)
 		drm_kms_helper_hotplug_event(dev);
-- 
2.11.0

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

* [PATCH v3 6/7] drm/i2c: tda998x: split encoder and component functions from the work
  2018-04-19 16:27 ` Peter Rosin
@ 2018-04-19 16:27   ` Peter Rosin
  -1 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-19 16:27 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, David Airlie, Rob Herring, Mark Rutland,
	Nicolas Ferre, Alexandre Belloni, Boris Brezillon, Daniel Vetter,
	Gustavo Padovan, Sean Paul, Russell King, Laurent Pinchart,
	Jacopo Mondi, dri-devel, devicetree, linux-arm-kernel

This enables reuse of the machinery for the case where a drm_bridge
needs to do the same work via different interfaces.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/gpu/drm/i2c/tda998x_drv.c | 46 ++++++++++++++++++++++++++++++---------
 1 file changed, 36 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index 8f6e013f2b87..9c78f7bde49c 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -1163,9 +1163,8 @@ static int tda998x_connector_init(struct tda998x_priv *priv,
 
 /* DRM encoder functions */
 
-static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
+static void tda998x_dpms(struct tda998x_priv *priv, int mode)
 {
-	struct tda998x_priv *priv = enc_to_tda998x_priv(encoder);
 	bool on;
 
 	/* we only care about on or off: */
@@ -1195,12 +1194,18 @@ static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
 	}
 }
 
-static void
-tda998x_encoder_mode_set(struct drm_encoder *encoder,
-			 struct drm_display_mode *mode,
-			 struct drm_display_mode *adjusted_mode)
+static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
 {
 	struct tda998x_priv *priv = enc_to_tda998x_priv(encoder);
+
+	tda998x_dpms(priv, mode);
+}
+
+static void
+tda998x_mode_set(struct tda998x_priv *priv,
+		 struct drm_display_mode *mode,
+		 struct drm_display_mode *adjusted_mode)
+{
 	u16 ref_pix, ref_line, n_pix, n_line;
 	u16 hs_pix_s, hs_pix_e;
 	u16 vs1_pix_s, vs1_pix_e, vs1_line_s, vs1_line_e;
@@ -1407,6 +1412,16 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,
 	mutex_unlock(&priv->audio_mutex);
 }
 
+static void
+tda998x_encoder_mode_set(struct drm_encoder *encoder,
+			 struct drm_display_mode *mode,
+			 struct drm_display_mode *adjusted_mode)
+{
+	struct tda998x_priv *priv = enc_to_tda998x_priv(encoder);
+
+	tda998x_mode_set(priv, mode, adjusted_mode);
+}
+
 static void tda998x_destroy(struct tda998x_priv *priv)
 {
 	/* disable all IRQs and free the IRQ handler */
@@ -1653,11 +1668,10 @@ static void tda998x_set_config(struct tda998x_priv *priv,
 	priv->audio_params = p->audio_params;
 }
 
-static int tda998x_bind(struct device *dev, struct device *master, void *data)
+static int tda998x_init(struct device *dev, struct drm_device *drm)
 {
 	struct tda998x_encoder_params *params = dev->platform_data;
 	struct i2c_client *client = to_i2c_client(dev);
-	struct drm_device *drm = data;
 	struct tda998x_priv *priv;
 	u32 crtcs = 0;
 	int ret;
@@ -1705,8 +1719,7 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data)
 	return ret;
 }
 
-static void tda998x_unbind(struct device *dev, struct device *master,
-			   void *data)
+static void tda998x_fini(struct device *dev)
 {
 	struct tda998x_priv *priv = dev_get_drvdata(dev);
 
@@ -1715,6 +1728,19 @@ static void tda998x_unbind(struct device *dev, struct device *master,
 	tda998x_destroy(priv);
 }
 
+static int tda998x_bind(struct device *dev, struct device *master, void *data)
+{
+	struct drm_device *drm = data;
+
+	return tda998x_init(dev, drm);
+}
+
+static void tda998x_unbind(struct device *dev, struct device *master,
+			   void *data)
+{
+	tda998x_fini(dev);
+}
+
 static const struct component_ops tda998x_ops = {
 	.bind = tda998x_bind,
 	.unbind = tda998x_unbind,
-- 
2.11.0

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

* [PATCH v3 6/7] drm/i2c: tda998x: split encoder and component functions from the work
@ 2018-04-19 16:27   ` Peter Rosin
  0 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-19 16:27 UTC (permalink / raw)
  To: linux-arm-kernel

This enables reuse of the machinery for the case where a drm_bridge
needs to do the same work via different interfaces.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/gpu/drm/i2c/tda998x_drv.c | 46 ++++++++++++++++++++++++++++++---------
 1 file changed, 36 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index 8f6e013f2b87..9c78f7bde49c 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -1163,9 +1163,8 @@ static int tda998x_connector_init(struct tda998x_priv *priv,
 
 /* DRM encoder functions */
 
-static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
+static void tda998x_dpms(struct tda998x_priv *priv, int mode)
 {
-	struct tda998x_priv *priv = enc_to_tda998x_priv(encoder);
 	bool on;
 
 	/* we only care about on or off: */
@@ -1195,12 +1194,18 @@ static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
 	}
 }
 
-static void
-tda998x_encoder_mode_set(struct drm_encoder *encoder,
-			 struct drm_display_mode *mode,
-			 struct drm_display_mode *adjusted_mode)
+static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
 {
 	struct tda998x_priv *priv = enc_to_tda998x_priv(encoder);
+
+	tda998x_dpms(priv, mode);
+}
+
+static void
+tda998x_mode_set(struct tda998x_priv *priv,
+		 struct drm_display_mode *mode,
+		 struct drm_display_mode *adjusted_mode)
+{
 	u16 ref_pix, ref_line, n_pix, n_line;
 	u16 hs_pix_s, hs_pix_e;
 	u16 vs1_pix_s, vs1_pix_e, vs1_line_s, vs1_line_e;
@@ -1407,6 +1412,16 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,
 	mutex_unlock(&priv->audio_mutex);
 }
 
+static void
+tda998x_encoder_mode_set(struct drm_encoder *encoder,
+			 struct drm_display_mode *mode,
+			 struct drm_display_mode *adjusted_mode)
+{
+	struct tda998x_priv *priv = enc_to_tda998x_priv(encoder);
+
+	tda998x_mode_set(priv, mode, adjusted_mode);
+}
+
 static void tda998x_destroy(struct tda998x_priv *priv)
 {
 	/* disable all IRQs and free the IRQ handler */
@@ -1653,11 +1668,10 @@ static void tda998x_set_config(struct tda998x_priv *priv,
 	priv->audio_params = p->audio_params;
 }
 
-static int tda998x_bind(struct device *dev, struct device *master, void *data)
+static int tda998x_init(struct device *dev, struct drm_device *drm)
 {
 	struct tda998x_encoder_params *params = dev->platform_data;
 	struct i2c_client *client = to_i2c_client(dev);
-	struct drm_device *drm = data;
 	struct tda998x_priv *priv;
 	u32 crtcs = 0;
 	int ret;
@@ -1705,8 +1719,7 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data)
 	return ret;
 }
 
-static void tda998x_unbind(struct device *dev, struct device *master,
-			   void *data)
+static void tda998x_fini(struct device *dev)
 {
 	struct tda998x_priv *priv = dev_get_drvdata(dev);
 
@@ -1715,6 +1728,19 @@ static void tda998x_unbind(struct device *dev, struct device *master,
 	tda998x_destroy(priv);
 }
 
+static int tda998x_bind(struct device *dev, struct device *master, void *data)
+{
+	struct drm_device *drm = data;
+
+	return tda998x_init(dev, drm);
+}
+
+static void tda998x_unbind(struct device *dev, struct device *master,
+			   void *data)
+{
+	tda998x_fini(dev);
+}
+
 static const struct component_ops tda998x_ops = {
 	.bind = tda998x_bind,
 	.unbind = tda998x_unbind,
-- 
2.11.0

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

* [PATCH v3 7/7] drm/i2c: tda998x: register as a drm bridge
  2018-04-19 16:27 ` Peter Rosin
@ 2018-04-19 16:27   ` Peter Rosin
  -1 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-19 16:27 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, David Airlie, Rob Herring, Mark Rutland,
	Nicolas Ferre, Alexandre Belloni, Boris Brezillon, Daniel Vetter,
	Gustavo Padovan, Sean Paul, Russell King, Laurent Pinchart,
	Jacopo Mondi, dri-devel, devicetree, linux-arm-kernel

This makes this driver work with all(?) drivers that are not
componentized and instead expect to connect to a panel/bridge. That
said, the only one tested is atmel_hlcdc.

This hooks the relevant work function previously called by the encoder
and the component also to the bridge, since the encoder goes away when
connecting to the bridge interface of the driver and the equivalent of
bind/unbind of the component is handled by bridge attach/detach.

The lifetime requirements of a bridge and a component are slightly
different, which is the reason for struct tda998x_bridge.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/gpu/drm/i2c/tda998x_drv.c | 157 +++++++++++++++++++++++++++++++++-----
 1 file changed, 137 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index 9c78f7bde49c..012dee61d817 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -36,6 +36,14 @@ struct tda998x_audio_port {
 	u8 config;		/* AP value */
 };
 
+struct tda998x_priv;
+
+struct tda998x_bridge {
+	struct tda998x_priv *priv;
+	struct device *dev;
+	struct drm_bridge bridge;
+};
+
 struct tda998x_priv {
 	struct i2c_client *cec;
 	struct i2c_client *hdmi;
@@ -63,6 +71,8 @@ struct tda998x_priv {
 	wait_queue_head_t edid_delay_waitq;
 	bool edid_delay_active;
 
+	struct tda998x_bridge *bridge;
+	bool local_encoder;
 	struct drm_encoder encoder;
 	struct drm_connector connector;
 
@@ -75,6 +85,9 @@ struct tda998x_priv {
 #define enc_to_tda998x_priv(x) \
 	container_of(x, struct tda998x_priv, encoder)
 
+#define bridge_to_tda998x_bridge(x) \
+	container_of(x, struct tda998x_bridge, bridge)
+
 /* The TDA9988 series of devices use a paged register scheme.. to simplify
  * things we encode the page # in upper bits of the register #.  To read/
  * write a given register, we need to make sure CURPAGE register is set
@@ -842,7 +855,8 @@ static int tda998x_audio_hw_params(struct device *dev, void *data,
 				   struct hdmi_codec_daifmt *daifmt,
 				   struct hdmi_codec_params *params)
 {
-	struct tda998x_priv *priv = dev_get_drvdata(dev);
+	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
+	struct tda998x_priv *priv = bridge->priv;
 	int i, ret;
 	struct tda998x_audio_params audio = {
 		.sample_width = params->sample_width,
@@ -899,7 +913,8 @@ static int tda998x_audio_hw_params(struct device *dev, void *data,
 
 static void tda998x_audio_shutdown(struct device *dev, void *data)
 {
-	struct tda998x_priv *priv = dev_get_drvdata(dev);
+	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
+	struct tda998x_priv *priv = bridge->priv;
 
 	mutex_lock(&priv->audio_mutex);
 
@@ -912,7 +927,8 @@ static void tda998x_audio_shutdown(struct device *dev, void *data)
 
 int tda998x_audio_digital_mute(struct device *dev, void *data, bool enable)
 {
-	struct tda998x_priv *priv = dev_get_drvdata(dev);
+	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
+	struct tda998x_priv *priv = bridge->priv;
 
 	mutex_lock(&priv->audio_mutex);
 
@@ -925,7 +941,8 @@ int tda998x_audio_digital_mute(struct device *dev, void *data, bool enable)
 static int tda998x_audio_get_eld(struct device *dev, void *data,
 				 uint8_t *buf, size_t len)
 {
-	struct tda998x_priv *priv = dev_get_drvdata(dev);
+	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
+	struct tda998x_priv *priv = bridge->priv;
 
 	mutex_lock(&priv->audio_mutex);
 	memcpy(buf, priv->connector.eld,
@@ -1126,7 +1143,10 @@ tda998x_connector_best_encoder(struct drm_connector *connector)
 {
 	struct tda998x_priv *priv = conn_to_tda998x_priv(connector);
 
-	return &priv->encoder;
+	if (priv->local_encoder)
+		return &priv->encoder;
+	else
+		return priv->bridge->bridge.encoder;
 }
 
 static
@@ -1140,6 +1160,7 @@ static int tda998x_connector_init(struct tda998x_priv *priv,
 				  struct drm_device *drm)
 {
 	struct drm_connector *connector = &priv->connector;
+	struct drm_encoder *encoder;
 	int ret;
 
 	connector->interlace_allowed = 1;
@@ -1156,7 +1177,8 @@ static int tda998x_connector_init(struct tda998x_priv *priv,
 	if (ret)
 		return ret;
 
-	drm_mode_connector_attach_encoder(&priv->connector, &priv->encoder);
+	encoder = tda998x_connector_best_encoder(&priv->connector);
+	drm_mode_connector_attach_encoder(&priv->connector, encoder);
 
 	return 0;
 }
@@ -1668,8 +1690,10 @@ static void tda998x_set_config(struct tda998x_priv *priv,
 	priv->audio_params = p->audio_params;
 }
 
-static int tda998x_init(struct device *dev, struct drm_device *drm)
+static int tda998x_init(struct device *dev, struct drm_device *drm,
+			bool local_encoder)
 {
+	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
 	struct tda998x_encoder_params *params = dev->platform_data;
 	struct i2c_client *client = to_i2c_client(dev);
 	struct tda998x_priv *priv;
@@ -1680,7 +1704,9 @@ static int tda998x_init(struct device *dev, struct drm_device *drm)
 	if (!priv)
 		return -ENOMEM;
 
-	dev_set_drvdata(dev, priv);
+	bridge->priv = priv;
+	priv->bridge = bridge;
+	priv->local_encoder = local_encoder;
 
 	if (dev->of_node)
 		crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
@@ -1691,7 +1717,8 @@ static int tda998x_init(struct device *dev, struct drm_device *drm)
 		crtcs = 1 << 0;
 	}
 
-	priv->encoder.possible_crtcs = crtcs;
+	if (local_encoder)
+		priv->encoder.possible_crtcs = crtcs;
 
 	ret = tda998x_create(client, priv);
 	if (ret)
@@ -1700,11 +1727,15 @@ static int tda998x_init(struct device *dev, struct drm_device *drm)
 	if (!dev->of_node && params)
 		tda998x_set_config(priv, params);
 
-	drm_encoder_helper_add(&priv->encoder, &tda998x_encoder_helper_funcs);
-	ret = drm_encoder_init(drm, &priv->encoder, &tda998x_encoder_funcs,
-			       DRM_MODE_ENCODER_TMDS, NULL);
-	if (ret)
-		goto err_encoder;
+	if (local_encoder) {
+		drm_encoder_helper_add(&priv->encoder,
+				       &tda998x_encoder_helper_funcs);
+		ret = drm_encoder_init(drm, &priv->encoder,
+				       &tda998x_encoder_funcs,
+				       DRM_MODE_ENCODER_TMDS, NULL);
+		if (ret)
+			goto err_encoder;
+	}
 
 	ret = tda998x_connector_init(priv, drm);
 	if (ret)
@@ -1713,7 +1744,8 @@ static int tda998x_init(struct device *dev, struct drm_device *drm)
 	return 0;
 
 err_connector:
-	drm_encoder_cleanup(&priv->encoder);
+	if (local_encoder)
+		drm_encoder_cleanup(&priv->encoder);
 err_encoder:
 	tda998x_destroy(priv);
 	return ret;
@@ -1721,10 +1753,12 @@ static int tda998x_init(struct device *dev, struct drm_device *drm)
 
 static void tda998x_fini(struct device *dev)
 {
-	struct tda998x_priv *priv = dev_get_drvdata(dev);
+	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
+	struct tda998x_priv *priv = bridge->priv;
 
 	drm_connector_cleanup(&priv->connector);
-	drm_encoder_cleanup(&priv->encoder);
+	if (priv->local_encoder)
+		drm_encoder_cleanup(&priv->encoder);
 	tda998x_destroy(priv);
 }
 
@@ -1732,7 +1766,7 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data)
 {
 	struct drm_device *drm = data;
 
-	return tda998x_init(dev, drm);
+	return tda998x_init(dev, drm, true);
 }
 
 static void tda998x_unbind(struct device *dev, struct device *master,
@@ -1746,19 +1780,102 @@ static const struct component_ops tda998x_ops = {
 	.unbind = tda998x_unbind,
 };
 
+/* DRM bridge functions */
+
+static int tda998x_bridge_attach(struct drm_bridge *dbridge)
+{
+	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
+	struct device *dev = bridge->dev;
+	struct drm_device *drm = bridge->bridge.dev;
+
+	dev_info(dev, "attach\n");
+	return tda998x_init(dev, drm, false);
+}
+
+static void tda998x_bridge_detach(struct drm_bridge *dbridge)
+{
+	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
+	struct device *dev = bridge->dev;
+
+	dev_info(dev, "detach\n");
+	tda998x_fini(dev);
+}
+
+static void tda998x_bridge_enable(struct drm_bridge *dbridge)
+{
+	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
+	struct tda998x_priv *priv = bridge->priv;
+
+	dev_info(bridge->dev, "enable\n");
+	tda998x_dpms(priv, DRM_MODE_DPMS_ON);
+}
+
+static void tda998x_bridge_disable(struct drm_bridge *dbridge)
+{
+	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
+	struct tda998x_priv *priv = bridge->priv;
+
+	dev_info(bridge->dev, "disable\n");
+	tda998x_dpms(priv, DRM_MODE_DPMS_OFF);
+}
+
+static void tda998x_bridge_mode_set(struct drm_bridge *dbridge,
+				    struct drm_display_mode *mode,
+				    struct drm_display_mode *adjusted_mode)
+{
+	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
+	struct tda998x_priv *priv = bridge->priv;
+
+	tda998x_mode_set(priv, mode, adjusted_mode);
+}
+
+static const struct drm_bridge_funcs tda998x_bridge_funcs = {
+	.attach = tda998x_bridge_attach,
+	.detach = tda998x_bridge_detach,
+	.enable = tda998x_bridge_enable,
+	.disable = tda998x_bridge_disable,
+	.mode_set = tda998x_bridge_mode_set,
+};
+
 static int
 tda998x_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
+	struct device *dev = &client->dev;
+	struct tda998x_bridge *bridge;
+	int ret;
+
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 		dev_warn(&client->dev, "adapter does not support I2C\n");
 		return -EIO;
 	}
-	return component_add(&client->dev, &tda998x_ops);
+
+	bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
+	if (!bridge)
+		return -ENOMEM;
+
+	bridge->dev = dev;
+	dev_set_drvdata(dev, bridge);
+
+	bridge->bridge.funcs = &tda998x_bridge_funcs;
+	bridge->bridge.of_node = dev->of_node;
+	drm_bridge_add(&bridge->bridge);
+
+	ret = component_add(dev, &tda998x_ops);
+
+	if (ret)
+		drm_bridge_remove(&bridge->bridge);
+
+	return ret;
 }
 
 static int tda998x_remove(struct i2c_client *client)
 {
-	component_del(&client->dev, &tda998x_ops);
+	struct device *dev = &client->dev;
+	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
+
+	drm_bridge_remove(&bridge->bridge);
+	component_del(dev, &tda998x_ops);
+
 	return 0;
 }
 
-- 
2.11.0

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

* [PATCH v3 7/7] drm/i2c: tda998x: register as a drm bridge
@ 2018-04-19 16:27   ` Peter Rosin
  0 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-19 16:27 UTC (permalink / raw)
  To: linux-arm-kernel

This makes this driver work with all(?) drivers that are not
componentized and instead expect to connect to a panel/bridge. That
said, the only one tested is atmel_hlcdc.

This hooks the relevant work function previously called by the encoder
and the component also to the bridge, since the encoder goes away when
connecting to the bridge interface of the driver and the equivalent of
bind/unbind of the component is handled by bridge attach/detach.

The lifetime requirements of a bridge and a component are slightly
different, which is the reason for struct tda998x_bridge.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/gpu/drm/i2c/tda998x_drv.c | 157 +++++++++++++++++++++++++++++++++-----
 1 file changed, 137 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index 9c78f7bde49c..012dee61d817 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -36,6 +36,14 @@ struct tda998x_audio_port {
 	u8 config;		/* AP value */
 };
 
+struct tda998x_priv;
+
+struct tda998x_bridge {
+	struct tda998x_priv *priv;
+	struct device *dev;
+	struct drm_bridge bridge;
+};
+
 struct tda998x_priv {
 	struct i2c_client *cec;
 	struct i2c_client *hdmi;
@@ -63,6 +71,8 @@ struct tda998x_priv {
 	wait_queue_head_t edid_delay_waitq;
 	bool edid_delay_active;
 
+	struct tda998x_bridge *bridge;
+	bool local_encoder;
 	struct drm_encoder encoder;
 	struct drm_connector connector;
 
@@ -75,6 +85,9 @@ struct tda998x_priv {
 #define enc_to_tda998x_priv(x) \
 	container_of(x, struct tda998x_priv, encoder)
 
+#define bridge_to_tda998x_bridge(x) \
+	container_of(x, struct tda998x_bridge, bridge)
+
 /* The TDA9988 series of devices use a paged register scheme.. to simplify
  * things we encode the page # in upper bits of the register #.  To read/
  * write a given register, we need to make sure CURPAGE register is set
@@ -842,7 +855,8 @@ static int tda998x_audio_hw_params(struct device *dev, void *data,
 				   struct hdmi_codec_daifmt *daifmt,
 				   struct hdmi_codec_params *params)
 {
-	struct tda998x_priv *priv = dev_get_drvdata(dev);
+	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
+	struct tda998x_priv *priv = bridge->priv;
 	int i, ret;
 	struct tda998x_audio_params audio = {
 		.sample_width = params->sample_width,
@@ -899,7 +913,8 @@ static int tda998x_audio_hw_params(struct device *dev, void *data,
 
 static void tda998x_audio_shutdown(struct device *dev, void *data)
 {
-	struct tda998x_priv *priv = dev_get_drvdata(dev);
+	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
+	struct tda998x_priv *priv = bridge->priv;
 
 	mutex_lock(&priv->audio_mutex);
 
@@ -912,7 +927,8 @@ static void tda998x_audio_shutdown(struct device *dev, void *data)
 
 int tda998x_audio_digital_mute(struct device *dev, void *data, bool enable)
 {
-	struct tda998x_priv *priv = dev_get_drvdata(dev);
+	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
+	struct tda998x_priv *priv = bridge->priv;
 
 	mutex_lock(&priv->audio_mutex);
 
@@ -925,7 +941,8 @@ int tda998x_audio_digital_mute(struct device *dev, void *data, bool enable)
 static int tda998x_audio_get_eld(struct device *dev, void *data,
 				 uint8_t *buf, size_t len)
 {
-	struct tda998x_priv *priv = dev_get_drvdata(dev);
+	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
+	struct tda998x_priv *priv = bridge->priv;
 
 	mutex_lock(&priv->audio_mutex);
 	memcpy(buf, priv->connector.eld,
@@ -1126,7 +1143,10 @@ tda998x_connector_best_encoder(struct drm_connector *connector)
 {
 	struct tda998x_priv *priv = conn_to_tda998x_priv(connector);
 
-	return &priv->encoder;
+	if (priv->local_encoder)
+		return &priv->encoder;
+	else
+		return priv->bridge->bridge.encoder;
 }
 
 static
@@ -1140,6 +1160,7 @@ static int tda998x_connector_init(struct tda998x_priv *priv,
 				  struct drm_device *drm)
 {
 	struct drm_connector *connector = &priv->connector;
+	struct drm_encoder *encoder;
 	int ret;
 
 	connector->interlace_allowed = 1;
@@ -1156,7 +1177,8 @@ static int tda998x_connector_init(struct tda998x_priv *priv,
 	if (ret)
 		return ret;
 
-	drm_mode_connector_attach_encoder(&priv->connector, &priv->encoder);
+	encoder = tda998x_connector_best_encoder(&priv->connector);
+	drm_mode_connector_attach_encoder(&priv->connector, encoder);
 
 	return 0;
 }
@@ -1668,8 +1690,10 @@ static void tda998x_set_config(struct tda998x_priv *priv,
 	priv->audio_params = p->audio_params;
 }
 
-static int tda998x_init(struct device *dev, struct drm_device *drm)
+static int tda998x_init(struct device *dev, struct drm_device *drm,
+			bool local_encoder)
 {
+	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
 	struct tda998x_encoder_params *params = dev->platform_data;
 	struct i2c_client *client = to_i2c_client(dev);
 	struct tda998x_priv *priv;
@@ -1680,7 +1704,9 @@ static int tda998x_init(struct device *dev, struct drm_device *drm)
 	if (!priv)
 		return -ENOMEM;
 
-	dev_set_drvdata(dev, priv);
+	bridge->priv = priv;
+	priv->bridge = bridge;
+	priv->local_encoder = local_encoder;
 
 	if (dev->of_node)
 		crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
@@ -1691,7 +1717,8 @@ static int tda998x_init(struct device *dev, struct drm_device *drm)
 		crtcs = 1 << 0;
 	}
 
-	priv->encoder.possible_crtcs = crtcs;
+	if (local_encoder)
+		priv->encoder.possible_crtcs = crtcs;
 
 	ret = tda998x_create(client, priv);
 	if (ret)
@@ -1700,11 +1727,15 @@ static int tda998x_init(struct device *dev, struct drm_device *drm)
 	if (!dev->of_node && params)
 		tda998x_set_config(priv, params);
 
-	drm_encoder_helper_add(&priv->encoder, &tda998x_encoder_helper_funcs);
-	ret = drm_encoder_init(drm, &priv->encoder, &tda998x_encoder_funcs,
-			       DRM_MODE_ENCODER_TMDS, NULL);
-	if (ret)
-		goto err_encoder;
+	if (local_encoder) {
+		drm_encoder_helper_add(&priv->encoder,
+				       &tda998x_encoder_helper_funcs);
+		ret = drm_encoder_init(drm, &priv->encoder,
+				       &tda998x_encoder_funcs,
+				       DRM_MODE_ENCODER_TMDS, NULL);
+		if (ret)
+			goto err_encoder;
+	}
 
 	ret = tda998x_connector_init(priv, drm);
 	if (ret)
@@ -1713,7 +1744,8 @@ static int tda998x_init(struct device *dev, struct drm_device *drm)
 	return 0;
 
 err_connector:
-	drm_encoder_cleanup(&priv->encoder);
+	if (local_encoder)
+		drm_encoder_cleanup(&priv->encoder);
 err_encoder:
 	tda998x_destroy(priv);
 	return ret;
@@ -1721,10 +1753,12 @@ static int tda998x_init(struct device *dev, struct drm_device *drm)
 
 static void tda998x_fini(struct device *dev)
 {
-	struct tda998x_priv *priv = dev_get_drvdata(dev);
+	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
+	struct tda998x_priv *priv = bridge->priv;
 
 	drm_connector_cleanup(&priv->connector);
-	drm_encoder_cleanup(&priv->encoder);
+	if (priv->local_encoder)
+		drm_encoder_cleanup(&priv->encoder);
 	tda998x_destroy(priv);
 }
 
@@ -1732,7 +1766,7 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data)
 {
 	struct drm_device *drm = data;
 
-	return tda998x_init(dev, drm);
+	return tda998x_init(dev, drm, true);
 }
 
 static void tda998x_unbind(struct device *dev, struct device *master,
@@ -1746,19 +1780,102 @@ static const struct component_ops tda998x_ops = {
 	.unbind = tda998x_unbind,
 };
 
+/* DRM bridge functions */
+
+static int tda998x_bridge_attach(struct drm_bridge *dbridge)
+{
+	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
+	struct device *dev = bridge->dev;
+	struct drm_device *drm = bridge->bridge.dev;
+
+	dev_info(dev, "attach\n");
+	return tda998x_init(dev, drm, false);
+}
+
+static void tda998x_bridge_detach(struct drm_bridge *dbridge)
+{
+	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
+	struct device *dev = bridge->dev;
+
+	dev_info(dev, "detach\n");
+	tda998x_fini(dev);
+}
+
+static void tda998x_bridge_enable(struct drm_bridge *dbridge)
+{
+	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
+	struct tda998x_priv *priv = bridge->priv;
+
+	dev_info(bridge->dev, "enable\n");
+	tda998x_dpms(priv, DRM_MODE_DPMS_ON);
+}
+
+static void tda998x_bridge_disable(struct drm_bridge *dbridge)
+{
+	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
+	struct tda998x_priv *priv = bridge->priv;
+
+	dev_info(bridge->dev, "disable\n");
+	tda998x_dpms(priv, DRM_MODE_DPMS_OFF);
+}
+
+static void tda998x_bridge_mode_set(struct drm_bridge *dbridge,
+				    struct drm_display_mode *mode,
+				    struct drm_display_mode *adjusted_mode)
+{
+	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
+	struct tda998x_priv *priv = bridge->priv;
+
+	tda998x_mode_set(priv, mode, adjusted_mode);
+}
+
+static const struct drm_bridge_funcs tda998x_bridge_funcs = {
+	.attach = tda998x_bridge_attach,
+	.detach = tda998x_bridge_detach,
+	.enable = tda998x_bridge_enable,
+	.disable = tda998x_bridge_disable,
+	.mode_set = tda998x_bridge_mode_set,
+};
+
 static int
 tda998x_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
+	struct device *dev = &client->dev;
+	struct tda998x_bridge *bridge;
+	int ret;
+
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 		dev_warn(&client->dev, "adapter does not support I2C\n");
 		return -EIO;
 	}
-	return component_add(&client->dev, &tda998x_ops);
+
+	bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
+	if (!bridge)
+		return -ENOMEM;
+
+	bridge->dev = dev;
+	dev_set_drvdata(dev, bridge);
+
+	bridge->bridge.funcs = &tda998x_bridge_funcs;
+	bridge->bridge.of_node = dev->of_node;
+	drm_bridge_add(&bridge->bridge);
+
+	ret = component_add(dev, &tda998x_ops);
+
+	if (ret)
+		drm_bridge_remove(&bridge->bridge);
+
+	return ret;
 }
 
 static int tda998x_remove(struct i2c_client *client)
 {
-	component_del(&client->dev, &tda998x_ops);
+	struct device *dev = &client->dev;
+	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
+
+	drm_bridge_remove(&bridge->bridge);
+	component_del(dev, &tda998x_ops);
+
 	return 0;
 }
 
-- 
2.11.0

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

* Re: [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
  2018-04-19 16:27 ` Peter Rosin
  (?)
@ 2018-04-20  8:52   ` jacopo mondi
  -1 siblings, 0 replies; 67+ messages in thread
From: jacopo mondi @ 2018-04-20  8:52 UTC (permalink / raw)
  To: Peter Rosin
  Cc: linux-kernel, David Airlie, Rob Herring, Mark Rutland,
	Nicolas Ferre, Alexandre Belloni, Boris Brezillon, Daniel Vetter,
	Gustavo Padovan, Sean Paul, Russell King, Laurent Pinchart,
	Jacopo Mondi, dri-devel, devicetree, linux-arm-kernel

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

Hi Peter,
    I've been a bit a pain in the arse for you recently, but please
bear with me a bit more, and sorry for jumping late on the band wagon.

On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
> Hi!
>
> I naively thought that since there was support for both nxp,tda19988 (in
> the tda998x driver) and the atmel-hlcdc, things would be a smooth ride.
> But it wasn't, so I started looking around and realized I had to fix
> things.
>
> In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
> component, but now in v3 I fix things by making the tda998x driver
> a bridge instead. This was after a suggestion from Boris Brezillion
> (the atmel-hlcdc maintainer), so there was some risk of bias ... but
> after comparing what was needed, I too find the bridge approach better.
>
> In addition to the above, our PCB interface between the SAMA5D3 and the
> HDMI encoder is only using 16 bits, and this has to be described
> somewhere, or the atmel-hlcdc driver have no chance of selecting the
> correct output mode. Since I have similar problems with a ds90c185 lvds
> encoder I added patches to override the atmel-hlcdc output format via
> DT properties compatible with the media video-interface binding and
> things start to play together.
>
> Since this series superseeds the bridge series [1], I have included the
> leftover bindings patch for the ti,ds90c185 here.
>

I feel like this series would look better if it would make use of the
proposed bridge media bus format support I have recently sent out [1]
(and which was not there when you first sent v1).

I understand your fundamental problem here is that the bus format
that should be reported by your bridge is different from the ones
actually supported by the TDA19988 chip, as the wirings ground some
of the input pins.

Although this is defintely something that could be described in the
bridge's own OF node with the 'bus_width' property, and what I would do,
now that you have made a bridge out from the tda19988 driver, is:

1) Set the bridge accepted input bus_format parsing its pin
configuration, or default it if that's not implemented yet.
This will likely be rgb888. You can do that using the trivial
support for bridge input image formats implemented by my series.
2) Specify in the bridge endpoint a 'bus_width' of <16>
3) In your atmel-hlcd get both the image format of the bridge (rgb888)
and parse the remote endpoint property 'bus_width' and get the <16>
value back.
4) Set the correct format in the atmel hlcd driver to accommodate a
bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
or are there other possible combinations I am missing?)

I would consider this better mostly because in this series you are
creating a semantic for the whole DRM subsystem on the 'bus_width'
property, where numerical values as '12', '16' etc are arbitrary tied
to the selection of a media bus format. At least you should use a
common set of defines [1] between the device tree and the driver,
but this looks anyway fragile imho.

Have I maybe missed some parts of the problem you are trying to solve
here?

Thank you
   j

[1] drm: bridge: Add support for static image formats
    https://lwn.net/Articles/752296/
[2] include/uapi/linux/media-bus-format.h
> Anyway, this series solves some real issues for my HW.
>
> Cheers,
> Peter
>
> Changes since v2   https://lkml.org/lkml/2018/4/17/385
> - patch 2/7 fixed spelling and added an example
> - patch 4/7 parse the DT up front and store the result indexed by encoder
> - old patch 5/6 and 6/6 dropped
> - patch 5-7/7 are new and makes the tda998x driver a drm_bridge
>
> Changes since v1   https://lkml.org/lkml/2018/4/9/294
> - added reviewed-by from Rob to patch 1/6
> - patch 2/6 changed so that the bus format override is in the endpoint
>   DT node, and follows the binding of media video-interfaces.
> - patch 3/6 is new, it adds drm_of_media_bus_fmt which parses above
>   media video-interface binding (partially).
> - patch 4/6 now makes use of the above helper (and also fixes problems
>   with the 3/5 patch from v1 when no override was specified).
> - do not mention unrelated connector display_info details in the cover
>   letter and commit messages.
>
> [1]
> "Bridge" series v2   https://lkml.org/lkml/2018/3/26/610
> "Bridge" series v1   https://lkml.org/lkml/2018/3/17/221
>
> Peter Rosin (7):
>   dt-bindings: display: bridge: lvds-transmitter: add ti,ds90c185
>   dt-bindings: display: atmel: optional video-interface of endpoints
>   drm: of: introduce drm_of_media_bus_fmt
>   drm/atmel-hlcdc: support bus-width (12/16/18/24) in endpoint nodes
>   drm/i2c: tda998x: find the drm_device via the drm_connector
>   drm/i2c: tda998x: split encoder and component functions from the work
>   drm/i2c: tda998x: register as a drm bridge
>
>  .../devicetree/bindings/display/atmel/hlcdc-dc.txt |  26 +++
>  .../bindings/display/bridge/lvds-transmitter.txt   |   8 +-
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c     |  71 ++++++--
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h       |   2 +
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c   |  40 +++-
>  drivers/gpu/drm/drm_of.c                           |  38 ++++
>  drivers/gpu/drm/i2c/tda998x_drv.c                  | 201 ++++++++++++++++++---
>  include/drm/drm_of.h                               |   7 +
>  8 files changed, 342 insertions(+), 51 deletions(-)
>
> --
> 2.11.0
>

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

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

* Re: [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
@ 2018-04-20  8:52   ` jacopo mondi
  0 siblings, 0 replies; 67+ messages in thread
From: jacopo mondi @ 2018-04-20  8:52 UTC (permalink / raw)
  To: Peter Rosin
  Cc: Mark Rutland, Boris Brezillon, Alexandre Belloni, devicetree,
	David Airlie, linux-kernel, dri-devel, Nicolas Ferre,
	Rob Herring, Laurent Pinchart, Daniel Vetter, Jacopo Mondi,
	Russell King, linux-arm-kernel


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

Hi Peter,
    I've been a bit a pain in the arse for you recently, but please
bear with me a bit more, and sorry for jumping late on the band wagon.

On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
> Hi!
>
> I naively thought that since there was support for both nxp,tda19988 (in
> the tda998x driver) and the atmel-hlcdc, things would be a smooth ride.
> But it wasn't, so I started looking around and realized I had to fix
> things.
>
> In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
> component, but now in v3 I fix things by making the tda998x driver
> a bridge instead. This was after a suggestion from Boris Brezillion
> (the atmel-hlcdc maintainer), so there was some risk of bias ... but
> after comparing what was needed, I too find the bridge approach better.
>
> In addition to the above, our PCB interface between the SAMA5D3 and the
> HDMI encoder is only using 16 bits, and this has to be described
> somewhere, or the atmel-hlcdc driver have no chance of selecting the
> correct output mode. Since I have similar problems with a ds90c185 lvds
> encoder I added patches to override the atmel-hlcdc output format via
> DT properties compatible with the media video-interface binding and
> things start to play together.
>
> Since this series superseeds the bridge series [1], I have included the
> leftover bindings patch for the ti,ds90c185 here.
>

I feel like this series would look better if it would make use of the
proposed bridge media bus format support I have recently sent out [1]
(and which was not there when you first sent v1).

I understand your fundamental problem here is that the bus format
that should be reported by your bridge is different from the ones
actually supported by the TDA19988 chip, as the wirings ground some
of the input pins.

Although this is defintely something that could be described in the
bridge's own OF node with the 'bus_width' property, and what I would do,
now that you have made a bridge out from the tda19988 driver, is:

1) Set the bridge accepted input bus_format parsing its pin
configuration, or default it if that's not implemented yet.
This will likely be rgb888. You can do that using the trivial
support for bridge input image formats implemented by my series.
2) Specify in the bridge endpoint a 'bus_width' of <16>
3) In your atmel-hlcd get both the image format of the bridge (rgb888)
and parse the remote endpoint property 'bus_width' and get the <16>
value back.
4) Set the correct format in the atmel hlcd driver to accommodate a
bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
or are there other possible combinations I am missing?)

I would consider this better mostly because in this series you are
creating a semantic for the whole DRM subsystem on the 'bus_width'
property, where numerical values as '12', '16' etc are arbitrary tied
to the selection of a media bus format. At least you should use a
common set of defines [1] between the device tree and the driver,
but this looks anyway fragile imho.

Have I maybe missed some parts of the problem you are trying to solve
here?

Thank you
   j

[1] drm: bridge: Add support for static image formats
    https://lwn.net/Articles/752296/
[2] include/uapi/linux/media-bus-format.h
> Anyway, this series solves some real issues for my HW.
>
> Cheers,
> Peter
>
> Changes since v2   https://lkml.org/lkml/2018/4/17/385
> - patch 2/7 fixed spelling and added an example
> - patch 4/7 parse the DT up front and store the result indexed by encoder
> - old patch 5/6 and 6/6 dropped
> - patch 5-7/7 are new and makes the tda998x driver a drm_bridge
>
> Changes since v1   https://lkml.org/lkml/2018/4/9/294
> - added reviewed-by from Rob to patch 1/6
> - patch 2/6 changed so that the bus format override is in the endpoint
>   DT node, and follows the binding of media video-interfaces.
> - patch 3/6 is new, it adds drm_of_media_bus_fmt which parses above
>   media video-interface binding (partially).
> - patch 4/6 now makes use of the above helper (and also fixes problems
>   with the 3/5 patch from v1 when no override was specified).
> - do not mention unrelated connector display_info details in the cover
>   letter and commit messages.
>
> [1]
> "Bridge" series v2   https://lkml.org/lkml/2018/3/26/610
> "Bridge" series v1   https://lkml.org/lkml/2018/3/17/221
>
> Peter Rosin (7):
>   dt-bindings: display: bridge: lvds-transmitter: add ti,ds90c185
>   dt-bindings: display: atmel: optional video-interface of endpoints
>   drm: of: introduce drm_of_media_bus_fmt
>   drm/atmel-hlcdc: support bus-width (12/16/18/24) in endpoint nodes
>   drm/i2c: tda998x: find the drm_device via the drm_connector
>   drm/i2c: tda998x: split encoder and component functions from the work
>   drm/i2c: tda998x: register as a drm bridge
>
>  .../devicetree/bindings/display/atmel/hlcdc-dc.txt |  26 +++
>  .../bindings/display/bridge/lvds-transmitter.txt   |   8 +-
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c     |  71 ++++++--
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h       |   2 +
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c   |  40 +++-
>  drivers/gpu/drm/drm_of.c                           |  38 ++++
>  drivers/gpu/drm/i2c/tda998x_drv.c                  | 201 ++++++++++++++++++---
>  include/drm/drm_of.h                               |   7 +
>  8 files changed, 342 insertions(+), 51 deletions(-)
>
> --
> 2.11.0
>

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

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

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

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

* [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
@ 2018-04-20  8:52   ` jacopo mondi
  0 siblings, 0 replies; 67+ messages in thread
From: jacopo mondi @ 2018-04-20  8:52 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Peter,
    I've been a bit a pain in the arse for you recently, but please
bear with me a bit more, and sorry for jumping late on the band wagon.

On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
> Hi!
>
> I naively thought that since there was support for both nxp,tda19988 (in
> the tda998x driver) and the atmel-hlcdc, things would be a smooth ride.
> But it wasn't, so I started looking around and realized I had to fix
> things.
>
> In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
> component, but now in v3 I fix things by making the tda998x driver
> a bridge instead. This was after a suggestion from Boris Brezillion
> (the atmel-hlcdc maintainer), so there was some risk of bias ... but
> after comparing what was needed, I too find the bridge approach better.
>
> In addition to the above, our PCB interface between the SAMA5D3 and the
> HDMI encoder is only using 16 bits, and this has to be described
> somewhere, or the atmel-hlcdc driver have no chance of selecting the
> correct output mode. Since I have similar problems with a ds90c185 lvds
> encoder I added patches to override the atmel-hlcdc output format via
> DT properties compatible with the media video-interface binding and
> things start to play together.
>
> Since this series superseeds the bridge series [1], I have included the
> leftover bindings patch for the ti,ds90c185 here.
>

I feel like this series would look better if it would make use of the
proposed bridge media bus format support I have recently sent out [1]
(and which was not there when you first sent v1).

I understand your fundamental problem here is that the bus format
that should be reported by your bridge is different from the ones
actually supported by the TDA19988 chip, as the wirings ground some
of the input pins.

Although this is defintely something that could be described in the
bridge's own OF node with the 'bus_width' property, and what I would do,
now that you have made a bridge out from the tda19988 driver, is:

1) Set the bridge accepted input bus_format parsing its pin
configuration, or default it if that's not implemented yet.
This will likely be rgb888. You can do that using the trivial
support for bridge input image formats implemented by my series.
2) Specify in the bridge endpoint a 'bus_width' of <16>
3) In your atmel-hlcd get both the image format of the bridge (rgb888)
and parse the remote endpoint property 'bus_width' and get the <16>
value back.
4) Set the correct format in the atmel hlcd driver to accommodate a
bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
or are there other possible combinations I am missing?)

I would consider this better mostly because in this series you are
creating a semantic for the whole DRM subsystem on the 'bus_width'
property, where numerical values as '12', '16' etc are arbitrary tied
to the selection of a media bus format. At least you should use a
common set of defines [1] between the device tree and the driver,
but this looks anyway fragile imho.

Have I maybe missed some parts of the problem you are trying to solve
here?

Thank you
   j

[1] drm: bridge: Add support for static image formats
    https://lwn.net/Articles/752296/
[2] include/uapi/linux/media-bus-format.h
> Anyway, this series solves some real issues for my HW.
>
> Cheers,
> Peter
>
> Changes since v2   https://lkml.org/lkml/2018/4/17/385
> - patch 2/7 fixed spelling and added an example
> - patch 4/7 parse the DT up front and store the result indexed by encoder
> - old patch 5/6 and 6/6 dropped
> - patch 5-7/7 are new and makes the tda998x driver a drm_bridge
>
> Changes since v1   https://lkml.org/lkml/2018/4/9/294
> - added reviewed-by from Rob to patch 1/6
> - patch 2/6 changed so that the bus format override is in the endpoint
>   DT node, and follows the binding of media video-interfaces.
> - patch 3/6 is new, it adds drm_of_media_bus_fmt which parses above
>   media video-interface binding (partially).
> - patch 4/6 now makes use of the above helper (and also fixes problems
>   with the 3/5 patch from v1 when no override was specified).
> - do not mention unrelated connector display_info details in the cover
>   letter and commit messages.
>
> [1]
> "Bridge" series v2   https://lkml.org/lkml/2018/3/26/610
> "Bridge" series v1   https://lkml.org/lkml/2018/3/17/221
>
> Peter Rosin (7):
>   dt-bindings: display: bridge: lvds-transmitter: add ti,ds90c185
>   dt-bindings: display: atmel: optional video-interface of endpoints
>   drm: of: introduce drm_of_media_bus_fmt
>   drm/atmel-hlcdc: support bus-width (12/16/18/24) in endpoint nodes
>   drm/i2c: tda998x: find the drm_device via the drm_connector
>   drm/i2c: tda998x: split encoder and component functions from the work
>   drm/i2c: tda998x: register as a drm bridge
>
>  .../devicetree/bindings/display/atmel/hlcdc-dc.txt |  26 +++
>  .../bindings/display/bridge/lvds-transmitter.txt   |   8 +-
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c     |  71 ++++++--
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h       |   2 +
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c   |  40 +++-
>  drivers/gpu/drm/drm_of.c                           |  38 ++++
>  drivers/gpu/drm/i2c/tda998x_drv.c                  | 201 ++++++++++++++++++---
>  include/drm/drm_of.h                               |   7 +
>  8 files changed, 342 insertions(+), 51 deletions(-)
>
> --
> 2.11.0
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180420/8179b3c9/attachment.sig>

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

* Re: [PATCH v3 5/7] drm/i2c: tda998x: find the drm_device via the drm_connector
  2018-04-19 16:27   ` Peter Rosin
@ 2018-04-20  9:41     ` Laurent Pinchart
  -1 siblings, 0 replies; 67+ messages in thread
From: Laurent Pinchart @ 2018-04-20  9:41 UTC (permalink / raw)
  To: dri-devel
  Cc: Peter Rosin, linux-kernel, Mark Rutland, Boris Brezillon,
	Alexandre Belloni, Jacopo Mondi, devicetree, David Airlie,
	Nicolas Ferre, Russell King, Rob Herring, Daniel Vetter,
	linux-arm-kernel

Hi Peter,

Thank you for the patch.

On Thursday, 19 April 2018 19:27:49 EEST Peter Rosin wrote:
> This prepares for being a drm_bridge which will not register the
> encoder. That makes the connector the better choice.
> 
> Signed-off-by: Peter Rosin <peda@axentia.se>

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

> ---
>  drivers/gpu/drm/i2c/tda998x_drv.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c
> b/drivers/gpu/drm/i2c/tda998x_drv.c index cd3f0873bbdd..8f6e013f2b87 100644
> --- a/drivers/gpu/drm/i2c/tda998x_drv.c
> +++ b/drivers/gpu/drm/i2c/tda998x_drv.c
> @@ -630,7 +630,7 @@ static void tda998x_detect_work(struct work_struct
> *work) {
>  	struct tda998x_priv *priv =
>  		container_of(work, struct tda998x_priv, detect_work);
> -	struct drm_device *dev = priv->encoder.dev;
> +	struct drm_device *dev = priv->connector.dev;
> 
>  	if (dev)
>  		drm_kms_helper_hotplug_event(dev);


-- 
Regards,

Laurent Pinchart

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

* [PATCH v3 5/7] drm/i2c: tda998x: find the drm_device via the drm_connector
@ 2018-04-20  9:41     ` Laurent Pinchart
  0 siblings, 0 replies; 67+ messages in thread
From: Laurent Pinchart @ 2018-04-20  9:41 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Peter,

Thank you for the patch.

On Thursday, 19 April 2018 19:27:49 EEST Peter Rosin wrote:
> This prepares for being a drm_bridge which will not register the
> encoder. That makes the connector the better choice.
> 
> Signed-off-by: Peter Rosin <peda@axentia.se>

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

> ---
>  drivers/gpu/drm/i2c/tda998x_drv.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c
> b/drivers/gpu/drm/i2c/tda998x_drv.c index cd3f0873bbdd..8f6e013f2b87 100644
> --- a/drivers/gpu/drm/i2c/tda998x_drv.c
> +++ b/drivers/gpu/drm/i2c/tda998x_drv.c
> @@ -630,7 +630,7 @@ static void tda998x_detect_work(struct work_struct
> *work) {
>  	struct tda998x_priv *priv =
>  		container_of(work, struct tda998x_priv, detect_work);
> -	struct drm_device *dev = priv->encoder.dev;
> +	struct drm_device *dev = priv->connector.dev;
> 
>  	if (dev)
>  		drm_kms_helper_hotplug_event(dev);


-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v3 6/7] drm/i2c: tda998x: split encoder and component functions from the work
  2018-04-19 16:27   ` Peter Rosin
@ 2018-04-20  9:51     ` Laurent Pinchart
  -1 siblings, 0 replies; 67+ messages in thread
From: Laurent Pinchart @ 2018-04-20  9:51 UTC (permalink / raw)
  To: dri-devel
  Cc: Peter Rosin, linux-kernel, Mark Rutland, Boris Brezillon,
	Alexandre Belloni, Jacopo Mondi, devicetree, David Airlie,
	Nicolas Ferre, Russell King, Rob Herring, Daniel Vetter,
	linux-arm-kernel

Hi Peter,

Thank you for the patch.

On Thursday, 19 April 2018 19:27:50 EEST Peter Rosin wrote:
> This enables reuse of the machinery for the case where a drm_bridge
> needs to do the same work via different interfaces.
> 
> Signed-off-by: Peter Rosin <peda@axentia.se>
> ---
>  drivers/gpu/drm/i2c/tda998x_drv.c | 46 ++++++++++++++++++++++++++++--------
>  1 file changed, 36 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c
> b/drivers/gpu/drm/i2c/tda998x_drv.c index 8f6e013f2b87..9c78f7bde49c 100644
> --- a/drivers/gpu/drm/i2c/tda998x_drv.c
> +++ b/drivers/gpu/drm/i2c/tda998x_drv.c
> @@ -1163,9 +1163,8 @@ static int tda998x_connector_init(struct tda998x_priv
> *priv,
> 
>  /* DRM encoder functions */
> 
> -static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
> +static void tda998x_dpms(struct tda998x_priv *priv, int mode)

I'd split this function into tda998x_enable() and tda998x_disable(), as the 
DRM bridge API doesn't need to care about DPMS. The core of the driver would 
then be DPMS-free.

Apart from that the patch looks good to me.

>  {
> -	struct tda998x_priv *priv = enc_to_tda998x_priv(encoder);
>  	bool on;
> 
>  	/* we only care about on or off: */
> @@ -1195,12 +1194,18 @@ static void tda998x_encoder_dpms(struct drm_encoder
> *encoder, int mode) }
>  }
> 
> -static void
> -tda998x_encoder_mode_set(struct drm_encoder *encoder,
> -			 struct drm_display_mode *mode,
> -			 struct drm_display_mode *adjusted_mode)
> +static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
>  {
>  	struct tda998x_priv *priv = enc_to_tda998x_priv(encoder);
> +
> +	tda998x_dpms(priv, mode);
> +}
> +
> +static void
> +tda998x_mode_set(struct tda998x_priv *priv,
> +		 struct drm_display_mode *mode,
> +		 struct drm_display_mode *adjusted_mode)
> +{
>  	u16 ref_pix, ref_line, n_pix, n_line;
>  	u16 hs_pix_s, hs_pix_e;
>  	u16 vs1_pix_s, vs1_pix_e, vs1_line_s, vs1_line_e;
> @@ -1407,6 +1412,16 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,
> mutex_unlock(&priv->audio_mutex);
>  }
> 
> +static void
> +tda998x_encoder_mode_set(struct drm_encoder *encoder,
> +			 struct drm_display_mode *mode,
> +			 struct drm_display_mode *adjusted_mode)
> +{
> +	struct tda998x_priv *priv = enc_to_tda998x_priv(encoder);
> +
> +	tda998x_mode_set(priv, mode, adjusted_mode);
> +}
> +
>  static void tda998x_destroy(struct tda998x_priv *priv)
>  {
>  	/* disable all IRQs and free the IRQ handler */
> @@ -1653,11 +1668,10 @@ static void tda998x_set_config(struct tda998x_priv
> *priv, priv->audio_params = p->audio_params;
>  }
> 
> -static int tda998x_bind(struct device *dev, struct device *master, void
> *data)
> +static int tda998x_init(struct device *dev, struct drm_device *drm)
> {
>  	struct tda998x_encoder_params *params = dev->platform_data;
>  	struct i2c_client *client = to_i2c_client(dev);
> -	struct drm_device *drm = data;
>  	struct tda998x_priv *priv;
>  	u32 crtcs = 0;
>  	int ret;
> @@ -1705,8 +1719,7 @@ static int tda998x_bind(struct device *dev, struct
> device *master, void *data) return ret;
>  }
> 
> -static void tda998x_unbind(struct device *dev, struct device *master,
> -			   void *data)
> +static void tda998x_fini(struct device *dev)
>  {
>  	struct tda998x_priv *priv = dev_get_drvdata(dev);
> 
> @@ -1715,6 +1728,19 @@ static void tda998x_unbind(struct device *dev, struct
> device *master, tda998x_destroy(priv);
>  }
> 
> +static int tda998x_bind(struct device *dev, struct device *master, void
> *data)
> +{
> +	struct drm_device *drm = data;
> +
> +	return tda998x_init(dev, drm);
> +}
> +
> +static void tda998x_unbind(struct device *dev, struct device *master,
> +			   void *data)
> +{
> +	tda998x_fini(dev);
> +}
> +
>  static const struct component_ops tda998x_ops = {
>  	.bind = tda998x_bind,
>  	.unbind = tda998x_unbind,

-- 
Regards,

Laurent Pinchart

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

* [PATCH v3 6/7] drm/i2c: tda998x: split encoder and component functions from the work
@ 2018-04-20  9:51     ` Laurent Pinchart
  0 siblings, 0 replies; 67+ messages in thread
From: Laurent Pinchart @ 2018-04-20  9:51 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Peter,

Thank you for the patch.

On Thursday, 19 April 2018 19:27:50 EEST Peter Rosin wrote:
> This enables reuse of the machinery for the case where a drm_bridge
> needs to do the same work via different interfaces.
> 
> Signed-off-by: Peter Rosin <peda@axentia.se>
> ---
>  drivers/gpu/drm/i2c/tda998x_drv.c | 46 ++++++++++++++++++++++++++++--------
>  1 file changed, 36 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c
> b/drivers/gpu/drm/i2c/tda998x_drv.c index 8f6e013f2b87..9c78f7bde49c 100644
> --- a/drivers/gpu/drm/i2c/tda998x_drv.c
> +++ b/drivers/gpu/drm/i2c/tda998x_drv.c
> @@ -1163,9 +1163,8 @@ static int tda998x_connector_init(struct tda998x_priv
> *priv,
> 
>  /* DRM encoder functions */
> 
> -static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
> +static void tda998x_dpms(struct tda998x_priv *priv, int mode)

I'd split this function into tda998x_enable() and tda998x_disable(), as the 
DRM bridge API doesn't need to care about DPMS. The core of the driver would 
then be DPMS-free.

Apart from that the patch looks good to me.

>  {
> -	struct tda998x_priv *priv = enc_to_tda998x_priv(encoder);
>  	bool on;
> 
>  	/* we only care about on or off: */
> @@ -1195,12 +1194,18 @@ static void tda998x_encoder_dpms(struct drm_encoder
> *encoder, int mode) }
>  }
> 
> -static void
> -tda998x_encoder_mode_set(struct drm_encoder *encoder,
> -			 struct drm_display_mode *mode,
> -			 struct drm_display_mode *adjusted_mode)
> +static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
>  {
>  	struct tda998x_priv *priv = enc_to_tda998x_priv(encoder);
> +
> +	tda998x_dpms(priv, mode);
> +}
> +
> +static void
> +tda998x_mode_set(struct tda998x_priv *priv,
> +		 struct drm_display_mode *mode,
> +		 struct drm_display_mode *adjusted_mode)
> +{
>  	u16 ref_pix, ref_line, n_pix, n_line;
>  	u16 hs_pix_s, hs_pix_e;
>  	u16 vs1_pix_s, vs1_pix_e, vs1_line_s, vs1_line_e;
> @@ -1407,6 +1412,16 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,
> mutex_unlock(&priv->audio_mutex);
>  }
> 
> +static void
> +tda998x_encoder_mode_set(struct drm_encoder *encoder,
> +			 struct drm_display_mode *mode,
> +			 struct drm_display_mode *adjusted_mode)
> +{
> +	struct tda998x_priv *priv = enc_to_tda998x_priv(encoder);
> +
> +	tda998x_mode_set(priv, mode, adjusted_mode);
> +}
> +
>  static void tda998x_destroy(struct tda998x_priv *priv)
>  {
>  	/* disable all IRQs and free the IRQ handler */
> @@ -1653,11 +1668,10 @@ static void tda998x_set_config(struct tda998x_priv
> *priv, priv->audio_params = p->audio_params;
>  }
> 
> -static int tda998x_bind(struct device *dev, struct device *master, void
> *data)
> +static int tda998x_init(struct device *dev, struct drm_device *drm)
> {
>  	struct tda998x_encoder_params *params = dev->platform_data;
>  	struct i2c_client *client = to_i2c_client(dev);
> -	struct drm_device *drm = data;
>  	struct tda998x_priv *priv;
>  	u32 crtcs = 0;
>  	int ret;
> @@ -1705,8 +1719,7 @@ static int tda998x_bind(struct device *dev, struct
> device *master, void *data) return ret;
>  }
> 
> -static void tda998x_unbind(struct device *dev, struct device *master,
> -			   void *data)
> +static void tda998x_fini(struct device *dev)
>  {
>  	struct tda998x_priv *priv = dev_get_drvdata(dev);
> 
> @@ -1715,6 +1728,19 @@ static void tda998x_unbind(struct device *dev, struct
> device *master, tda998x_destroy(priv);
>  }
> 
> +static int tda998x_bind(struct device *dev, struct device *master, void
> *data)
> +{
> +	struct drm_device *drm = data;
> +
> +	return tda998x_init(dev, drm);
> +}
> +
> +static void tda998x_unbind(struct device *dev, struct device *master,
> +			   void *data)
> +{
> +	tda998x_fini(dev);
> +}
> +
>  static const struct component_ops tda998x_ops = {
>  	.bind = tda998x_bind,
>  	.unbind = tda998x_unbind,

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v3 7/7] drm/i2c: tda998x: register as a drm bridge
  2018-04-19 16:27   ` Peter Rosin
  (?)
@ 2018-04-20 10:06     ` Laurent Pinchart
  -1 siblings, 0 replies; 67+ messages in thread
From: Laurent Pinchart @ 2018-04-20 10:06 UTC (permalink / raw)
  To: dri-devel
  Cc: Peter Rosin, linux-kernel, Mark Rutland, Boris Brezillon,
	Alexandre Belloni, Jacopo Mondi, devicetree, David Airlie,
	Nicolas Ferre, Russell King, Rob Herring, Daniel Vetter,
	linux-arm-kernel

Hi Peter,

Thank you for the patch.

On Thursday, 19 April 2018 19:27:51 EEST Peter Rosin wrote:
> This makes this driver work with all(?) drivers that are not
> componentized and instead expect to connect to a panel/bridge. That
> said, the only one tested is atmel_hlcdc.
> 
> This hooks the relevant work function previously called by the encoder
> and the component also to the bridge, since the encoder goes away when
> connecting to the bridge interface of the driver and the equivalent of
> bind/unbind of the component is handled by bridge attach/detach.
> 
> The lifetime requirements of a bridge and a component are slightly
> different, which is the reason for struct tda998x_bridge.

Couldn't you move the allocation and initialization (tda998x_create) of the 
tda998x_priv structure to probe time ? I think you wouldn't need a separate 
structure in that case. Unless I'm mistaken there would be an added benefit of 
separating component and bridge initialization, resulting in the encoder not 
being initialized at all if the component isn't used. You wouldn't need to add 
a local_encoder parameter to the tda998x_init() function.

> Signed-off-by: Peter Rosin <peda@axentia.se>
> ---
>  drivers/gpu/drm/i2c/tda998x_drv.c | 157 ++++++++++++++++++++++++++++++++---
>  1 file changed, 137 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c
> b/drivers/gpu/drm/i2c/tda998x_drv.c index 9c78f7bde49c..012dee61d817 100644
> --- a/drivers/gpu/drm/i2c/tda998x_drv.c
> +++ b/drivers/gpu/drm/i2c/tda998x_drv.c
> @@ -36,6 +36,14 @@ struct tda998x_audio_port {
>  	u8 config;		/* AP value */
>  };
> 
> +struct tda998x_priv;
> +
> +struct tda998x_bridge {
> +	struct tda998x_priv *priv;
> +	struct device *dev;
> +	struct drm_bridge bridge;
> +};
> +
>  struct tda998x_priv {
>  	struct i2c_client *cec;
>  	struct i2c_client *hdmi;
> @@ -63,6 +71,8 @@ struct tda998x_priv {
>  	wait_queue_head_t edid_delay_waitq;
>  	bool edid_delay_active;
> 
> +	struct tda998x_bridge *bridge;
> +	bool local_encoder;
>  	struct drm_encoder encoder;
>  	struct drm_connector connector;
> 
> @@ -75,6 +85,9 @@ struct tda998x_priv {
>  #define enc_to_tda998x_priv(x) \
>  	container_of(x, struct tda998x_priv, encoder)
> 
> +#define bridge_to_tda998x_bridge(x) \
> +	container_of(x, struct tda998x_bridge, bridge)
> +
>  /* The TDA9988 series of devices use a paged register scheme.. to simplify
>   * things we encode the page # in upper bits of the register #.  To read/
>   * write a given register, we need to make sure CURPAGE register is set
> @@ -842,7 +855,8 @@ static int tda998x_audio_hw_params(struct device *dev,
> void *data, struct hdmi_codec_daifmt *daifmt,
>  				   struct hdmi_codec_params *params)
>  {
> -	struct tda998x_priv *priv = dev_get_drvdata(dev);
> +	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
> +	struct tda998x_priv *priv = bridge->priv;
>  	int i, ret;
>  	struct tda998x_audio_params audio = {
>  		.sample_width = params->sample_width,
> @@ -899,7 +913,8 @@ static int tda998x_audio_hw_params(struct device *dev,
> void *data,
> 
>  static void tda998x_audio_shutdown(struct device *dev, void *data)
>  {
> -	struct tda998x_priv *priv = dev_get_drvdata(dev);
> +	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
> +	struct tda998x_priv *priv = bridge->priv;
> 
>  	mutex_lock(&priv->audio_mutex);
> 
> @@ -912,7 +927,8 @@ static void tda998x_audio_shutdown(struct device *dev,
> void *data)
> 
>  int tda998x_audio_digital_mute(struct device *dev, void *data, bool enable)
> {
> -	struct tda998x_priv *priv = dev_get_drvdata(dev);
> +	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
> +	struct tda998x_priv *priv = bridge->priv;
> 
>  	mutex_lock(&priv->audio_mutex);
> 
> @@ -925,7 +941,8 @@ int tda998x_audio_digital_mute(struct device *dev, void
> *data, bool enable) static int tda998x_audio_get_eld(struct device *dev,
> void *data,
>  				 uint8_t *buf, size_t len)
>  {
> -	struct tda998x_priv *priv = dev_get_drvdata(dev);
> +	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
> +	struct tda998x_priv *priv = bridge->priv;
> 
>  	mutex_lock(&priv->audio_mutex);
>  	memcpy(buf, priv->connector.eld,
> @@ -1126,7 +1143,10 @@ tda998x_connector_best_encoder(struct drm_connector
> *connector) {
>  	struct tda998x_priv *priv = conn_to_tda998x_priv(connector);
> 
> -	return &priv->encoder;
> +	if (priv->local_encoder)
> +		return &priv->encoder;
> +	else
> +		return priv->bridge->bridge.encoder;
>  }
> 
>  static
> @@ -1140,6 +1160,7 @@ static int tda998x_connector_init(struct tda998x_priv
> *priv, struct drm_device *drm)
>  {
>  	struct drm_connector *connector = &priv->connector;
> +	struct drm_encoder *encoder;
>  	int ret;
> 
>  	connector->interlace_allowed = 1;
> @@ -1156,7 +1177,8 @@ static int tda998x_connector_init(struct tda998x_priv
> *priv, if (ret)
>  		return ret;
> 
> -	drm_mode_connector_attach_encoder(&priv->connector, &priv->encoder);
> +	encoder = tda998x_connector_best_encoder(&priv->connector);
> +	drm_mode_connector_attach_encoder(&priv->connector, encoder);
> 
>  	return 0;
>  }
> @@ -1668,8 +1690,10 @@ static void tda998x_set_config(struct tda998x_priv
> *priv, priv->audio_params = p->audio_params;
>  }
> 
> -static int tda998x_init(struct device *dev, struct drm_device *drm)
> +static int tda998x_init(struct device *dev, struct drm_device *drm,
> +			bool local_encoder)
>  {
> +	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
>  	struct tda998x_encoder_params *params = dev->platform_data;
>  	struct i2c_client *client = to_i2c_client(dev);
>  	struct tda998x_priv *priv;
> @@ -1680,7 +1704,9 @@ static int tda998x_init(struct device *dev, struct
> drm_device *drm) if (!priv)
>  		return -ENOMEM;
> 
> -	dev_set_drvdata(dev, priv);
> +	bridge->priv = priv;
> +	priv->bridge = bridge;
> +	priv->local_encoder = local_encoder;
> 
>  	if (dev->of_node)
>  		crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
> @@ -1691,7 +1717,8 @@ static int tda998x_init(struct device *dev, struct
> drm_device *drm) crtcs = 1 << 0;
>  	}
> 
> -	priv->encoder.possible_crtcs = crtcs;
> +	if (local_encoder)
> +		priv->encoder.possible_crtcs = crtcs;
> 
>  	ret = tda998x_create(client, priv);
>  	if (ret)
> @@ -1700,11 +1727,15 @@ static int tda998x_init(struct device *dev, struct
> drm_device *drm) if (!dev->of_node && params)
>  		tda998x_set_config(priv, params);
> 
> -	drm_encoder_helper_add(&priv->encoder, &tda998x_encoder_helper_funcs);
> -	ret = drm_encoder_init(drm, &priv->encoder, &tda998x_encoder_funcs,
> -			       DRM_MODE_ENCODER_TMDS, NULL);
> -	if (ret)
> -		goto err_encoder;
> +	if (local_encoder) {
> +		drm_encoder_helper_add(&priv->encoder,
> +				       &tda998x_encoder_helper_funcs);
> +		ret = drm_encoder_init(drm, &priv->encoder,
> +				       &tda998x_encoder_funcs,
> +				       DRM_MODE_ENCODER_TMDS, NULL);
> +		if (ret)
> +			goto err_encoder;
> +	}
> 
>  	ret = tda998x_connector_init(priv, drm);
>  	if (ret)
> @@ -1713,7 +1744,8 @@ static int tda998x_init(struct device *dev, struct
> drm_device *drm) return 0;
> 
>  err_connector:
> -	drm_encoder_cleanup(&priv->encoder);
> +	if (local_encoder)
> +		drm_encoder_cleanup(&priv->encoder);
>  err_encoder:
>  	tda998x_destroy(priv);
>  	return ret;
> @@ -1721,10 +1753,12 @@ static int tda998x_init(struct device *dev, struct
> drm_device *drm)
> 
>  static void tda998x_fini(struct device *dev)
>  {
> -	struct tda998x_priv *priv = dev_get_drvdata(dev);
> +	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
> +	struct tda998x_priv *priv = bridge->priv;
> 
>  	drm_connector_cleanup(&priv->connector);
> -	drm_encoder_cleanup(&priv->encoder);
> +	if (priv->local_encoder)
> +		drm_encoder_cleanup(&priv->encoder);
>  	tda998x_destroy(priv);
>  }
> 
> @@ -1732,7 +1766,7 @@ static int tda998x_bind(struct device *dev, struct
> device *master, void *data) {
>  	struct drm_device *drm = data;
> 
> -	return tda998x_init(dev, drm);
> +	return tda998x_init(dev, drm, true);
>  }
> 
>  static void tda998x_unbind(struct device *dev, struct device *master,
> @@ -1746,19 +1780,102 @@ static const struct component_ops tda998x_ops = {
>  	.unbind = tda998x_unbind,
>  };
> 
> +/* DRM bridge functions */
> +
> +static int tda998x_bridge_attach(struct drm_bridge *dbridge)
> +{
> +	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
> +	struct device *dev = bridge->dev;
> +	struct drm_device *drm = bridge->bridge.dev;
> +
> +	dev_info(dev, "attach\n");

You can drop all the dev_info messages.

> +	return tda998x_init(dev, drm, false);
> +}
> +
> +static void tda998x_bridge_detach(struct drm_bridge *dbridge)
> +{
> +	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
> +	struct device *dev = bridge->dev;
> +
> +	dev_info(dev, "detach\n");
> +	tda998x_fini(dev);
> +}
> +
> +static void tda998x_bridge_enable(struct drm_bridge *dbridge)
> +{
> +	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
> +	struct tda998x_priv *priv = bridge->priv;
> +
> +	dev_info(bridge->dev, "enable\n");
> +	tda998x_dpms(priv, DRM_MODE_DPMS_ON);
> +}
> +
> +static void tda998x_bridge_disable(struct drm_bridge *dbridge)
> +{
> +	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
> +	struct tda998x_priv *priv = bridge->priv;
> +
> +	dev_info(bridge->dev, "disable\n");
> +	tda998x_dpms(priv, DRM_MODE_DPMS_OFF);
> +}
> +
> +static void tda998x_bridge_mode_set(struct drm_bridge *dbridge,
> +				    struct drm_display_mode *mode,
> +				    struct drm_display_mode *adjusted_mode)
> +{
> +	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
> +	struct tda998x_priv *priv = bridge->priv;
> +
> +	tda998x_mode_set(priv, mode, adjusted_mode);
> +}
> +
> +static const struct drm_bridge_funcs tda998x_bridge_funcs = {
> +	.attach = tda998x_bridge_attach,
> +	.detach = tda998x_bridge_detach,
> +	.enable = tda998x_bridge_enable,
> +	.disable = tda998x_bridge_disable,
> +	.mode_set = tda998x_bridge_mode_set,
> +};
> +
>  static int
>  tda998x_probe(struct i2c_client *client, const struct i2c_device_id *id)
>  {
> +	struct device *dev = &client->dev;
> +	struct tda998x_bridge *bridge;
> +	int ret;
> +
>  	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
>  		dev_warn(&client->dev, "adapter does not support I2C\n");
>  		return -EIO;
>  	}
> -	return component_add(&client->dev, &tda998x_ops);
> +
> +	bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
> +	if (!bridge)
> +		return -ENOMEM;
> +
> +	bridge->dev = dev;
> +	dev_set_drvdata(dev, bridge);
> +
> +	bridge->bridge.funcs = &tda998x_bridge_funcs;
> +	bridge->bridge.of_node = dev->of_node;
> +	drm_bridge_add(&bridge->bridge);
> +
> +	ret = component_add(dev, &tda998x_ops);
> +
> +	if (ret)
> +		drm_bridge_remove(&bridge->bridge);
> +
> +	return ret;
>  }
> 
>  static int tda998x_remove(struct i2c_client *client)
>  {
> -	component_del(&client->dev, &tda998x_ops);
> +	struct device *dev = &client->dev;
> +	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
> +
> +	drm_bridge_remove(&bridge->bridge);
> +	component_del(dev, &tda998x_ops);
> +
>  	return 0;
>  }

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v3 7/7] drm/i2c: tda998x: register as a drm bridge
@ 2018-04-20 10:06     ` Laurent Pinchart
  0 siblings, 0 replies; 67+ messages in thread
From: Laurent Pinchart @ 2018-04-20 10:06 UTC (permalink / raw)
  To: dri-devel
  Cc: Mark Rutland, Boris Brezillon, Alexandre Belloni, devicetree,
	David Airlie, linux-kernel, Nicolas Ferre, Rob Herring,
	Jacopo Mondi, Daniel Vetter, Russell King, Peter Rosin,
	linux-arm-kernel

Hi Peter,

Thank you for the patch.

On Thursday, 19 April 2018 19:27:51 EEST Peter Rosin wrote:
> This makes this driver work with all(?) drivers that are not
> componentized and instead expect to connect to a panel/bridge. That
> said, the only one tested is atmel_hlcdc.
> 
> This hooks the relevant work function previously called by the encoder
> and the component also to the bridge, since the encoder goes away when
> connecting to the bridge interface of the driver and the equivalent of
> bind/unbind of the component is handled by bridge attach/detach.
> 
> The lifetime requirements of a bridge and a component are slightly
> different, which is the reason for struct tda998x_bridge.

Couldn't you move the allocation and initialization (tda998x_create) of the 
tda998x_priv structure to probe time ? I think you wouldn't need a separate 
structure in that case. Unless I'm mistaken there would be an added benefit of 
separating component and bridge initialization, resulting in the encoder not 
being initialized at all if the component isn't used. You wouldn't need to add 
a local_encoder parameter to the tda998x_init() function.

> Signed-off-by: Peter Rosin <peda@axentia.se>
> ---
>  drivers/gpu/drm/i2c/tda998x_drv.c | 157 ++++++++++++++++++++++++++++++++---
>  1 file changed, 137 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c
> b/drivers/gpu/drm/i2c/tda998x_drv.c index 9c78f7bde49c..012dee61d817 100644
> --- a/drivers/gpu/drm/i2c/tda998x_drv.c
> +++ b/drivers/gpu/drm/i2c/tda998x_drv.c
> @@ -36,6 +36,14 @@ struct tda998x_audio_port {
>  	u8 config;		/* AP value */
>  };
> 
> +struct tda998x_priv;
> +
> +struct tda998x_bridge {
> +	struct tda998x_priv *priv;
> +	struct device *dev;
> +	struct drm_bridge bridge;
> +};
> +
>  struct tda998x_priv {
>  	struct i2c_client *cec;
>  	struct i2c_client *hdmi;
> @@ -63,6 +71,8 @@ struct tda998x_priv {
>  	wait_queue_head_t edid_delay_waitq;
>  	bool edid_delay_active;
> 
> +	struct tda998x_bridge *bridge;
> +	bool local_encoder;
>  	struct drm_encoder encoder;
>  	struct drm_connector connector;
> 
> @@ -75,6 +85,9 @@ struct tda998x_priv {
>  #define enc_to_tda998x_priv(x) \
>  	container_of(x, struct tda998x_priv, encoder)
> 
> +#define bridge_to_tda998x_bridge(x) \
> +	container_of(x, struct tda998x_bridge, bridge)
> +
>  /* The TDA9988 series of devices use a paged register scheme.. to simplify
>   * things we encode the page # in upper bits of the register #.  To read/
>   * write a given register, we need to make sure CURPAGE register is set
> @@ -842,7 +855,8 @@ static int tda998x_audio_hw_params(struct device *dev,
> void *data, struct hdmi_codec_daifmt *daifmt,
>  				   struct hdmi_codec_params *params)
>  {
> -	struct tda998x_priv *priv = dev_get_drvdata(dev);
> +	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
> +	struct tda998x_priv *priv = bridge->priv;
>  	int i, ret;
>  	struct tda998x_audio_params audio = {
>  		.sample_width = params->sample_width,
> @@ -899,7 +913,8 @@ static int tda998x_audio_hw_params(struct device *dev,
> void *data,
> 
>  static void tda998x_audio_shutdown(struct device *dev, void *data)
>  {
> -	struct tda998x_priv *priv = dev_get_drvdata(dev);
> +	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
> +	struct tda998x_priv *priv = bridge->priv;
> 
>  	mutex_lock(&priv->audio_mutex);
> 
> @@ -912,7 +927,8 @@ static void tda998x_audio_shutdown(struct device *dev,
> void *data)
> 
>  int tda998x_audio_digital_mute(struct device *dev, void *data, bool enable)
> {
> -	struct tda998x_priv *priv = dev_get_drvdata(dev);
> +	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
> +	struct tda998x_priv *priv = bridge->priv;
> 
>  	mutex_lock(&priv->audio_mutex);
> 
> @@ -925,7 +941,8 @@ int tda998x_audio_digital_mute(struct device *dev, void
> *data, bool enable) static int tda998x_audio_get_eld(struct device *dev,
> void *data,
>  				 uint8_t *buf, size_t len)
>  {
> -	struct tda998x_priv *priv = dev_get_drvdata(dev);
> +	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
> +	struct tda998x_priv *priv = bridge->priv;
> 
>  	mutex_lock(&priv->audio_mutex);
>  	memcpy(buf, priv->connector.eld,
> @@ -1126,7 +1143,10 @@ tda998x_connector_best_encoder(struct drm_connector
> *connector) {
>  	struct tda998x_priv *priv = conn_to_tda998x_priv(connector);
> 
> -	return &priv->encoder;
> +	if (priv->local_encoder)
> +		return &priv->encoder;
> +	else
> +		return priv->bridge->bridge.encoder;
>  }
> 
>  static
> @@ -1140,6 +1160,7 @@ static int tda998x_connector_init(struct tda998x_priv
> *priv, struct drm_device *drm)
>  {
>  	struct drm_connector *connector = &priv->connector;
> +	struct drm_encoder *encoder;
>  	int ret;
> 
>  	connector->interlace_allowed = 1;
> @@ -1156,7 +1177,8 @@ static int tda998x_connector_init(struct tda998x_priv
> *priv, if (ret)
>  		return ret;
> 
> -	drm_mode_connector_attach_encoder(&priv->connector, &priv->encoder);
> +	encoder = tda998x_connector_best_encoder(&priv->connector);
> +	drm_mode_connector_attach_encoder(&priv->connector, encoder);
> 
>  	return 0;
>  }
> @@ -1668,8 +1690,10 @@ static void tda998x_set_config(struct tda998x_priv
> *priv, priv->audio_params = p->audio_params;
>  }
> 
> -static int tda998x_init(struct device *dev, struct drm_device *drm)
> +static int tda998x_init(struct device *dev, struct drm_device *drm,
> +			bool local_encoder)
>  {
> +	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
>  	struct tda998x_encoder_params *params = dev->platform_data;
>  	struct i2c_client *client = to_i2c_client(dev);
>  	struct tda998x_priv *priv;
> @@ -1680,7 +1704,9 @@ static int tda998x_init(struct device *dev, struct
> drm_device *drm) if (!priv)
>  		return -ENOMEM;
> 
> -	dev_set_drvdata(dev, priv);
> +	bridge->priv = priv;
> +	priv->bridge = bridge;
> +	priv->local_encoder = local_encoder;
> 
>  	if (dev->of_node)
>  		crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
> @@ -1691,7 +1717,8 @@ static int tda998x_init(struct device *dev, struct
> drm_device *drm) crtcs = 1 << 0;
>  	}
> 
> -	priv->encoder.possible_crtcs = crtcs;
> +	if (local_encoder)
> +		priv->encoder.possible_crtcs = crtcs;
> 
>  	ret = tda998x_create(client, priv);
>  	if (ret)
> @@ -1700,11 +1727,15 @@ static int tda998x_init(struct device *dev, struct
> drm_device *drm) if (!dev->of_node && params)
>  		tda998x_set_config(priv, params);
> 
> -	drm_encoder_helper_add(&priv->encoder, &tda998x_encoder_helper_funcs);
> -	ret = drm_encoder_init(drm, &priv->encoder, &tda998x_encoder_funcs,
> -			       DRM_MODE_ENCODER_TMDS, NULL);
> -	if (ret)
> -		goto err_encoder;
> +	if (local_encoder) {
> +		drm_encoder_helper_add(&priv->encoder,
> +				       &tda998x_encoder_helper_funcs);
> +		ret = drm_encoder_init(drm, &priv->encoder,
> +				       &tda998x_encoder_funcs,
> +				       DRM_MODE_ENCODER_TMDS, NULL);
> +		if (ret)
> +			goto err_encoder;
> +	}
> 
>  	ret = tda998x_connector_init(priv, drm);
>  	if (ret)
> @@ -1713,7 +1744,8 @@ static int tda998x_init(struct device *dev, struct
> drm_device *drm) return 0;
> 
>  err_connector:
> -	drm_encoder_cleanup(&priv->encoder);
> +	if (local_encoder)
> +		drm_encoder_cleanup(&priv->encoder);
>  err_encoder:
>  	tda998x_destroy(priv);
>  	return ret;
> @@ -1721,10 +1753,12 @@ static int tda998x_init(struct device *dev, struct
> drm_device *drm)
> 
>  static void tda998x_fini(struct device *dev)
>  {
> -	struct tda998x_priv *priv = dev_get_drvdata(dev);
> +	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
> +	struct tda998x_priv *priv = bridge->priv;
> 
>  	drm_connector_cleanup(&priv->connector);
> -	drm_encoder_cleanup(&priv->encoder);
> +	if (priv->local_encoder)
> +		drm_encoder_cleanup(&priv->encoder);
>  	tda998x_destroy(priv);
>  }
> 
> @@ -1732,7 +1766,7 @@ static int tda998x_bind(struct device *dev, struct
> device *master, void *data) {
>  	struct drm_device *drm = data;
> 
> -	return tda998x_init(dev, drm);
> +	return tda998x_init(dev, drm, true);
>  }
> 
>  static void tda998x_unbind(struct device *dev, struct device *master,
> @@ -1746,19 +1780,102 @@ static const struct component_ops tda998x_ops = {
>  	.unbind = tda998x_unbind,
>  };
> 
> +/* DRM bridge functions */
> +
> +static int tda998x_bridge_attach(struct drm_bridge *dbridge)
> +{
> +	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
> +	struct device *dev = bridge->dev;
> +	struct drm_device *drm = bridge->bridge.dev;
> +
> +	dev_info(dev, "attach\n");

You can drop all the dev_info messages.

> +	return tda998x_init(dev, drm, false);
> +}
> +
> +static void tda998x_bridge_detach(struct drm_bridge *dbridge)
> +{
> +	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
> +	struct device *dev = bridge->dev;
> +
> +	dev_info(dev, "detach\n");
> +	tda998x_fini(dev);
> +}
> +
> +static void tda998x_bridge_enable(struct drm_bridge *dbridge)
> +{
> +	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
> +	struct tda998x_priv *priv = bridge->priv;
> +
> +	dev_info(bridge->dev, "enable\n");
> +	tda998x_dpms(priv, DRM_MODE_DPMS_ON);
> +}
> +
> +static void tda998x_bridge_disable(struct drm_bridge *dbridge)
> +{
> +	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
> +	struct tda998x_priv *priv = bridge->priv;
> +
> +	dev_info(bridge->dev, "disable\n");
> +	tda998x_dpms(priv, DRM_MODE_DPMS_OFF);
> +}
> +
> +static void tda998x_bridge_mode_set(struct drm_bridge *dbridge,
> +				    struct drm_display_mode *mode,
> +				    struct drm_display_mode *adjusted_mode)
> +{
> +	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
> +	struct tda998x_priv *priv = bridge->priv;
> +
> +	tda998x_mode_set(priv, mode, adjusted_mode);
> +}
> +
> +static const struct drm_bridge_funcs tda998x_bridge_funcs = {
> +	.attach = tda998x_bridge_attach,
> +	.detach = tda998x_bridge_detach,
> +	.enable = tda998x_bridge_enable,
> +	.disable = tda998x_bridge_disable,
> +	.mode_set = tda998x_bridge_mode_set,
> +};
> +
>  static int
>  tda998x_probe(struct i2c_client *client, const struct i2c_device_id *id)
>  {
> +	struct device *dev = &client->dev;
> +	struct tda998x_bridge *bridge;
> +	int ret;
> +
>  	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
>  		dev_warn(&client->dev, "adapter does not support I2C\n");
>  		return -EIO;
>  	}
> -	return component_add(&client->dev, &tda998x_ops);
> +
> +	bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
> +	if (!bridge)
> +		return -ENOMEM;
> +
> +	bridge->dev = dev;
> +	dev_set_drvdata(dev, bridge);
> +
> +	bridge->bridge.funcs = &tda998x_bridge_funcs;
> +	bridge->bridge.of_node = dev->of_node;
> +	drm_bridge_add(&bridge->bridge);
> +
> +	ret = component_add(dev, &tda998x_ops);
> +
> +	if (ret)
> +		drm_bridge_remove(&bridge->bridge);
> +
> +	return ret;
>  }
> 
>  static int tda998x_remove(struct i2c_client *client)
>  {
> -	component_del(&client->dev, &tda998x_ops);
> +	struct device *dev = &client->dev;
> +	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
> +
> +	drm_bridge_remove(&bridge->bridge);
> +	component_del(dev, &tda998x_ops);
> +
>  	return 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] 67+ messages in thread

* [PATCH v3 7/7] drm/i2c: tda998x: register as a drm bridge
@ 2018-04-20 10:06     ` Laurent Pinchart
  0 siblings, 0 replies; 67+ messages in thread
From: Laurent Pinchart @ 2018-04-20 10:06 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Peter,

Thank you for the patch.

On Thursday, 19 April 2018 19:27:51 EEST Peter Rosin wrote:
> This makes this driver work with all(?) drivers that are not
> componentized and instead expect to connect to a panel/bridge. That
> said, the only one tested is atmel_hlcdc.
> 
> This hooks the relevant work function previously called by the encoder
> and the component also to the bridge, since the encoder goes away when
> connecting to the bridge interface of the driver and the equivalent of
> bind/unbind of the component is handled by bridge attach/detach.
> 
> The lifetime requirements of a bridge and a component are slightly
> different, which is the reason for struct tda998x_bridge.

Couldn't you move the allocation and initialization (tda998x_create) of the 
tda998x_priv structure to probe time ? I think you wouldn't need a separate 
structure in that case. Unless I'm mistaken there would be an added benefit of 
separating component and bridge initialization, resulting in the encoder not 
being initialized at all if the component isn't used. You wouldn't need to add 
a local_encoder parameter to the tda998x_init() function.

> Signed-off-by: Peter Rosin <peda@axentia.se>
> ---
>  drivers/gpu/drm/i2c/tda998x_drv.c | 157 ++++++++++++++++++++++++++++++++---
>  1 file changed, 137 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c
> b/drivers/gpu/drm/i2c/tda998x_drv.c index 9c78f7bde49c..012dee61d817 100644
> --- a/drivers/gpu/drm/i2c/tda998x_drv.c
> +++ b/drivers/gpu/drm/i2c/tda998x_drv.c
> @@ -36,6 +36,14 @@ struct tda998x_audio_port {
>  	u8 config;		/* AP value */
>  };
> 
> +struct tda998x_priv;
> +
> +struct tda998x_bridge {
> +	struct tda998x_priv *priv;
> +	struct device *dev;
> +	struct drm_bridge bridge;
> +};
> +
>  struct tda998x_priv {
>  	struct i2c_client *cec;
>  	struct i2c_client *hdmi;
> @@ -63,6 +71,8 @@ struct tda998x_priv {
>  	wait_queue_head_t edid_delay_waitq;
>  	bool edid_delay_active;
> 
> +	struct tda998x_bridge *bridge;
> +	bool local_encoder;
>  	struct drm_encoder encoder;
>  	struct drm_connector connector;
> 
> @@ -75,6 +85,9 @@ struct tda998x_priv {
>  #define enc_to_tda998x_priv(x) \
>  	container_of(x, struct tda998x_priv, encoder)
> 
> +#define bridge_to_tda998x_bridge(x) \
> +	container_of(x, struct tda998x_bridge, bridge)
> +
>  /* The TDA9988 series of devices use a paged register scheme.. to simplify
>   * things we encode the page # in upper bits of the register #.  To read/
>   * write a given register, we need to make sure CURPAGE register is set
> @@ -842,7 +855,8 @@ static int tda998x_audio_hw_params(struct device *dev,
> void *data, struct hdmi_codec_daifmt *daifmt,
>  				   struct hdmi_codec_params *params)
>  {
> -	struct tda998x_priv *priv = dev_get_drvdata(dev);
> +	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
> +	struct tda998x_priv *priv = bridge->priv;
>  	int i, ret;
>  	struct tda998x_audio_params audio = {
>  		.sample_width = params->sample_width,
> @@ -899,7 +913,8 @@ static int tda998x_audio_hw_params(struct device *dev,
> void *data,
> 
>  static void tda998x_audio_shutdown(struct device *dev, void *data)
>  {
> -	struct tda998x_priv *priv = dev_get_drvdata(dev);
> +	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
> +	struct tda998x_priv *priv = bridge->priv;
> 
>  	mutex_lock(&priv->audio_mutex);
> 
> @@ -912,7 +927,8 @@ static void tda998x_audio_shutdown(struct device *dev,
> void *data)
> 
>  int tda998x_audio_digital_mute(struct device *dev, void *data, bool enable)
> {
> -	struct tda998x_priv *priv = dev_get_drvdata(dev);
> +	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
> +	struct tda998x_priv *priv = bridge->priv;
> 
>  	mutex_lock(&priv->audio_mutex);
> 
> @@ -925,7 +941,8 @@ int tda998x_audio_digital_mute(struct device *dev, void
> *data, bool enable) static int tda998x_audio_get_eld(struct device *dev,
> void *data,
>  				 uint8_t *buf, size_t len)
>  {
> -	struct tda998x_priv *priv = dev_get_drvdata(dev);
> +	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
> +	struct tda998x_priv *priv = bridge->priv;
> 
>  	mutex_lock(&priv->audio_mutex);
>  	memcpy(buf, priv->connector.eld,
> @@ -1126,7 +1143,10 @@ tda998x_connector_best_encoder(struct drm_connector
> *connector) {
>  	struct tda998x_priv *priv = conn_to_tda998x_priv(connector);
> 
> -	return &priv->encoder;
> +	if (priv->local_encoder)
> +		return &priv->encoder;
> +	else
> +		return priv->bridge->bridge.encoder;
>  }
> 
>  static
> @@ -1140,6 +1160,7 @@ static int tda998x_connector_init(struct tda998x_priv
> *priv, struct drm_device *drm)
>  {
>  	struct drm_connector *connector = &priv->connector;
> +	struct drm_encoder *encoder;
>  	int ret;
> 
>  	connector->interlace_allowed = 1;
> @@ -1156,7 +1177,8 @@ static int tda998x_connector_init(struct tda998x_priv
> *priv, if (ret)
>  		return ret;
> 
> -	drm_mode_connector_attach_encoder(&priv->connector, &priv->encoder);
> +	encoder = tda998x_connector_best_encoder(&priv->connector);
> +	drm_mode_connector_attach_encoder(&priv->connector, encoder);
> 
>  	return 0;
>  }
> @@ -1668,8 +1690,10 @@ static void tda998x_set_config(struct tda998x_priv
> *priv, priv->audio_params = p->audio_params;
>  }
> 
> -static int tda998x_init(struct device *dev, struct drm_device *drm)
> +static int tda998x_init(struct device *dev, struct drm_device *drm,
> +			bool local_encoder)
>  {
> +	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
>  	struct tda998x_encoder_params *params = dev->platform_data;
>  	struct i2c_client *client = to_i2c_client(dev);
>  	struct tda998x_priv *priv;
> @@ -1680,7 +1704,9 @@ static int tda998x_init(struct device *dev, struct
> drm_device *drm) if (!priv)
>  		return -ENOMEM;
> 
> -	dev_set_drvdata(dev, priv);
> +	bridge->priv = priv;
> +	priv->bridge = bridge;
> +	priv->local_encoder = local_encoder;
> 
>  	if (dev->of_node)
>  		crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
> @@ -1691,7 +1717,8 @@ static int tda998x_init(struct device *dev, struct
> drm_device *drm) crtcs = 1 << 0;
>  	}
> 
> -	priv->encoder.possible_crtcs = crtcs;
> +	if (local_encoder)
> +		priv->encoder.possible_crtcs = crtcs;
> 
>  	ret = tda998x_create(client, priv);
>  	if (ret)
> @@ -1700,11 +1727,15 @@ static int tda998x_init(struct device *dev, struct
> drm_device *drm) if (!dev->of_node && params)
>  		tda998x_set_config(priv, params);
> 
> -	drm_encoder_helper_add(&priv->encoder, &tda998x_encoder_helper_funcs);
> -	ret = drm_encoder_init(drm, &priv->encoder, &tda998x_encoder_funcs,
> -			       DRM_MODE_ENCODER_TMDS, NULL);
> -	if (ret)
> -		goto err_encoder;
> +	if (local_encoder) {
> +		drm_encoder_helper_add(&priv->encoder,
> +				       &tda998x_encoder_helper_funcs);
> +		ret = drm_encoder_init(drm, &priv->encoder,
> +				       &tda998x_encoder_funcs,
> +				       DRM_MODE_ENCODER_TMDS, NULL);
> +		if (ret)
> +			goto err_encoder;
> +	}
> 
>  	ret = tda998x_connector_init(priv, drm);
>  	if (ret)
> @@ -1713,7 +1744,8 @@ static int tda998x_init(struct device *dev, struct
> drm_device *drm) return 0;
> 
>  err_connector:
> -	drm_encoder_cleanup(&priv->encoder);
> +	if (local_encoder)
> +		drm_encoder_cleanup(&priv->encoder);
>  err_encoder:
>  	tda998x_destroy(priv);
>  	return ret;
> @@ -1721,10 +1753,12 @@ static int tda998x_init(struct device *dev, struct
> drm_device *drm)
> 
>  static void tda998x_fini(struct device *dev)
>  {
> -	struct tda998x_priv *priv = dev_get_drvdata(dev);
> +	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
> +	struct tda998x_priv *priv = bridge->priv;
> 
>  	drm_connector_cleanup(&priv->connector);
> -	drm_encoder_cleanup(&priv->encoder);
> +	if (priv->local_encoder)
> +		drm_encoder_cleanup(&priv->encoder);
>  	tda998x_destroy(priv);
>  }
> 
> @@ -1732,7 +1766,7 @@ static int tda998x_bind(struct device *dev, struct
> device *master, void *data) {
>  	struct drm_device *drm = data;
> 
> -	return tda998x_init(dev, drm);
> +	return tda998x_init(dev, drm, true);
>  }
> 
>  static void tda998x_unbind(struct device *dev, struct device *master,
> @@ -1746,19 +1780,102 @@ static const struct component_ops tda998x_ops = {
>  	.unbind = tda998x_unbind,
>  };
> 
> +/* DRM bridge functions */
> +
> +static int tda998x_bridge_attach(struct drm_bridge *dbridge)
> +{
> +	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
> +	struct device *dev = bridge->dev;
> +	struct drm_device *drm = bridge->bridge.dev;
> +
> +	dev_info(dev, "attach\n");

You can drop all the dev_info messages.

> +	return tda998x_init(dev, drm, false);
> +}
> +
> +static void tda998x_bridge_detach(struct drm_bridge *dbridge)
> +{
> +	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
> +	struct device *dev = bridge->dev;
> +
> +	dev_info(dev, "detach\n");
> +	tda998x_fini(dev);
> +}
> +
> +static void tda998x_bridge_enable(struct drm_bridge *dbridge)
> +{
> +	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
> +	struct tda998x_priv *priv = bridge->priv;
> +
> +	dev_info(bridge->dev, "enable\n");
> +	tda998x_dpms(priv, DRM_MODE_DPMS_ON);
> +}
> +
> +static void tda998x_bridge_disable(struct drm_bridge *dbridge)
> +{
> +	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
> +	struct tda998x_priv *priv = bridge->priv;
> +
> +	dev_info(bridge->dev, "disable\n");
> +	tda998x_dpms(priv, DRM_MODE_DPMS_OFF);
> +}
> +
> +static void tda998x_bridge_mode_set(struct drm_bridge *dbridge,
> +				    struct drm_display_mode *mode,
> +				    struct drm_display_mode *adjusted_mode)
> +{
> +	struct tda998x_bridge *bridge = bridge_to_tda998x_bridge(dbridge);
> +	struct tda998x_priv *priv = bridge->priv;
> +
> +	tda998x_mode_set(priv, mode, adjusted_mode);
> +}
> +
> +static const struct drm_bridge_funcs tda998x_bridge_funcs = {
> +	.attach = tda998x_bridge_attach,
> +	.detach = tda998x_bridge_detach,
> +	.enable = tda998x_bridge_enable,
> +	.disable = tda998x_bridge_disable,
> +	.mode_set = tda998x_bridge_mode_set,
> +};
> +
>  static int
>  tda998x_probe(struct i2c_client *client, const struct i2c_device_id *id)
>  {
> +	struct device *dev = &client->dev;
> +	struct tda998x_bridge *bridge;
> +	int ret;
> +
>  	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
>  		dev_warn(&client->dev, "adapter does not support I2C\n");
>  		return -EIO;
>  	}
> -	return component_add(&client->dev, &tda998x_ops);
> +
> +	bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
> +	if (!bridge)
> +		return -ENOMEM;
> +
> +	bridge->dev = dev;
> +	dev_set_drvdata(dev, bridge);
> +
> +	bridge->bridge.funcs = &tda998x_bridge_funcs;
> +	bridge->bridge.of_node = dev->of_node;
> +	drm_bridge_add(&bridge->bridge);
> +
> +	ret = component_add(dev, &tda998x_ops);
> +
> +	if (ret)
> +		drm_bridge_remove(&bridge->bridge);
> +
> +	return ret;
>  }
> 
>  static int tda998x_remove(struct i2c_client *client)
>  {
> -	component_del(&client->dev, &tda998x_ops);
> +	struct device *dev = &client->dev;
> +	struct tda998x_bridge *bridge = dev_get_drvdata(dev);
> +
> +	drm_bridge_remove(&bridge->bridge);
> +	component_del(dev, &tda998x_ops);
> +
>  	return 0;
>  }

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
  2018-04-20  8:52   ` jacopo mondi
  (?)
@ 2018-04-20 10:18     ` Laurent Pinchart
  -1 siblings, 0 replies; 67+ messages in thread
From: Laurent Pinchart @ 2018-04-20 10:18 UTC (permalink / raw)
  To: jacopo mondi
  Cc: Peter Rosin, linux-kernel, David Airlie, Rob Herring,
	Mark Rutland, Nicolas Ferre, Alexandre Belloni, Boris Brezillon,
	Daniel Vetter, Gustavo Padovan, Sean Paul, Russell King,
	Jacopo Mondi, dri-devel, devicetree, linux-arm-kernel

Hello,

On Friday, 20 April 2018 11:52:35 EEST jacopo mondi wrote:
> Hi Peter,
>     I've been a bit a pain in the arse for you recently, but please
> bear with me a bit more, and sorry for jumping late on the band wagon.
> 
> On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
> > Hi!
> > 
> > I naively thought that since there was support for both nxp,tda19988 (in
> > the tda998x driver) and the atmel-hlcdc, things would be a smooth ride.
> > But it wasn't, so I started looking around and realized I had to fix
> > things.
> > 
> > In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
> > component, but now in v3 I fix things by making the tda998x driver
> > a bridge instead. This was after a suggestion from Boris Brezillion
> > (the atmel-hlcdc maintainer), so there was some risk of bias ... but
> > after comparing what was needed, I too find the bridge approach better.
> > 
> > In addition to the above, our PCB interface between the SAMA5D3 and the
> > HDMI encoder is only using 16 bits, and this has to be described
> > somewhere, or the atmel-hlcdc driver have no chance of selecting the
> > correct output mode. Since I have similar problems with a ds90c185 lvds
> > encoder I added patches to override the atmel-hlcdc output format via
> > DT properties compatible with the media video-interface binding and
> > things start to play together.
> > 
> > Since this series superseeds the bridge series [1], I have included the
> > leftover bindings patch for the ti,ds90c185 here.
> 
> I feel like this series would look better if it would make use of the
> proposed bridge media bus format support I have recently sent out [1]
> (and which was not there when you first sent v1).
> 
> I understand your fundamental problem here is that the bus format
> that should be reported by your bridge is different from the ones
> actually supported by the TDA19988 chip, as the wirings ground some
> of the input pins.
> 
> Although this is defintely something that could be described in the
> bridge's own OF node with the 'bus_width' property, and what I would do,
> now that you have made a bridge out from the tda19988 driver, is:
> 
> 1) Set the bridge accepted input bus_format parsing its pin
> configuration, or default it if that's not implemented yet.
> This will likely be rgb888. You can do that using the trivial
> support for bridge input image formats implemented by my series.
> 2) Specify in the bridge endpoint a 'bus_width' of <16>
> 3) In your atmel-hlcd get both the image format of the bridge (rgb888)
> and parse the remote endpoint property 'bus_width' and get the <16>
> value back.

Parsing properties of remote nodes should be avoided as much as possible, as 
they need to be interpreted in the context of the DT bindings related to the 
compatible string applicable to that node. I'd rather have the bus_width 
property in the local endpoint node.

> 4) Set the correct format in the atmel hlcd driver to accommodate a
> bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
> or are there other possible combinations I am missing?)
> 
> I would consider this better mostly because in this series you are
> creating a semantic for the whole DRM subsystem on the 'bus_width'
> property, where numerical values as '12', '16' etc are arbitrary tied
> to the selection of a media bus format. At least you should use a
> common set of defines [1] between the device tree and the driver,
> but this looks anyway fragile imho.

This I agree with though. Combining the remote bus format with the local bus 
width should fix the problem without having to parse remote properties.

> Have I maybe missed some parts of the problem you are trying to solve
> here?
> 
> Thank you
>    j
> 
> [1] drm: bridge: Add support for static image formats
>     https://lwn.net/Articles/752296/
> [2] include/uapi/linux/media-bus-format.h
> 
> > Anyway, this series solves some real issues for my HW.
> > 
> > Cheers,
> > Peter
> > 
> > Changes since v2   https://lkml.org/lkml/2018/4/17/385
> > - patch 2/7 fixed spelling and added an example
> > - patch 4/7 parse the DT up front and store the result indexed by encoder
> > - old patch 5/6 and 6/6 dropped
> > - patch 5-7/7 are new and makes the tda998x driver a drm_bridge
> > 
> > Changes since v1   https://lkml.org/lkml/2018/4/9/294
> > - added reviewed-by from Rob to patch 1/6
> > - patch 2/6 changed so that the bus format override is in the endpoint
> >   DT node, and follows the binding of media video-interfaces.
> > - patch 3/6 is new, it adds drm_of_media_bus_fmt which parses above
> >   media video-interface binding (partially).
> > - patch 4/6 now makes use of the above helper (and also fixes problems
> >   with the 3/5 patch from v1 when no override was specified).
> > - do not mention unrelated connector display_info details in the cover
> >   letter and commit messages.
> > 
> > [1]
> > "Bridge" series v2   https://lkml.org/lkml/2018/3/26/610
> > "Bridge" series v1   https://lkml.org/lkml/2018/3/17/221
> > 
> > Peter Rosin (7):
> >   dt-bindings: display: bridge: lvds-transmitter: add ti,ds90c185
> >   dt-bindings: display: atmel: optional video-interface of endpoints
> >   drm: of: introduce drm_of_media_bus_fmt
> >   drm/atmel-hlcdc: support bus-width (12/16/18/24) in endpoint nodes
> >   drm/i2c: tda998x: find the drm_device via the drm_connector
> >   drm/i2c: tda998x: split encoder and component functions from the work
> >   drm/i2c: tda998x: register as a drm bridge
> >  
> >  .../devicetree/bindings/display/atmel/hlcdc-dc.txt |  26 +++
> >  .../bindings/display/bridge/lvds-transmitter.txt   |   8 +-
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c     |  71 ++++++--
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h       |   2 +
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c   |  40 +++-
> >  drivers/gpu/drm/drm_of.c                           |  38 ++++
> >  drivers/gpu/drm/i2c/tda998x_drv.c                  | 201 ++++++++++++++--
> >  include/drm/drm_of.h                               |   7 +
> >  8 files changed, 342 insertions(+), 51 deletions(-)

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
@ 2018-04-20 10:18     ` Laurent Pinchart
  0 siblings, 0 replies; 67+ messages in thread
From: Laurent Pinchart @ 2018-04-20 10:18 UTC (permalink / raw)
  To: jacopo mondi
  Cc: Mark Rutland, Boris Brezillon, Alexandre Belloni, devicetree,
	David Airlie, Nicolas Ferre, dri-devel, linux-kernel,
	Rob Herring, Jacopo Mondi, Daniel Vetter, Peter Rosin,
	Russell King, linux-arm-kernel

Hello,

On Friday, 20 April 2018 11:52:35 EEST jacopo mondi wrote:
> Hi Peter,
>     I've been a bit a pain in the arse for you recently, but please
> bear with me a bit more, and sorry for jumping late on the band wagon.
> 
> On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
> > Hi!
> > 
> > I naively thought that since there was support for both nxp,tda19988 (in
> > the tda998x driver) and the atmel-hlcdc, things would be a smooth ride.
> > But it wasn't, so I started looking around and realized I had to fix
> > things.
> > 
> > In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
> > component, but now in v3 I fix things by making the tda998x driver
> > a bridge instead. This was after a suggestion from Boris Brezillion
> > (the atmel-hlcdc maintainer), so there was some risk of bias ... but
> > after comparing what was needed, I too find the bridge approach better.
> > 
> > In addition to the above, our PCB interface between the SAMA5D3 and the
> > HDMI encoder is only using 16 bits, and this has to be described
> > somewhere, or the atmel-hlcdc driver have no chance of selecting the
> > correct output mode. Since I have similar problems with a ds90c185 lvds
> > encoder I added patches to override the atmel-hlcdc output format via
> > DT properties compatible with the media video-interface binding and
> > things start to play together.
> > 
> > Since this series superseeds the bridge series [1], I have included the
> > leftover bindings patch for the ti,ds90c185 here.
> 
> I feel like this series would look better if it would make use of the
> proposed bridge media bus format support I have recently sent out [1]
> (and which was not there when you first sent v1).
> 
> I understand your fundamental problem here is that the bus format
> that should be reported by your bridge is different from the ones
> actually supported by the TDA19988 chip, as the wirings ground some
> of the input pins.
> 
> Although this is defintely something that could be described in the
> bridge's own OF node with the 'bus_width' property, and what I would do,
> now that you have made a bridge out from the tda19988 driver, is:
> 
> 1) Set the bridge accepted input bus_format parsing its pin
> configuration, or default it if that's not implemented yet.
> This will likely be rgb888. You can do that using the trivial
> support for bridge input image formats implemented by my series.
> 2) Specify in the bridge endpoint a 'bus_width' of <16>
> 3) In your atmel-hlcd get both the image format of the bridge (rgb888)
> and parse the remote endpoint property 'bus_width' and get the <16>
> value back.

Parsing properties of remote nodes should be avoided as much as possible, as 
they need to be interpreted in the context of the DT bindings related to the 
compatible string applicable to that node. I'd rather have the bus_width 
property in the local endpoint node.

> 4) Set the correct format in the atmel hlcd driver to accommodate a
> bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
> or are there other possible combinations I am missing?)
> 
> I would consider this better mostly because in this series you are
> creating a semantic for the whole DRM subsystem on the 'bus_width'
> property, where numerical values as '12', '16' etc are arbitrary tied
> to the selection of a media bus format. At least you should use a
> common set of defines [1] between the device tree and the driver,
> but this looks anyway fragile imho.

This I agree with though. Combining the remote bus format with the local bus 
width should fix the problem without having to parse remote properties.

> Have I maybe missed some parts of the problem you are trying to solve
> here?
> 
> Thank you
>    j
> 
> [1] drm: bridge: Add support for static image formats
>     https://lwn.net/Articles/752296/
> [2] include/uapi/linux/media-bus-format.h
> 
> > Anyway, this series solves some real issues for my HW.
> > 
> > Cheers,
> > Peter
> > 
> > Changes since v2   https://lkml.org/lkml/2018/4/17/385
> > - patch 2/7 fixed spelling and added an example
> > - patch 4/7 parse the DT up front and store the result indexed by encoder
> > - old patch 5/6 and 6/6 dropped
> > - patch 5-7/7 are new and makes the tda998x driver a drm_bridge
> > 
> > Changes since v1   https://lkml.org/lkml/2018/4/9/294
> > - added reviewed-by from Rob to patch 1/6
> > - patch 2/6 changed so that the bus format override is in the endpoint
> >   DT node, and follows the binding of media video-interfaces.
> > - patch 3/6 is new, it adds drm_of_media_bus_fmt which parses above
> >   media video-interface binding (partially).
> > - patch 4/6 now makes use of the above helper (and also fixes problems
> >   with the 3/5 patch from v1 when no override was specified).
> > - do not mention unrelated connector display_info details in the cover
> >   letter and commit messages.
> > 
> > [1]
> > "Bridge" series v2   https://lkml.org/lkml/2018/3/26/610
> > "Bridge" series v1   https://lkml.org/lkml/2018/3/17/221
> > 
> > Peter Rosin (7):
> >   dt-bindings: display: bridge: lvds-transmitter: add ti,ds90c185
> >   dt-bindings: display: atmel: optional video-interface of endpoints
> >   drm: of: introduce drm_of_media_bus_fmt
> >   drm/atmel-hlcdc: support bus-width (12/16/18/24) in endpoint nodes
> >   drm/i2c: tda998x: find the drm_device via the drm_connector
> >   drm/i2c: tda998x: split encoder and component functions from the work
> >   drm/i2c: tda998x: register as a drm bridge
> >  
> >  .../devicetree/bindings/display/atmel/hlcdc-dc.txt |  26 +++
> >  .../bindings/display/bridge/lvds-transmitter.txt   |   8 +-
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c     |  71 ++++++--
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h       |   2 +
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c   |  40 +++-
> >  drivers/gpu/drm/drm_of.c                           |  38 ++++
> >  drivers/gpu/drm/i2c/tda998x_drv.c                  | 201 ++++++++++++++--
> >  include/drm/drm_of.h                               |   7 +
> >  8 files changed, 342 insertions(+), 51 deletions(-)

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

* [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
@ 2018-04-20 10:18     ` Laurent Pinchart
  0 siblings, 0 replies; 67+ messages in thread
From: Laurent Pinchart @ 2018-04-20 10:18 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Friday, 20 April 2018 11:52:35 EEST jacopo mondi wrote:
> Hi Peter,
>     I've been a bit a pain in the arse for you recently, but please
> bear with me a bit more, and sorry for jumping late on the band wagon.
> 
> On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
> > Hi!
> > 
> > I naively thought that since there was support for both nxp,tda19988 (in
> > the tda998x driver) and the atmel-hlcdc, things would be a smooth ride.
> > But it wasn't, so I started looking around and realized I had to fix
> > things.
> > 
> > In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
> > component, but now in v3 I fix things by making the tda998x driver
> > a bridge instead. This was after a suggestion from Boris Brezillion
> > (the atmel-hlcdc maintainer), so there was some risk of bias ... but
> > after comparing what was needed, I too find the bridge approach better.
> > 
> > In addition to the above, our PCB interface between the SAMA5D3 and the
> > HDMI encoder is only using 16 bits, and this has to be described
> > somewhere, or the atmel-hlcdc driver have no chance of selecting the
> > correct output mode. Since I have similar problems with a ds90c185 lvds
> > encoder I added patches to override the atmel-hlcdc output format via
> > DT properties compatible with the media video-interface binding and
> > things start to play together.
> > 
> > Since this series superseeds the bridge series [1], I have included the
> > leftover bindings patch for the ti,ds90c185 here.
> 
> I feel like this series would look better if it would make use of the
> proposed bridge media bus format support I have recently sent out [1]
> (and which was not there when you first sent v1).
> 
> I understand your fundamental problem here is that the bus format
> that should be reported by your bridge is different from the ones
> actually supported by the TDA19988 chip, as the wirings ground some
> of the input pins.
> 
> Although this is defintely something that could be described in the
> bridge's own OF node with the 'bus_width' property, and what I would do,
> now that you have made a bridge out from the tda19988 driver, is:
> 
> 1) Set the bridge accepted input bus_format parsing its pin
> configuration, or default it if that's not implemented yet.
> This will likely be rgb888. You can do that using the trivial
> support for bridge input image formats implemented by my series.
> 2) Specify in the bridge endpoint a 'bus_width' of <16>
> 3) In your atmel-hlcd get both the image format of the bridge (rgb888)
> and parse the remote endpoint property 'bus_width' and get the <16>
> value back.

Parsing properties of remote nodes should be avoided as much as possible, as 
they need to be interpreted in the context of the DT bindings related to the 
compatible string applicable to that node. I'd rather have the bus_width 
property in the local endpoint node.

> 4) Set the correct format in the atmel hlcd driver to accommodate a
> bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
> or are there other possible combinations I am missing?)
> 
> I would consider this better mostly because in this series you are
> creating a semantic for the whole DRM subsystem on the 'bus_width'
> property, where numerical values as '12', '16' etc are arbitrary tied
> to the selection of a media bus format. At least you should use a
> common set of defines [1] between the device tree and the driver,
> but this looks anyway fragile imho.

This I agree with though. Combining the remote bus format with the local bus 
width should fix the problem without having to parse remote properties.

> Have I maybe missed some parts of the problem you are trying to solve
> here?
> 
> Thank you
>    j
> 
> [1] drm: bridge: Add support for static image formats
>     https://lwn.net/Articles/752296/
> [2] include/uapi/linux/media-bus-format.h
> 
> > Anyway, this series solves some real issues for my HW.
> > 
> > Cheers,
> > Peter
> > 
> > Changes since v2   https://lkml.org/lkml/2018/4/17/385
> > - patch 2/7 fixed spelling and added an example
> > - patch 4/7 parse the DT up front and store the result indexed by encoder
> > - old patch 5/6 and 6/6 dropped
> > - patch 5-7/7 are new and makes the tda998x driver a drm_bridge
> > 
> > Changes since v1   https://lkml.org/lkml/2018/4/9/294
> > - added reviewed-by from Rob to patch 1/6
> > - patch 2/6 changed so that the bus format override is in the endpoint
> >   DT node, and follows the binding of media video-interfaces.
> > - patch 3/6 is new, it adds drm_of_media_bus_fmt which parses above
> >   media video-interface binding (partially).
> > - patch 4/6 now makes use of the above helper (and also fixes problems
> >   with the 3/5 patch from v1 when no override was specified).
> > - do not mention unrelated connector display_info details in the cover
> >   letter and commit messages.
> > 
> > [1]
> > "Bridge" series v2   https://lkml.org/lkml/2018/3/26/610
> > "Bridge" series v1   https://lkml.org/lkml/2018/3/17/221
> > 
> > Peter Rosin (7):
> >   dt-bindings: display: bridge: lvds-transmitter: add ti,ds90c185
> >   dt-bindings: display: atmel: optional video-interface of endpoints
> >   drm: of: introduce drm_of_media_bus_fmt
> >   drm/atmel-hlcdc: support bus-width (12/16/18/24) in endpoint nodes
> >   drm/i2c: tda998x: find the drm_device via the drm_connector
> >   drm/i2c: tda998x: split encoder and component functions from the work
> >   drm/i2c: tda998x: register as a drm bridge
> >  
> >  .../devicetree/bindings/display/atmel/hlcdc-dc.txt |  26 +++
> >  .../bindings/display/bridge/lvds-transmitter.txt   |   8 +-
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c     |  71 ++++++--
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h       |   2 +
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c   |  40 +++-
> >  drivers/gpu/drm/drm_of.c                           |  38 ++++
> >  drivers/gpu/drm/i2c/tda998x_drv.c                  | 201 ++++++++++++++--
> >  include/drm/drm_of.h                               |   7 +
> >  8 files changed, 342 insertions(+), 51 deletions(-)

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v3 7/7] drm/i2c: tda998x: register as a drm bridge
  2018-04-20 10:06     ` Laurent Pinchart
@ 2018-04-20 10:24       ` Russell King - ARM Linux
  -1 siblings, 0 replies; 67+ messages in thread
From: Russell King - ARM Linux @ 2018-04-20 10:24 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: dri-devel, Mark Rutland, Boris Brezillon, Alexandre Belloni,
	devicetree, David Airlie, linux-kernel, Rob Herring,
	Jacopo Mondi, Daniel Vetter, Peter Rosin, linux-arm-kernel

On Fri, Apr 20, 2018 at 01:06:49PM +0300, Laurent Pinchart wrote:
> Hi Peter,
> 
> Thank you for the patch.
> 
> On Thursday, 19 April 2018 19:27:51 EEST Peter Rosin wrote:
> > This makes this driver work with all(?) drivers that are not
> > componentized and instead expect to connect to a panel/bridge. That
> > said, the only one tested is atmel_hlcdc.
> > 
> > This hooks the relevant work function previously called by the encoder
> > and the component also to the bridge, since the encoder goes away when
> > connecting to the bridge interface of the driver and the equivalent of
> > bind/unbind of the component is handled by bridge attach/detach.
> > 
> > The lifetime requirements of a bridge and a component are slightly
> > different, which is the reason for struct tda998x_bridge.
> 
> Couldn't you move the allocation and initialization (tda998x_create) of the 
> tda998x_priv structure to probe time ? I think you wouldn't need a separate 
> structure in that case. Unless I'm mistaken there would be an added benefit of 
> separating component and bridge initialization, resulting in the encoder not 
> being initialized at all if the component isn't used. You wouldn't need to add 
> a local_encoder parameter to the tda998x_init() function.

No, I don't like that idea one bit, as I've stated in the past about the
component API.  The same (probably) goes for the bridge stuff too.

Consider the following:

Your DRM system is initialised.  You then remove a module, which results
in the DRM system being torn down.  You re-insert the module (eg, having
made a change to it).  The DRM system is then re-initialised.

At this point, what is the state of variables such as priv->is_on if
you allocate the structure at probe time?

What about all the other variables in the driver private structure - are
you sure that the driver can cope with random values from the previous
"usage" remaining there?

At the moment, this isn't a concern for the driver because we
dev_kzalloc() the structure in the bind callback.  Move that to the
probe function, and the structure is no longer re-initialised each
time, and so it retains the previous state.  The driver is not setup
to cope with that.

So, to work around that, you would need to reinitialise _everything_
in the structure that the driver requires, which IMHO is a very
open to bugs (eg, if a member is missed, or added without the
necessary re-initialisation), _especially_ when this is not a path
that will get regular testing.

If you want to do this for a subset of data, it would be much better
to separate them into independent structures (maybe one embedded into
the other) so that this problem can not occur.  That way, a subset
of the data can be memset() when bound to the rest of the DRM system
ensuring a consistent driver state and still achieve what you're
suggesting.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up

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

* [PATCH v3 7/7] drm/i2c: tda998x: register as a drm bridge
@ 2018-04-20 10:24       ` Russell King - ARM Linux
  0 siblings, 0 replies; 67+ messages in thread
From: Russell King - ARM Linux @ 2018-04-20 10:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Apr 20, 2018 at 01:06:49PM +0300, Laurent Pinchart wrote:
> Hi Peter,
> 
> Thank you for the patch.
> 
> On Thursday, 19 April 2018 19:27:51 EEST Peter Rosin wrote:
> > This makes this driver work with all(?) drivers that are not
> > componentized and instead expect to connect to a panel/bridge. That
> > said, the only one tested is atmel_hlcdc.
> > 
> > This hooks the relevant work function previously called by the encoder
> > and the component also to the bridge, since the encoder goes away when
> > connecting to the bridge interface of the driver and the equivalent of
> > bind/unbind of the component is handled by bridge attach/detach.
> > 
> > The lifetime requirements of a bridge and a component are slightly
> > different, which is the reason for struct tda998x_bridge.
> 
> Couldn't you move the allocation and initialization (tda998x_create) of the 
> tda998x_priv structure to probe time ? I think you wouldn't need a separate 
> structure in that case. Unless I'm mistaken there would be an added benefit of 
> separating component and bridge initialization, resulting in the encoder not 
> being initialized at all if the component isn't used. You wouldn't need to add 
> a local_encoder parameter to the tda998x_init() function.

No, I don't like that idea one bit, as I've stated in the past about the
component API.  The same (probably) goes for the bridge stuff too.

Consider the following:

Your DRM system is initialised.  You then remove a module, which results
in the DRM system being torn down.  You re-insert the module (eg, having
made a change to it).  The DRM system is then re-initialised.

At this point, what is the state of variables such as priv->is_on if
you allocate the structure at probe time?

What about all the other variables in the driver private structure - are
you sure that the driver can cope with random values from the previous
"usage" remaining there?

At the moment, this isn't a concern for the driver because we
dev_kzalloc() the structure in the bind callback.  Move that to the
probe function, and the structure is no longer re-initialised each
time, and so it retains the previous state.  The driver is not setup
to cope with that.

So, to work around that, you would need to reinitialise _everything_
in the structure that the driver requires, which IMHO is a very
open to bugs (eg, if a member is missed, or added without the
necessary re-initialisation), _especially_ when this is not a path
that will get regular testing.

If you want to do this for a subset of data, it would be much better
to separate them into independent structures (maybe one embedded into
the other) so that this problem can not occur.  That way, a subset
of the data can be memset() when bound to the rest of the DRM system
ensuring a consistent driver state and still achieve what you're
suggesting.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up

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

* Re: [PATCH v3 7/7] drm/i2c: tda998x: register as a drm bridge
  2018-04-19 16:27   ` Peter Rosin
  (?)
@ 2018-04-20 10:41     ` kbuild test robot
  -1 siblings, 0 replies; 67+ messages in thread
From: kbuild test robot @ 2018-04-20 10:41 UTC (permalink / raw)
  To: Peter Rosin
  Cc: kbuild-all, linux-kernel, Peter Rosin, David Airlie, Rob Herring,
	Mark Rutland, Nicolas Ferre, Alexandre Belloni, Boris Brezillon,
	Daniel Vetter, Gustavo Padovan, Sean Paul, Russell King,
	Laurent Pinchart, Jacopo Mondi, dri-devel, devicetree,
	linux-arm-kernel

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

Hi Peter,

I love your patch! Yet something to improve:

[auto build test ERROR on drm/drm-next]
[also build test ERROR on v4.17-rc1 next-20180420]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Peter-Rosin/Add-tda998x-HDMI-support-to-atmel-hlcdc/20180420-160131
base:   git://people.freedesktop.org/~airlied/linux.git drm-next
config: i386-randconfig-a0-201815 (attached as .config)
compiler: gcc-4.9 (Debian 4.9.4-2) 4.9.4
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

   drivers/gpu/drm/i2c/tda998x_drv.c: In function 'tda998x_probe':
>> drivers/gpu/drm/i2c/tda998x_drv.c:1859:16: error: 'struct drm_bridge' has no member named 'of_node'
     bridge->bridge.of_node = dev->of_node;
                   ^

vim +1859 drivers/gpu/drm/i2c/tda998x_drv.c

  1838	
  1839	static int
  1840	tda998x_probe(struct i2c_client *client, const struct i2c_device_id *id)
  1841	{
  1842		struct device *dev = &client->dev;
  1843		struct tda998x_bridge *bridge;
  1844		int ret;
  1845	
  1846		if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
  1847			dev_warn(&client->dev, "adapter does not support I2C\n");
  1848			return -EIO;
  1849		}
  1850	
  1851		bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
  1852		if (!bridge)
  1853			return -ENOMEM;
  1854	
  1855		bridge->dev = dev;
  1856		dev_set_drvdata(dev, bridge);
  1857	
  1858		bridge->bridge.funcs = &tda998x_bridge_funcs;
> 1859		bridge->bridge.of_node = dev->of_node;
  1860		drm_bridge_add(&bridge->bridge);
  1861	
  1862		ret = component_add(dev, &tda998x_ops);
  1863	
  1864		if (ret)
  1865			drm_bridge_remove(&bridge->bridge);
  1866	
  1867		return ret;
  1868	}
  1869	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

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

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

* Re: [PATCH v3 7/7] drm/i2c: tda998x: register as a drm bridge
@ 2018-04-20 10:41     ` kbuild test robot
  0 siblings, 0 replies; 67+ messages in thread
From: kbuild test robot @ 2018-04-20 10:41 UTC (permalink / raw)
  Cc: Mark Rutland, Boris Brezillon, Alexandre Belloni,
	linux-arm-kernel, Jacopo Mondi, devicetree, David Airlie,
	linux-kernel, dri-devel, Nicolas Ferre, Rob Herring, kbuild-all,
	Daniel Vetter, Peter Rosin, Russell King, Laurent Pinchart

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

Hi Peter,

I love your patch! Yet something to improve:

[auto build test ERROR on drm/drm-next]
[also build test ERROR on v4.17-rc1 next-20180420]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Peter-Rosin/Add-tda998x-HDMI-support-to-atmel-hlcdc/20180420-160131
base:   git://people.freedesktop.org/~airlied/linux.git drm-next
config: i386-randconfig-a0-201815 (attached as .config)
compiler: gcc-4.9 (Debian 4.9.4-2) 4.9.4
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

   drivers/gpu/drm/i2c/tda998x_drv.c: In function 'tda998x_probe':
>> drivers/gpu/drm/i2c/tda998x_drv.c:1859:16: error: 'struct drm_bridge' has no member named 'of_node'
     bridge->bridge.of_node = dev->of_node;
                   ^

vim +1859 drivers/gpu/drm/i2c/tda998x_drv.c

  1838	
  1839	static int
  1840	tda998x_probe(struct i2c_client *client, const struct i2c_device_id *id)
  1841	{
  1842		struct device *dev = &client->dev;
  1843		struct tda998x_bridge *bridge;
  1844		int ret;
  1845	
  1846		if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
  1847			dev_warn(&client->dev, "adapter does not support I2C\n");
  1848			return -EIO;
  1849		}
  1850	
  1851		bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
  1852		if (!bridge)
  1853			return -ENOMEM;
  1854	
  1855		bridge->dev = dev;
  1856		dev_set_drvdata(dev, bridge);
  1857	
  1858		bridge->bridge.funcs = &tda998x_bridge_funcs;
> 1859		bridge->bridge.of_node = dev->of_node;
  1860		drm_bridge_add(&bridge->bridge);
  1861	
  1862		ret = component_add(dev, &tda998x_ops);
  1863	
  1864		if (ret)
  1865			drm_bridge_remove(&bridge->bridge);
  1866	
  1867		return ret;
  1868	}
  1869	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

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

[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

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

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

* [PATCH v3 7/7] drm/i2c: tda998x: register as a drm bridge
@ 2018-04-20 10:41     ` kbuild test robot
  0 siblings, 0 replies; 67+ messages in thread
From: kbuild test robot @ 2018-04-20 10:41 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Peter,

I love your patch! Yet something to improve:

[auto build test ERROR on drm/drm-next]
[also build test ERROR on v4.17-rc1 next-20180420]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Peter-Rosin/Add-tda998x-HDMI-support-to-atmel-hlcdc/20180420-160131
base:   git://people.freedesktop.org/~airlied/linux.git drm-next
config: i386-randconfig-a0-201815 (attached as .config)
compiler: gcc-4.9 (Debian 4.9.4-2) 4.9.4
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

   drivers/gpu/drm/i2c/tda998x_drv.c: In function 'tda998x_probe':
>> drivers/gpu/drm/i2c/tda998x_drv.c:1859:16: error: 'struct drm_bridge' has no member named 'of_node'
     bridge->bridge.of_node = dev->of_node;
                   ^

vim +1859 drivers/gpu/drm/i2c/tda998x_drv.c

  1838	
  1839	static int
  1840	tda998x_probe(struct i2c_client *client, const struct i2c_device_id *id)
  1841	{
  1842		struct device *dev = &client->dev;
  1843		struct tda998x_bridge *bridge;
  1844		int ret;
  1845	
  1846		if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
  1847			dev_warn(&client->dev, "adapter does not support I2C\n");
  1848			return -EIO;
  1849		}
  1850	
  1851		bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
  1852		if (!bridge)
  1853			return -ENOMEM;
  1854	
  1855		bridge->dev = dev;
  1856		dev_set_drvdata(dev, bridge);
  1857	
  1858		bridge->bridge.funcs = &tda998x_bridge_funcs;
> 1859		bridge->bridge.of_node = dev->of_node;
  1860		drm_bridge_add(&bridge->bridge);
  1861	
  1862		ret = component_add(dev, &tda998x_ops);
  1863	
  1864		if (ret)
  1865			drm_bridge_remove(&bridge->bridge);
  1866	
  1867		return ret;
  1868	}
  1869	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 31929 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180420/2bc893dc/attachment-0001.gz>

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

* Re: [PATCH v3 7/7] drm/i2c: tda998x: register as a drm bridge
  2018-04-20 10:41     ` kbuild test robot
@ 2018-04-20 10:49       ` Peter Rosin
  -1 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-20 10:49 UTC (permalink / raw)
  To: kbuild test robot
  Cc: kbuild-all, linux-kernel, David Airlie, Rob Herring,
	Mark Rutland, Nicolas Ferre, Alexandre Belloni, Boris Brezillon,
	Daniel Vetter, Gustavo Padovan, Sean Paul, Russell King,
	Laurent Pinchart, Jacopo Mondi, dri-devel, devicetree,
	linux-arm-kernel

On 2018-04-20 12:41, kbuild test robot wrote:
> Hi Peter,
> 
> I love your patch! Yet something to improve:

Yup, right you are!

> [auto build test ERROR on drm/drm-next]
> [also build test ERROR on v4.17-rc1 next-20180420]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
> 
> url:    https://github.com/0day-ci/linux/commits/Peter-Rosin/Add-tda998x-HDMI-support-to-atmel-hlcdc/20180420-160131
> base:   git://people.freedesktop.org/~airlied/linux.git drm-next
> config: i386-randconfig-a0-201815 (attached as .config)
> compiler: gcc-4.9 (Debian 4.9.4-2) 4.9.4
> reproduce:
>         # save the attached .config to linux build tree
>         make ARCH=i386 
> 
> All errors (new ones prefixed by >>):
> 
>    drivers/gpu/drm/i2c/tda998x_drv.c: In function 'tda998x_probe':
>>> drivers/gpu/drm/i2c/tda998x_drv.c:1859:16: error: 'struct drm_bridge' has no member named 'of_node'
>      bridge->bridge.of_node = dev->of_node;
>                    ^

Anybody got a better fix than this?

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

Cheers,
Peter

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

* [PATCH v3 7/7] drm/i2c: tda998x: register as a drm bridge
@ 2018-04-20 10:49       ` Peter Rosin
  0 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-20 10:49 UTC (permalink / raw)
  To: linux-arm-kernel

On 2018-04-20 12:41, kbuild test robot wrote:
> Hi Peter,
> 
> I love your patch! Yet something to improve:

Yup, right you are!

> [auto build test ERROR on drm/drm-next]
> [also build test ERROR on v4.17-rc1 next-20180420]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
> 
> url:    https://github.com/0day-ci/linux/commits/Peter-Rosin/Add-tda998x-HDMI-support-to-atmel-hlcdc/20180420-160131
> base:   git://people.freedesktop.org/~airlied/linux.git drm-next
> config: i386-randconfig-a0-201815 (attached as .config)
> compiler: gcc-4.9 (Debian 4.9.4-2) 4.9.4
> reproduce:
>         # save the attached .config to linux build tree
>         make ARCH=i386 
> 
> All errors (new ones prefixed by >>):
> 
>    drivers/gpu/drm/i2c/tda998x_drv.c: In function 'tda998x_probe':
>>> drivers/gpu/drm/i2c/tda998x_drv.c:1859:16: error: 'struct drm_bridge' has no member named 'of_node'
>      bridge->bridge.of_node = dev->of_node;
>                    ^

Anybody got a better fix than this?

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

Cheers,
Peter

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

* Re: [PATCH v3 7/7] drm/i2c: tda998x: register as a drm bridge
  2018-04-20 10:49       ` Peter Rosin
@ 2018-04-20 10:53         ` Russell King - ARM Linux
  -1 siblings, 0 replies; 67+ messages in thread
From: Russell King - ARM Linux @ 2018-04-20 10:53 UTC (permalink / raw)
  To: Peter Rosin
  Cc: kbuild test robot, kbuild-all, linux-kernel, David Airlie,
	Rob Herring, Mark Rutland, Nicolas Ferre, Alexandre Belloni,
	Boris Brezillon, Daniel Vetter, Gustavo Padovan, Sean Paul,
	Laurent Pinchart, Jacopo Mondi, dri-devel, devicetree,
	linux-arm-kernel

On Fri, Apr 20, 2018 at 12:49:42PM +0200, Peter Rosin wrote:
> On 2018-04-20 12:41, kbuild test robot wrote:
> > Hi Peter,
> > 
> > I love your patch! Yet something to improve:
> 
> Yup, right you are!
> 
> > [auto build test ERROR on drm/drm-next]
> > [also build test ERROR on v4.17-rc1 next-20180420]
> > [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
> > 
> > url:    https://github.com/0day-ci/linux/commits/Peter-Rosin/Add-tda998x-HDMI-support-to-atmel-hlcdc/20180420-160131
> > base:   git://people.freedesktop.org/~airlied/linux.git drm-next
> > config: i386-randconfig-a0-201815 (attached as .config)
> > compiler: gcc-4.9 (Debian 4.9.4-2) 4.9.4
> > reproduce:
> >         # save the attached .config to linux build tree
> >         make ARCH=i386 
> > 
> > All errors (new ones prefixed by >>):
> > 
> >    drivers/gpu/drm/i2c/tda998x_drv.c: In function 'tda998x_probe':
> >>> drivers/gpu/drm/i2c/tda998x_drv.c:1859:16: error: 'struct drm_bridge' has no member named 'of_node'
> >      bridge->bridge.of_node = dev->of_node;
> >                    ^
> 
> Anybody got a better fix than this?
> 
> #ifdef CONFIG_OF
> 	bridge->bridge.of_node = dev->of_node;
> #endif

How about the bridge code provides a helper to do this, something like:

static inline void bridge_set_device(struct drm_bridge *bridge,
				     struct device *dev)
{
#ifdef CONFIG_OF
	bridge->of_node = dev->of_node;
#endif
}

which (a) nicely hides the firmware flavour, and (b) hides the ifdef in
the bridge header where it belongs.  If the bridge code needs to be
converted to fwnode in the future, at least this would be abstracted
from the drivers.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up

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

* [PATCH v3 7/7] drm/i2c: tda998x: register as a drm bridge
@ 2018-04-20 10:53         ` Russell King - ARM Linux
  0 siblings, 0 replies; 67+ messages in thread
From: Russell King - ARM Linux @ 2018-04-20 10:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Apr 20, 2018 at 12:49:42PM +0200, Peter Rosin wrote:
> On 2018-04-20 12:41, kbuild test robot wrote:
> > Hi Peter,
> > 
> > I love your patch! Yet something to improve:
> 
> Yup, right you are!
> 
> > [auto build test ERROR on drm/drm-next]
> > [also build test ERROR on v4.17-rc1 next-20180420]
> > [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
> > 
> > url:    https://github.com/0day-ci/linux/commits/Peter-Rosin/Add-tda998x-HDMI-support-to-atmel-hlcdc/20180420-160131
> > base:   git://people.freedesktop.org/~airlied/linux.git drm-next
> > config: i386-randconfig-a0-201815 (attached as .config)
> > compiler: gcc-4.9 (Debian 4.9.4-2) 4.9.4
> > reproduce:
> >         # save the attached .config to linux build tree
> >         make ARCH=i386 
> > 
> > All errors (new ones prefixed by >>):
> > 
> >    drivers/gpu/drm/i2c/tda998x_drv.c: In function 'tda998x_probe':
> >>> drivers/gpu/drm/i2c/tda998x_drv.c:1859:16: error: 'struct drm_bridge' has no member named 'of_node'
> >      bridge->bridge.of_node = dev->of_node;
> >                    ^
> 
> Anybody got a better fix than this?
> 
> #ifdef CONFIG_OF
> 	bridge->bridge.of_node = dev->of_node;
> #endif

How about the bridge code provides a helper to do this, something like:

static inline void bridge_set_device(struct drm_bridge *bridge,
				     struct device *dev)
{
#ifdef CONFIG_OF
	bridge->of_node = dev->of_node;
#endif
}

which (a) nicely hides the firmware flavour, and (b) hides the ifdef in
the bridge header where it belongs.  If the bridge code needs to be
converted to fwnode in the future, at least this would be abstracted
from the drivers.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up

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

* Re: [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
  2018-04-20 10:18     ` Laurent Pinchart
@ 2018-04-20 11:05       ` Peter Rosin
  -1 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-20 11:05 UTC (permalink / raw)
  To: Laurent Pinchart, jacopo mondi
  Cc: linux-kernel, David Airlie, Rob Herring, Mark Rutland,
	Nicolas Ferre, Alexandre Belloni, Boris Brezillon, Daniel Vetter,
	Gustavo Padovan, Sean Paul, Russell King, Jacopo Mondi,
	dri-devel, devicetree, linux-arm-kernel

On 2018-04-20 12:18, Laurent Pinchart wrote:
> Hello,
> 
> On Friday, 20 April 2018 11:52:35 EEST jacopo mondi wrote:
>> Hi Peter,
>>     I've been a bit a pain in the arse for you recently, but please
>> bear with me a bit more, and sorry for jumping late on the band wagon.
>>
>> On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
>>> Hi!
>>>
>>> I naively thought that since there was support for both nxp,tda19988 (in
>>> the tda998x driver) and the atmel-hlcdc, things would be a smooth ride.
>>> But it wasn't, so I started looking around and realized I had to fix
>>> things.
>>>
>>> In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
>>> component, but now in v3 I fix things by making the tda998x driver
>>> a bridge instead. This was after a suggestion from Boris Brezillion

That should be Brezillon, sorry for being sloppy with the spelling.

>>> (the atmel-hlcdc maintainer), so there was some risk of bias ... but
>>> after comparing what was needed, I too find the bridge approach better.
>>>
>>> In addition to the above, our PCB interface between the SAMA5D3 and the
>>> HDMI encoder is only using 16 bits, and this has to be described
>>> somewhere, or the atmel-hlcdc driver have no chance of selecting the
>>> correct output mode. Since I have similar problems with a ds90c185 lvds
>>> encoder I added patches to override the atmel-hlcdc output format via
>>> DT properties compatible with the media video-interface binding and
>>> things start to play together.
>>>
>>> Since this series superseeds the bridge series [1], I have included the
>>> leftover bindings patch for the ti,ds90c185 here.
>>
>> I feel like this series would look better if it would make use of the
>> proposed bridge media bus format support I have recently sent out [1]
>> (and which was not there when you first sent v1).
>>
>> I understand your fundamental problem here is that the bus format
>> that should be reported by your bridge is different from the ones
>> actually supported by the TDA19988 chip, as the wirings ground some
>> of the input pins.
>>
>> Although this is defintely something that could be described in the
>> bridge's own OF node with the 'bus_width' property, and what I would do,
>> now that you have made a bridge out from the tda19988 driver, is:
>>
>> 1) Set the bridge accepted input bus_format parsing its pin
>> configuration, or default it if that's not implemented yet.
>> This will likely be rgb888. You can do that using the trivial
>> support for bridge input image formats implemented by my series.
>> 2) Specify in the bridge endpoint a 'bus_width' of <16>
>> 3) In your atmel-hlcd get both the image format of the bridge (rgb888)
>> and parse the remote endpoint property 'bus_width' and get the <16>
>> value back.
> 
> Parsing properties of remote nodes should be avoided as much as possible, as 
> they need to be interpreted in the context of the DT bindings related to the 
> compatible string applicable to that node. I'd rather have the bus_width 
> property in the local endpoint node.

In addition to that, my view of this binding

	endpoint {
		bus-type = <0>;
		bus-widht = <16>;
	};

is that it always means rgb565. See further below.

>> 4) Set the correct format in the atmel hlcd driver to accommodate a
>> bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
>> or are there other possible combinations I am missing?)
>>
>> I would consider this better mostly because in this series you are
>> creating a semantic for the whole DRM subsystem on the 'bus_width'
>> property, where numerical values as '12', '16' etc are arbitrary tied
>> to the selection of a media bus format. At least you should use a
>> common set of defines [1] between the device tree and the driver,
>> but this looks anyway fragile imho.
> 
> This I agree with though. Combining the remote bus format with the local bus 
> width should fix the problem without having to parse remote properties.

My thinking was that the binding with bus-type = <0> and bus-width = <bpp>
would mean a parallel bus (type 0 means auto-detect and with a bus-width that
auto-detect means a parallel bus) and the most natural/common interpretation
of that bus-width. For bus widths of 12, 16, 18, 24, 30 etc I think that
would be rgb444, rgb565, rgb666, rgb888, rgb101010 (or, I'm first so I get
to define the default). If you have some other interpretation of a bus with
that width, you'd need to extend the video-interface binding with some way
of saying what you need, perhaps using some kind of data mapping or something
to say e.g. bgr666. And you'd need some kind of indicator if you have YUV
signals instead of RGB, and LVDS isn't a completely parallel bus, so you'd
need something for that. Etc.

Because the word from Rob was that there should be one common binding that
describes video interfaces. I started an implementation that interprets that
binding in a drm context in
[PATCH 3/7] drm: of: introduce drm_of_media_bus_fmt

With that view, any input format specification of the bridge is not helpful
for me since what the bridge specifies (without help) is going to be wrong
anyway. End result, I need to specify the format manually on either the
bridge or the atmel-hlcdc side, and I happen to think that the correct side
is with the atmel-hlcdc, because that is where my issue originates. In short,
the "drm: bridge: Add support for static image formats" series is unrelated
as far as I can tell.

Cheers,
Peter

>> Have I maybe missed some parts of the problem you are trying to solve
>> here?
>>
>> Thank you
>>    j

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

* [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
@ 2018-04-20 11:05       ` Peter Rosin
  0 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-20 11:05 UTC (permalink / raw)
  To: linux-arm-kernel

On 2018-04-20 12:18, Laurent Pinchart wrote:
> Hello,
> 
> On Friday, 20 April 2018 11:52:35 EEST jacopo mondi wrote:
>> Hi Peter,
>>     I've been a bit a pain in the arse for you recently, but please
>> bear with me a bit more, and sorry for jumping late on the band wagon.
>>
>> On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
>>> Hi!
>>>
>>> I naively thought that since there was support for both nxp,tda19988 (in
>>> the tda998x driver) and the atmel-hlcdc, things would be a smooth ride.
>>> But it wasn't, so I started looking around and realized I had to fix
>>> things.
>>>
>>> In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
>>> component, but now in v3 I fix things by making the tda998x driver
>>> a bridge instead. This was after a suggestion from Boris Brezillion

That should be Brezillon, sorry for being sloppy with the spelling.

>>> (the atmel-hlcdc maintainer), so there was some risk of bias ... but
>>> after comparing what was needed, I too find the bridge approach better.
>>>
>>> In addition to the above, our PCB interface between the SAMA5D3 and the
>>> HDMI encoder is only using 16 bits, and this has to be described
>>> somewhere, or the atmel-hlcdc driver have no chance of selecting the
>>> correct output mode. Since I have similar problems with a ds90c185 lvds
>>> encoder I added patches to override the atmel-hlcdc output format via
>>> DT properties compatible with the media video-interface binding and
>>> things start to play together.
>>>
>>> Since this series superseeds the bridge series [1], I have included the
>>> leftover bindings patch for the ti,ds90c185 here.
>>
>> I feel like this series would look better if it would make use of the
>> proposed bridge media bus format support I have recently sent out [1]
>> (and which was not there when you first sent v1).
>>
>> I understand your fundamental problem here is that the bus format
>> that should be reported by your bridge is different from the ones
>> actually supported by the TDA19988 chip, as the wirings ground some
>> of the input pins.
>>
>> Although this is defintely something that could be described in the
>> bridge's own OF node with the 'bus_width' property, and what I would do,
>> now that you have made a bridge out from the tda19988 driver, is:
>>
>> 1) Set the bridge accepted input bus_format parsing its pin
>> configuration, or default it if that's not implemented yet.
>> This will likely be rgb888. You can do that using the trivial
>> support for bridge input image formats implemented by my series.
>> 2) Specify in the bridge endpoint a 'bus_width' of <16>
>> 3) In your atmel-hlcd get both the image format of the bridge (rgb888)
>> and parse the remote endpoint property 'bus_width' and get the <16>
>> value back.
> 
> Parsing properties of remote nodes should be avoided as much as possible, as 
> they need to be interpreted in the context of the DT bindings related to the 
> compatible string applicable to that node. I'd rather have the bus_width 
> property in the local endpoint node.

In addition to that, my view of this binding

	endpoint {
		bus-type = <0>;
		bus-widht = <16>;
	};

is that it always means rgb565. See further below.

>> 4) Set the correct format in the atmel hlcd driver to accommodate a
>> bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
>> or are there other possible combinations I am missing?)
>>
>> I would consider this better mostly because in this series you are
>> creating a semantic for the whole DRM subsystem on the 'bus_width'
>> property, where numerical values as '12', '16' etc are arbitrary tied
>> to the selection of a media bus format. At least you should use a
>> common set of defines [1] between the device tree and the driver,
>> but this looks anyway fragile imho.
> 
> This I agree with though. Combining the remote bus format with the local bus 
> width should fix the problem without having to parse remote properties.

My thinking was that the binding with bus-type = <0> and bus-width = <bpp>
would mean a parallel bus (type 0 means auto-detect and with a bus-width that
auto-detect means a parallel bus) and the most natural/common interpretation
of that bus-width. For bus widths of 12, 16, 18, 24, 30 etc I think that
would be rgb444, rgb565, rgb666, rgb888, rgb101010 (or, I'm first so I get
to define the default). If you have some other interpretation of a bus with
that width, you'd need to extend the video-interface binding with some way
of saying what you need, perhaps using some kind of data mapping or something
to say e.g. bgr666. And you'd need some kind of indicator if you have YUV
signals instead of RGB, and LVDS isn't a completely parallel bus, so you'd
need something for that. Etc.

Because the word from Rob was that there should be one common binding that
describes video interfaces. I started an implementation that interprets that
binding in a drm context in
[PATCH 3/7] drm: of: introduce drm_of_media_bus_fmt

With that view, any input format specification of the bridge is not helpful
for me since what the bridge specifies (without help) is going to be wrong
anyway. End result, I need to specify the format manually on either the
bridge or the atmel-hlcdc side, and I happen to think that the correct side
is with the atmel-hlcdc, because that is where my issue originates. In short,
the "drm: bridge: Add support for static image formats" series is unrelated
as far as I can tell.

Cheers,
Peter

>> Have I maybe missed some parts of the problem you are trying to solve
>> here?
>>
>> Thank you
>>    j

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

* Re: [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
  2018-04-20 10:18     ` Laurent Pinchart
  (?)
@ 2018-04-20 11:22       ` jacopo mondi
  -1 siblings, 0 replies; 67+ messages in thread
From: jacopo mondi @ 2018-04-20 11:22 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Peter Rosin, linux-kernel, David Airlie, Rob Herring,
	Mark Rutland, Nicolas Ferre, Alexandre Belloni, Boris Brezillon,
	Daniel Vetter, Gustavo Padovan, Sean Paul, Russell King,
	Jacopo Mondi, dri-devel, devicetree, linux-arm-kernel

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

Hi Laurent,

On Fri, Apr 20, 2018 at 01:18:13PM +0300, Laurent Pinchart wrote:
> Hello,
>
> On Friday, 20 April 2018 11:52:35 EEST jacopo mondi wrote:
> > Hi Peter,
> >     I've been a bit a pain in the arse for you recently, but please
> > bear with me a bit more, and sorry for jumping late on the band wagon.
> >
> > On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
> > > Hi!
> > >
> > > I naively thought that since there was support for both nxp,tda19988 (in
> > > the tda998x driver) and the atmel-hlcdc, things would be a smooth ride.
> > > But it wasn't, so I started looking around and realized I had to fix
> > > things.
> > >
> > > In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
> > > component, but now in v3 I fix things by making the tda998x driver
> > > a bridge instead. This was after a suggestion from Boris Brezillion
> > > (the atmel-hlcdc maintainer), so there was some risk of bias ... but
> > > after comparing what was needed, I too find the bridge approach better.
> > >
> > > In addition to the above, our PCB interface between the SAMA5D3 and the
> > > HDMI encoder is only using 16 bits, and this has to be described
> > > somewhere, or the atmel-hlcdc driver have no chance of selecting the
> > > correct output mode. Since I have similar problems with a ds90c185 lvds
> > > encoder I added patches to override the atmel-hlcdc output format via
> > > DT properties compatible with the media video-interface binding and
> > > things start to play together.
> > >
> > > Since this series superseeds the bridge series [1], I have included the
> > > leftover bindings patch for the ti,ds90c185 here.
> >
> > I feel like this series would look better if it would make use of the
> > proposed bridge media bus format support I have recently sent out [1]
> > (and which was not there when you first sent v1).
> >
> > I understand your fundamental problem here is that the bus format
> > that should be reported by your bridge is different from the ones
> > actually supported by the TDA19988 chip, as the wirings ground some
> > of the input pins.
> >
> > Although this is defintely something that could be described in the
> > bridge's own OF node with the 'bus_width' property, and what I would do,
> > now that you have made a bridge out from the tda19988 driver, is:
> >
> > 1) Set the bridge accepted input bus_format parsing its pin
> > configuration, or default it if that's not implemented yet.
> > This will likely be rgb888. You can do that using the trivial
> > support for bridge input image formats implemented by my series.
> > 2) Specify in the bridge endpoint a 'bus_width' of <16>
> > 3) In your atmel-hlcd get both the image format of the bridge (rgb888)
> > and parse the remote endpoint property 'bus_width' and get the <16>
> > value back.
>
> Parsing properties of remote nodes should be avoided as much as possible, as
> they need to be interpreted in the context of the DT bindings related to the
> compatible string applicable to that node. I'd rather have the bus_width
> property in the local endpoint node.

Right, I see...
Well, in Peter's case, the bus width, being a consequence of
wirings, can be described safely in both endpoints, right?

>
> > 4) Set the correct format in the atmel hlcd driver to accommodate a
> > bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
> > or are there other possible combinations I am missing?)
> >
> > I would consider this better mostly because in this series you are
> > creating a semantic for the whole DRM subsystem on the 'bus_width'
> > property, where numerical values as '12', '16' etc are arbitrary tied
> > to the selection of a media bus format. At least you should use a
> > common set of defines [1] between the device tree and the driver,
> > but this looks anyway fragile imho.
>
> This I agree with though. Combining the remote bus format with the local bus
> width should fix the problem without having to parse remote properties.
>
> > Have I maybe missed some parts of the problem you are trying to solve
> > here?
> >
> > Thank you
> >    j
> >
> > [1] drm: bridge: Add support for static image formats
> >     https://lwn.net/Articles/752296/
> > [2] include/uapi/linux/media-bus-format.h
> >
> > > Anyway, this series solves some real issues for my HW.
> > >
> > > Cheers,
> > > Peter
> > >
> > > Changes since v2   https://lkml.org/lkml/2018/4/17/385
> > > - patch 2/7 fixed spelling and added an example
> > > - patch 4/7 parse the DT up front and store the result indexed by encoder
> > > - old patch 5/6 and 6/6 dropped
> > > - patch 5-7/7 are new and makes the tda998x driver a drm_bridge
> > >
> > > Changes since v1   https://lkml.org/lkml/2018/4/9/294
> > > - added reviewed-by from Rob to patch 1/6
> > > - patch 2/6 changed so that the bus format override is in the endpoint
> > >   DT node, and follows the binding of media video-interfaces.
> > > - patch 3/6 is new, it adds drm_of_media_bus_fmt which parses above
> > >   media video-interface binding (partially).
> > > - patch 4/6 now makes use of the above helper (and also fixes problems
> > >   with the 3/5 patch from v1 when no override was specified).
> > > - do not mention unrelated connector display_info details in the cover
> > >   letter and commit messages.
> > >
> > > [1]
> > > "Bridge" series v2   https://lkml.org/lkml/2018/3/26/610
> > > "Bridge" series v1   https://lkml.org/lkml/2018/3/17/221
> > >
> > > Peter Rosin (7):
> > >   dt-bindings: display: bridge: lvds-transmitter: add ti,ds90c185
> > >   dt-bindings: display: atmel: optional video-interface of endpoints
> > >   drm: of: introduce drm_of_media_bus_fmt
> > >   drm/atmel-hlcdc: support bus-width (12/16/18/24) in endpoint nodes
> > >   drm/i2c: tda998x: find the drm_device via the drm_connector
> > >   drm/i2c: tda998x: split encoder and component functions from the work
> > >   drm/i2c: tda998x: register as a drm bridge
> > >
> > >  .../devicetree/bindings/display/atmel/hlcdc-dc.txt |  26 +++
> > >  .../bindings/display/bridge/lvds-transmitter.txt   |   8 +-
> > >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c     |  71 ++++++--
> > >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h       |   2 +
> > >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c   |  40 +++-
> > >  drivers/gpu/drm/drm_of.c                           |  38 ++++
> > >  drivers/gpu/drm/i2c/tda998x_drv.c                  | 201 ++++++++++++++--
> > >  include/drm/drm_of.h                               |   7 +
> > >  8 files changed, 342 insertions(+), 51 deletions(-)
>
> --
> Regards,
>
> Laurent Pinchart
>
>
>

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

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

* Re: [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
@ 2018-04-20 11:22       ` jacopo mondi
  0 siblings, 0 replies; 67+ messages in thread
From: jacopo mondi @ 2018-04-20 11:22 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Mark Rutland, Boris Brezillon, Alexandre Belloni, devicetree,
	David Airlie, Nicolas Ferre, dri-devel, linux-kernel,
	Rob Herring, Jacopo Mondi, Daniel Vetter, Peter Rosin,
	Russell King, linux-arm-kernel


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

Hi Laurent,

On Fri, Apr 20, 2018 at 01:18:13PM +0300, Laurent Pinchart wrote:
> Hello,
>
> On Friday, 20 April 2018 11:52:35 EEST jacopo mondi wrote:
> > Hi Peter,
> >     I've been a bit a pain in the arse for you recently, but please
> > bear with me a bit more, and sorry for jumping late on the band wagon.
> >
> > On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
> > > Hi!
> > >
> > > I naively thought that since there was support for both nxp,tda19988 (in
> > > the tda998x driver) and the atmel-hlcdc, things would be a smooth ride.
> > > But it wasn't, so I started looking around and realized I had to fix
> > > things.
> > >
> > > In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
> > > component, but now in v3 I fix things by making the tda998x driver
> > > a bridge instead. This was after a suggestion from Boris Brezillion
> > > (the atmel-hlcdc maintainer), so there was some risk of bias ... but
> > > after comparing what was needed, I too find the bridge approach better.
> > >
> > > In addition to the above, our PCB interface between the SAMA5D3 and the
> > > HDMI encoder is only using 16 bits, and this has to be described
> > > somewhere, or the atmel-hlcdc driver have no chance of selecting the
> > > correct output mode. Since I have similar problems with a ds90c185 lvds
> > > encoder I added patches to override the atmel-hlcdc output format via
> > > DT properties compatible with the media video-interface binding and
> > > things start to play together.
> > >
> > > Since this series superseeds the bridge series [1], I have included the
> > > leftover bindings patch for the ti,ds90c185 here.
> >
> > I feel like this series would look better if it would make use of the
> > proposed bridge media bus format support I have recently sent out [1]
> > (and which was not there when you first sent v1).
> >
> > I understand your fundamental problem here is that the bus format
> > that should be reported by your bridge is different from the ones
> > actually supported by the TDA19988 chip, as the wirings ground some
> > of the input pins.
> >
> > Although this is defintely something that could be described in the
> > bridge's own OF node with the 'bus_width' property, and what I would do,
> > now that you have made a bridge out from the tda19988 driver, is:
> >
> > 1) Set the bridge accepted input bus_format parsing its pin
> > configuration, or default it if that's not implemented yet.
> > This will likely be rgb888. You can do that using the trivial
> > support for bridge input image formats implemented by my series.
> > 2) Specify in the bridge endpoint a 'bus_width' of <16>
> > 3) In your atmel-hlcd get both the image format of the bridge (rgb888)
> > and parse the remote endpoint property 'bus_width' and get the <16>
> > value back.
>
> Parsing properties of remote nodes should be avoided as much as possible, as
> they need to be interpreted in the context of the DT bindings related to the
> compatible string applicable to that node. I'd rather have the bus_width
> property in the local endpoint node.

Right, I see...
Well, in Peter's case, the bus width, being a consequence of
wirings, can be described safely in both endpoints, right?

>
> > 4) Set the correct format in the atmel hlcd driver to accommodate a
> > bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
> > or are there other possible combinations I am missing?)
> >
> > I would consider this better mostly because in this series you are
> > creating a semantic for the whole DRM subsystem on the 'bus_width'
> > property, where numerical values as '12', '16' etc are arbitrary tied
> > to the selection of a media bus format. At least you should use a
> > common set of defines [1] between the device tree and the driver,
> > but this looks anyway fragile imho.
>
> This I agree with though. Combining the remote bus format with the local bus
> width should fix the problem without having to parse remote properties.
>
> > Have I maybe missed some parts of the problem you are trying to solve
> > here?
> >
> > Thank you
> >    j
> >
> > [1] drm: bridge: Add support for static image formats
> >     https://lwn.net/Articles/752296/
> > [2] include/uapi/linux/media-bus-format.h
> >
> > > Anyway, this series solves some real issues for my HW.
> > >
> > > Cheers,
> > > Peter
> > >
> > > Changes since v2   https://lkml.org/lkml/2018/4/17/385
> > > - patch 2/7 fixed spelling and added an example
> > > - patch 4/7 parse the DT up front and store the result indexed by encoder
> > > - old patch 5/6 and 6/6 dropped
> > > - patch 5-7/7 are new and makes the tda998x driver a drm_bridge
> > >
> > > Changes since v1   https://lkml.org/lkml/2018/4/9/294
> > > - added reviewed-by from Rob to patch 1/6
> > > - patch 2/6 changed so that the bus format override is in the endpoint
> > >   DT node, and follows the binding of media video-interfaces.
> > > - patch 3/6 is new, it adds drm_of_media_bus_fmt which parses above
> > >   media video-interface binding (partially).
> > > - patch 4/6 now makes use of the above helper (and also fixes problems
> > >   with the 3/5 patch from v1 when no override was specified).
> > > - do not mention unrelated connector display_info details in the cover
> > >   letter and commit messages.
> > >
> > > [1]
> > > "Bridge" series v2   https://lkml.org/lkml/2018/3/26/610
> > > "Bridge" series v1   https://lkml.org/lkml/2018/3/17/221
> > >
> > > Peter Rosin (7):
> > >   dt-bindings: display: bridge: lvds-transmitter: add ti,ds90c185
> > >   dt-bindings: display: atmel: optional video-interface of endpoints
> > >   drm: of: introduce drm_of_media_bus_fmt
> > >   drm/atmel-hlcdc: support bus-width (12/16/18/24) in endpoint nodes
> > >   drm/i2c: tda998x: find the drm_device via the drm_connector
> > >   drm/i2c: tda998x: split encoder and component functions from the work
> > >   drm/i2c: tda998x: register as a drm bridge
> > >
> > >  .../devicetree/bindings/display/atmel/hlcdc-dc.txt |  26 +++
> > >  .../bindings/display/bridge/lvds-transmitter.txt   |   8 +-
> > >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c     |  71 ++++++--
> > >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h       |   2 +
> > >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c   |  40 +++-
> > >  drivers/gpu/drm/drm_of.c                           |  38 ++++
> > >  drivers/gpu/drm/i2c/tda998x_drv.c                  | 201 ++++++++++++++--
> > >  include/drm/drm_of.h                               |   7 +
> > >  8 files changed, 342 insertions(+), 51 deletions(-)
>
> --
> Regards,
>
> Laurent Pinchart
>
>
>

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

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

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

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

* [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
@ 2018-04-20 11:22       ` jacopo mondi
  0 siblings, 0 replies; 67+ messages in thread
From: jacopo mondi @ 2018-04-20 11:22 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Laurent,

On Fri, Apr 20, 2018 at 01:18:13PM +0300, Laurent Pinchart wrote:
> Hello,
>
> On Friday, 20 April 2018 11:52:35 EEST jacopo mondi wrote:
> > Hi Peter,
> >     I've been a bit a pain in the arse for you recently, but please
> > bear with me a bit more, and sorry for jumping late on the band wagon.
> >
> > On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
> > > Hi!
> > >
> > > I naively thought that since there was support for both nxp,tda19988 (in
> > > the tda998x driver) and the atmel-hlcdc, things would be a smooth ride.
> > > But it wasn't, so I started looking around and realized I had to fix
> > > things.
> > >
> > > In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
> > > component, but now in v3 I fix things by making the tda998x driver
> > > a bridge instead. This was after a suggestion from Boris Brezillion
> > > (the atmel-hlcdc maintainer), so there was some risk of bias ... but
> > > after comparing what was needed, I too find the bridge approach better.
> > >
> > > In addition to the above, our PCB interface between the SAMA5D3 and the
> > > HDMI encoder is only using 16 bits, and this has to be described
> > > somewhere, or the atmel-hlcdc driver have no chance of selecting the
> > > correct output mode. Since I have similar problems with a ds90c185 lvds
> > > encoder I added patches to override the atmel-hlcdc output format via
> > > DT properties compatible with the media video-interface binding and
> > > things start to play together.
> > >
> > > Since this series superseeds the bridge series [1], I have included the
> > > leftover bindings patch for the ti,ds90c185 here.
> >
> > I feel like this series would look better if it would make use of the
> > proposed bridge media bus format support I have recently sent out [1]
> > (and which was not there when you first sent v1).
> >
> > I understand your fundamental problem here is that the bus format
> > that should be reported by your bridge is different from the ones
> > actually supported by the TDA19988 chip, as the wirings ground some
> > of the input pins.
> >
> > Although this is defintely something that could be described in the
> > bridge's own OF node with the 'bus_width' property, and what I would do,
> > now that you have made a bridge out from the tda19988 driver, is:
> >
> > 1) Set the bridge accepted input bus_format parsing its pin
> > configuration, or default it if that's not implemented yet.
> > This will likely be rgb888. You can do that using the trivial
> > support for bridge input image formats implemented by my series.
> > 2) Specify in the bridge endpoint a 'bus_width' of <16>
> > 3) In your atmel-hlcd get both the image format of the bridge (rgb888)
> > and parse the remote endpoint property 'bus_width' and get the <16>
> > value back.
>
> Parsing properties of remote nodes should be avoided as much as possible, as
> they need to be interpreted in the context of the DT bindings related to the
> compatible string applicable to that node. I'd rather have the bus_width
> property in the local endpoint node.

Right, I see...
Well, in Peter's case, the bus width, being a consequence of
wirings, can be described safely in both endpoints, right?

>
> > 4) Set the correct format in the atmel hlcd driver to accommodate a
> > bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
> > or are there other possible combinations I am missing?)
> >
> > I would consider this better mostly because in this series you are
> > creating a semantic for the whole DRM subsystem on the 'bus_width'
> > property, where numerical values as '12', '16' etc are arbitrary tied
> > to the selection of a media bus format. At least you should use a
> > common set of defines [1] between the device tree and the driver,
> > but this looks anyway fragile imho.
>
> This I agree with though. Combining the remote bus format with the local bus
> width should fix the problem without having to parse remote properties.
>
> > Have I maybe missed some parts of the problem you are trying to solve
> > here?
> >
> > Thank you
> >    j
> >
> > [1] drm: bridge: Add support for static image formats
> >     https://lwn.net/Articles/752296/
> > [2] include/uapi/linux/media-bus-format.h
> >
> > > Anyway, this series solves some real issues for my HW.
> > >
> > > Cheers,
> > > Peter
> > >
> > > Changes since v2   https://lkml.org/lkml/2018/4/17/385
> > > - patch 2/7 fixed spelling and added an example
> > > - patch 4/7 parse the DT up front and store the result indexed by encoder
> > > - old patch 5/6 and 6/6 dropped
> > > - patch 5-7/7 are new and makes the tda998x driver a drm_bridge
> > >
> > > Changes since v1   https://lkml.org/lkml/2018/4/9/294
> > > - added reviewed-by from Rob to patch 1/6
> > > - patch 2/6 changed so that the bus format override is in the endpoint
> > >   DT node, and follows the binding of media video-interfaces.
> > > - patch 3/6 is new, it adds drm_of_media_bus_fmt which parses above
> > >   media video-interface binding (partially).
> > > - patch 4/6 now makes use of the above helper (and also fixes problems
> > >   with the 3/5 patch from v1 when no override was specified).
> > > - do not mention unrelated connector display_info details in the cover
> > >   letter and commit messages.
> > >
> > > [1]
> > > "Bridge" series v2   https://lkml.org/lkml/2018/3/26/610
> > > "Bridge" series v1   https://lkml.org/lkml/2018/3/17/221
> > >
> > > Peter Rosin (7):
> > >   dt-bindings: display: bridge: lvds-transmitter: add ti,ds90c185
> > >   dt-bindings: display: atmel: optional video-interface of endpoints
> > >   drm: of: introduce drm_of_media_bus_fmt
> > >   drm/atmel-hlcdc: support bus-width (12/16/18/24) in endpoint nodes
> > >   drm/i2c: tda998x: find the drm_device via the drm_connector
> > >   drm/i2c: tda998x: split encoder and component functions from the work
> > >   drm/i2c: tda998x: register as a drm bridge
> > >
> > >  .../devicetree/bindings/display/atmel/hlcdc-dc.txt |  26 +++
> > >  .../bindings/display/bridge/lvds-transmitter.txt   |   8 +-
> > >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c     |  71 ++++++--
> > >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h       |   2 +
> > >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c   |  40 +++-
> > >  drivers/gpu/drm/drm_of.c                           |  38 ++++
> > >  drivers/gpu/drm/i2c/tda998x_drv.c                  | 201 ++++++++++++++--
> > >  include/drm/drm_of.h                               |   7 +
> > >  8 files changed, 342 insertions(+), 51 deletions(-)
>
> --
> Regards,
>
> Laurent Pinchart
>
>
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180420/d7a1c20c/attachment-0001.sig>

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

* Re: [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
  2018-04-20 11:05       ` Peter Rosin
  (?)
@ 2018-04-20 11:38         ` jacopo mondi
  -1 siblings, 0 replies; 67+ messages in thread
From: jacopo mondi @ 2018-04-20 11:38 UTC (permalink / raw)
  To: Peter Rosin
  Cc: Laurent Pinchart, linux-kernel, David Airlie, Rob Herring,
	Mark Rutland, Nicolas Ferre, Alexandre Belloni, Boris Brezillon,
	Daniel Vetter, Gustavo Padovan, Sean Paul, Russell King,
	Jacopo Mondi, dri-devel, devicetree, linux-arm-kernel

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

Hi Peter,

On Fri, Apr 20, 2018 at 01:05:21PM +0200, Peter Rosin wrote:
> On 2018-04-20 12:18, Laurent Pinchart wrote:
> > Hello,
> >
> > On Friday, 20 April 2018 11:52:35 EEST jacopo mondi wrote:
> >> Hi Peter,
> >>     I've been a bit a pain in the arse for you recently, but please
> >> bear with me a bit more, and sorry for jumping late on the band wagon.
> >>
> >> On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
> >>> Hi!
> >>>
> >>> I naively thought that since there was support for both nxp,tda19988 (in
> >>> the tda998x driver) and the atmel-hlcdc, things would be a smooth ride.
> >>> But it wasn't, so I started looking around and realized I had to fix
> >>> things.
> >>>
> >>> In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
> >>> component, but now in v3 I fix things by making the tda998x driver
> >>> a bridge instead. This was after a suggestion from Boris Brezillion
>
> That should be Brezillon, sorry for being sloppy with the spelling.
>
> >>> (the atmel-hlcdc maintainer), so there was some risk of bias ... but
> >>> after comparing what was needed, I too find the bridge approach better.
> >>>
> >>> In addition to the above, our PCB interface between the SAMA5D3 and the
> >>> HDMI encoder is only using 16 bits, and this has to be described
> >>> somewhere, or the atmel-hlcdc driver have no chance of selecting the
> >>> correct output mode. Since I have similar problems with a ds90c185 lvds
> >>> encoder I added patches to override the atmel-hlcdc output format via
> >>> DT properties compatible with the media video-interface binding and
> >>> things start to play together.
> >>>
> >>> Since this series superseeds the bridge series [1], I have included the
> >>> leftover bindings patch for the ti,ds90c185 here.
> >>
> >> I feel like this series would look better if it would make use of the
> >> proposed bridge media bus format support I have recently sent out [1]
> >> (and which was not there when you first sent v1).
> >>
> >> I understand your fundamental problem here is that the bus format
> >> that should be reported by your bridge is different from the ones
> >> actually supported by the TDA19988 chip, as the wirings ground some
> >> of the input pins.
> >>
> >> Although this is defintely something that could be described in the
> >> bridge's own OF node with the 'bus_width' property, and what I would do,
> >> now that you have made a bridge out from the tda19988 driver, is:
> >>
> >> 1) Set the bridge accepted input bus_format parsing its pin
> >> configuration, or default it if that's not implemented yet.
> >> This will likely be rgb888. You can do that using the trivial
> >> support for bridge input image formats implemented by my series.
> >> 2) Specify in the bridge endpoint a 'bus_width' of <16>
> >> 3) In your atmel-hlcd get both the image format of the bridge (rgb888)
> >> and parse the remote endpoint property 'bus_width' and get the <16>
> >> value back.
> >
> > Parsing properties of remote nodes should be avoided as much as possible, as
> > they need to be interpreted in the context of the DT bindings related to the
> > compatible string applicable to that node. I'd rather have the bus_width
> > property in the local endpoint node.
>
> In addition to that, my view of this binding
>
> 	endpoint {
> 		bus-type = <0>;

bus-type is used by v4l2_fwnode helpers to decide which type of bus
they're dealing with iirc. Here it seems to me it has no added
value, also because in your bindings description "it shall be 0" and
it is not parsed anywhere in you code, but no big deal....

> 		bus-widht = <16>;
> 	};
>
> is that it always means rgb565. See further below.
>
> >> 4) Set the correct format in the atmel hlcd driver to accommodate a
> >> bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
> >> or are there other possible combinations I am missing?)
> >>
> >> I would consider this better mostly because in this series you are
> >> creating a semantic for the whole DRM subsystem on the 'bus_width'
> >> property, where numerical values as '12', '16' etc are arbitrary tied
> >> to the selection of a media bus format. At least you should use a
> >> common set of defines [1] between the device tree and the driver,
> >> but this looks anyway fragile imho.
> >
> > This I agree with though. Combining the remote bus format with the local bus
> > width should fix the problem without having to parse remote properties.
>
> My thinking was that the binding with bus-type = <0> and bus-width = <bpp>
> would mean a parallel bus (type 0 means auto-detect and with a bus-width that
> auto-detect means a parallel bus) and the most natural/common interpretation
> of that bus-width. For bus widths of 12, 16, 18, 24, 30 etc I think that
> would be rgb444, rgb565, rgb666, rgb888, rgb101010 (or, I'm first so I get
> to define the default). If you have some other interpretation of a bus with
> that width, you'd need to extend the video-interface binding with some way
> of saying what you need, perhaps using some kind of data mapping or something
> to say e.g. bgr666. And you'd need some kind of indicator if you have YUV
> signals instead of RGB, and LVDS isn't a completely parallel bus, so you'd
> need something for that. Etc.

The fundamental issue here is that you're tying the bus with to an
image format. Why <16> can't be, say, MEDIA_BUS_FMT_YVYU8_1X16? it
spans to 16 bits, doesn't it? And I'm sorry but the 'I'm first so I
get to define defaults' argument doesn't apply here.

So, it is my opinion you need to expose an image format somewhere. And
it is my opinion again, which can be very wrong ofc, that this place
is the bridge driver.

You need to adjust the output to accommodate wirings? You can use the
bus_width on the hlcd side, as Laurent suggested, but the bus width
does not tie to any image format at all, even more if you're making
that decision in a drm-wide function.

>
> Because the word from Rob was that there should be one common binding that
> describes video interfaces. I started an implementation that interprets that
> binding in a drm context in
> [PATCH 3/7] drm: of: introduce drm_of_media_bus_fmt

As usual, one should try to reuse as much as possible of the existing
bindings. That's a totally different thing compared to assign to a bus
width property an associated image format for the whole DRM subsystem

ot: those properties should be moved outside of
media/video_interfaces.txt sooner or later, to a more generic place...

>
> With that view, any input format specification of the bridge is not helpful
> for me since what the bridge specifies (without help) is going to be wrong

No it's not useless. I can have an encoder that can provide both YUV
and RGB formats. If your bridge accepts RGB I want to know that, and
the bus_width is unrelated imho.

> anyway. End result, I need to specify the format manually on either the
> bridge or the atmel-hlcdc side, and I happen to think that the correct side
> is with the atmel-hlcdc, because that is where my issue originates. In short,
> the "drm: bridge: Add support for static image formats" series is unrelated
> as far as I can tell.

I may be biased on this, so I let other to judge and provide more
suggestions.

Thanks
   j

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

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

* Re: [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
@ 2018-04-20 11:38         ` jacopo mondi
  0 siblings, 0 replies; 67+ messages in thread
From: jacopo mondi @ 2018-04-20 11:38 UTC (permalink / raw)
  To: Peter Rosin
  Cc: Mark Rutland, Boris Brezillon, Alexandre Belloni, devicetree,
	David Airlie, Nicolas Ferre, dri-devel, linux-kernel,
	Rob Herring, Laurent Pinchart, Daniel Vetter, Jacopo Mondi,
	Russell King, linux-arm-kernel


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

Hi Peter,

On Fri, Apr 20, 2018 at 01:05:21PM +0200, Peter Rosin wrote:
> On 2018-04-20 12:18, Laurent Pinchart wrote:
> > Hello,
> >
> > On Friday, 20 April 2018 11:52:35 EEST jacopo mondi wrote:
> >> Hi Peter,
> >>     I've been a bit a pain in the arse for you recently, but please
> >> bear with me a bit more, and sorry for jumping late on the band wagon.
> >>
> >> On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
> >>> Hi!
> >>>
> >>> I naively thought that since there was support for both nxp,tda19988 (in
> >>> the tda998x driver) and the atmel-hlcdc, things would be a smooth ride.
> >>> But it wasn't, so I started looking around and realized I had to fix
> >>> things.
> >>>
> >>> In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
> >>> component, but now in v3 I fix things by making the tda998x driver
> >>> a bridge instead. This was after a suggestion from Boris Brezillion
>
> That should be Brezillon, sorry for being sloppy with the spelling.
>
> >>> (the atmel-hlcdc maintainer), so there was some risk of bias ... but
> >>> after comparing what was needed, I too find the bridge approach better.
> >>>
> >>> In addition to the above, our PCB interface between the SAMA5D3 and the
> >>> HDMI encoder is only using 16 bits, and this has to be described
> >>> somewhere, or the atmel-hlcdc driver have no chance of selecting the
> >>> correct output mode. Since I have similar problems with a ds90c185 lvds
> >>> encoder I added patches to override the atmel-hlcdc output format via
> >>> DT properties compatible with the media video-interface binding and
> >>> things start to play together.
> >>>
> >>> Since this series superseeds the bridge series [1], I have included the
> >>> leftover bindings patch for the ti,ds90c185 here.
> >>
> >> I feel like this series would look better if it would make use of the
> >> proposed bridge media bus format support I have recently sent out [1]
> >> (and which was not there when you first sent v1).
> >>
> >> I understand your fundamental problem here is that the bus format
> >> that should be reported by your bridge is different from the ones
> >> actually supported by the TDA19988 chip, as the wirings ground some
> >> of the input pins.
> >>
> >> Although this is defintely something that could be described in the
> >> bridge's own OF node with the 'bus_width' property, and what I would do,
> >> now that you have made a bridge out from the tda19988 driver, is:
> >>
> >> 1) Set the bridge accepted input bus_format parsing its pin
> >> configuration, or default it if that's not implemented yet.
> >> This will likely be rgb888. You can do that using the trivial
> >> support for bridge input image formats implemented by my series.
> >> 2) Specify in the bridge endpoint a 'bus_width' of <16>
> >> 3) In your atmel-hlcd get both the image format of the bridge (rgb888)
> >> and parse the remote endpoint property 'bus_width' and get the <16>
> >> value back.
> >
> > Parsing properties of remote nodes should be avoided as much as possible, as
> > they need to be interpreted in the context of the DT bindings related to the
> > compatible string applicable to that node. I'd rather have the bus_width
> > property in the local endpoint node.
>
> In addition to that, my view of this binding
>
> 	endpoint {
> 		bus-type = <0>;

bus-type is used by v4l2_fwnode helpers to decide which type of bus
they're dealing with iirc. Here it seems to me it has no added
value, also because in your bindings description "it shall be 0" and
it is not parsed anywhere in you code, but no big deal....

> 		bus-widht = <16>;
> 	};
>
> is that it always means rgb565. See further below.
>
> >> 4) Set the correct format in the atmel hlcd driver to accommodate a
> >> bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
> >> or are there other possible combinations I am missing?)
> >>
> >> I would consider this better mostly because in this series you are
> >> creating a semantic for the whole DRM subsystem on the 'bus_width'
> >> property, where numerical values as '12', '16' etc are arbitrary tied
> >> to the selection of a media bus format. At least you should use a
> >> common set of defines [1] between the device tree and the driver,
> >> but this looks anyway fragile imho.
> >
> > This I agree with though. Combining the remote bus format with the local bus
> > width should fix the problem without having to parse remote properties.
>
> My thinking was that the binding with bus-type = <0> and bus-width = <bpp>
> would mean a parallel bus (type 0 means auto-detect and with a bus-width that
> auto-detect means a parallel bus) and the most natural/common interpretation
> of that bus-width. For bus widths of 12, 16, 18, 24, 30 etc I think that
> would be rgb444, rgb565, rgb666, rgb888, rgb101010 (or, I'm first so I get
> to define the default). If you have some other interpretation of a bus with
> that width, you'd need to extend the video-interface binding with some way
> of saying what you need, perhaps using some kind of data mapping or something
> to say e.g. bgr666. And you'd need some kind of indicator if you have YUV
> signals instead of RGB, and LVDS isn't a completely parallel bus, so you'd
> need something for that. Etc.

The fundamental issue here is that you're tying the bus with to an
image format. Why <16> can't be, say, MEDIA_BUS_FMT_YVYU8_1X16? it
spans to 16 bits, doesn't it? And I'm sorry but the 'I'm first so I
get to define defaults' argument doesn't apply here.

So, it is my opinion you need to expose an image format somewhere. And
it is my opinion again, which can be very wrong ofc, that this place
is the bridge driver.

You need to adjust the output to accommodate wirings? You can use the
bus_width on the hlcd side, as Laurent suggested, but the bus width
does not tie to any image format at all, even more if you're making
that decision in a drm-wide function.

>
> Because the word from Rob was that there should be one common binding that
> describes video interfaces. I started an implementation that interprets that
> binding in a drm context in
> [PATCH 3/7] drm: of: introduce drm_of_media_bus_fmt

As usual, one should try to reuse as much as possible of the existing
bindings. That's a totally different thing compared to assign to a bus
width property an associated image format for the whole DRM subsystem

ot: those properties should be moved outside of
media/video_interfaces.txt sooner or later, to a more generic place...

>
> With that view, any input format specification of the bridge is not helpful
> for me since what the bridge specifies (without help) is going to be wrong

No it's not useless. I can have an encoder that can provide both YUV
and RGB formats. If your bridge accepts RGB I want to know that, and
the bus_width is unrelated imho.

> anyway. End result, I need to specify the format manually on either the
> bridge or the atmel-hlcdc side, and I happen to think that the correct side
> is with the atmel-hlcdc, because that is where my issue originates. In short,
> the "drm: bridge: Add support for static image formats" series is unrelated
> as far as I can tell.

I may be biased on this, so I let other to judge and provide more
suggestions.

Thanks
   j

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

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

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

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

* [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
@ 2018-04-20 11:38         ` jacopo mondi
  0 siblings, 0 replies; 67+ messages in thread
From: jacopo mondi @ 2018-04-20 11:38 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Peter,

On Fri, Apr 20, 2018 at 01:05:21PM +0200, Peter Rosin wrote:
> On 2018-04-20 12:18, Laurent Pinchart wrote:
> > Hello,
> >
> > On Friday, 20 April 2018 11:52:35 EEST jacopo mondi wrote:
> >> Hi Peter,
> >>     I've been a bit a pain in the arse for you recently, but please
> >> bear with me a bit more, and sorry for jumping late on the band wagon.
> >>
> >> On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
> >>> Hi!
> >>>
> >>> I naively thought that since there was support for both nxp,tda19988 (in
> >>> the tda998x driver) and the atmel-hlcdc, things would be a smooth ride.
> >>> But it wasn't, so I started looking around and realized I had to fix
> >>> things.
> >>>
> >>> In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
> >>> component, but now in v3 I fix things by making the tda998x driver
> >>> a bridge instead. This was after a suggestion from Boris Brezillion
>
> That should be Brezillon, sorry for being sloppy with the spelling.
>
> >>> (the atmel-hlcdc maintainer), so there was some risk of bias ... but
> >>> after comparing what was needed, I too find the bridge approach better.
> >>>
> >>> In addition to the above, our PCB interface between the SAMA5D3 and the
> >>> HDMI encoder is only using 16 bits, and this has to be described
> >>> somewhere, or the atmel-hlcdc driver have no chance of selecting the
> >>> correct output mode. Since I have similar problems with a ds90c185 lvds
> >>> encoder I added patches to override the atmel-hlcdc output format via
> >>> DT properties compatible with the media video-interface binding and
> >>> things start to play together.
> >>>
> >>> Since this series superseeds the bridge series [1], I have included the
> >>> leftover bindings patch for the ti,ds90c185 here.
> >>
> >> I feel like this series would look better if it would make use of the
> >> proposed bridge media bus format support I have recently sent out [1]
> >> (and which was not there when you first sent v1).
> >>
> >> I understand your fundamental problem here is that the bus format
> >> that should be reported by your bridge is different from the ones
> >> actually supported by the TDA19988 chip, as the wirings ground some
> >> of the input pins.
> >>
> >> Although this is defintely something that could be described in the
> >> bridge's own OF node with the 'bus_width' property, and what I would do,
> >> now that you have made a bridge out from the tda19988 driver, is:
> >>
> >> 1) Set the bridge accepted input bus_format parsing its pin
> >> configuration, or default it if that's not implemented yet.
> >> This will likely be rgb888. You can do that using the trivial
> >> support for bridge input image formats implemented by my series.
> >> 2) Specify in the bridge endpoint a 'bus_width' of <16>
> >> 3) In your atmel-hlcd get both the image format of the bridge (rgb888)
> >> and parse the remote endpoint property 'bus_width' and get the <16>
> >> value back.
> >
> > Parsing properties of remote nodes should be avoided as much as possible, as
> > they need to be interpreted in the context of the DT bindings related to the
> > compatible string applicable to that node. I'd rather have the bus_width
> > property in the local endpoint node.
>
> In addition to that, my view of this binding
>
> 	endpoint {
> 		bus-type = <0>;

bus-type is used by v4l2_fwnode helpers to decide which type of bus
they're dealing with iirc. Here it seems to me it has no added
value, also because in your bindings description "it shall be 0" and
it is not parsed anywhere in you code, but no big deal....

> 		bus-widht = <16>;
> 	};
>
> is that it always means rgb565. See further below.
>
> >> 4) Set the correct format in the atmel hlcd driver to accommodate a
> >> bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
> >> or are there other possible combinations I am missing?)
> >>
> >> I would consider this better mostly because in this series you are
> >> creating a semantic for the whole DRM subsystem on the 'bus_width'
> >> property, where numerical values as '12', '16' etc are arbitrary tied
> >> to the selection of a media bus format. At least you should use a
> >> common set of defines [1] between the device tree and the driver,
> >> but this looks anyway fragile imho.
> >
> > This I agree with though. Combining the remote bus format with the local bus
> > width should fix the problem without having to parse remote properties.
>
> My thinking was that the binding with bus-type = <0> and bus-width = <bpp>
> would mean a parallel bus (type 0 means auto-detect and with a bus-width that
> auto-detect means a parallel bus) and the most natural/common interpretation
> of that bus-width. For bus widths of 12, 16, 18, 24, 30 etc I think that
> would be rgb444, rgb565, rgb666, rgb888, rgb101010 (or, I'm first so I get
> to define the default). If you have some other interpretation of a bus with
> that width, you'd need to extend the video-interface binding with some way
> of saying what you need, perhaps using some kind of data mapping or something
> to say e.g. bgr666. And you'd need some kind of indicator if you have YUV
> signals instead of RGB, and LVDS isn't a completely parallel bus, so you'd
> need something for that. Etc.

The fundamental issue here is that you're tying the bus with to an
image format. Why <16> can't be, say, MEDIA_BUS_FMT_YVYU8_1X16? it
spans to 16 bits, doesn't it? And I'm sorry but the 'I'm first so I
get to define defaults' argument doesn't apply here.

So, it is my opinion you need to expose an image format somewhere. And
it is my opinion again, which can be very wrong ofc, that this place
is the bridge driver.

You need to adjust the output to accommodate wirings? You can use the
bus_width on the hlcd side, as Laurent suggested, but the bus width
does not tie to any image format at all, even more if you're making
that decision in a drm-wide function.

>
> Because the word from Rob was that there should be one common binding that
> describes video interfaces. I started an implementation that interprets that
> binding in a drm context in
> [PATCH 3/7] drm: of: introduce drm_of_media_bus_fmt

As usual, one should try to reuse as much as possible of the existing
bindings. That's a totally different thing compared to assign to a bus
width property an associated image format for the whole DRM subsystem

ot: those properties should be moved outside of
media/video_interfaces.txt sooner or later, to a more generic place...

>
> With that view, any input format specification of the bridge is not helpful
> for me since what the bridge specifies (without help) is going to be wrong

No it's not useless. I can have an encoder that can provide both YUV
and RGB formats. If your bridge accepts RGB I want to know that, and
the bus_width is unrelated imho.

> anyway. End result, I need to specify the format manually on either the
> bridge or the atmel-hlcdc side, and I happen to think that the correct side
> is with the atmel-hlcdc, because that is where my issue originates. In short,
> the "drm: bridge: Add support for static image formats" series is unrelated
> as far as I can tell.

I may be biased on this, so I let other to judge and provide more
suggestions.

Thanks
   j
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180420/c669041c/attachment-0001.sig>

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

* Re: [PATCH v3 7/7] drm/i2c: tda998x: register as a drm bridge
  2018-04-19 16:27   ` Peter Rosin
@ 2018-04-20 12:00     ` Russell King - ARM Linux
  -1 siblings, 0 replies; 67+ messages in thread
From: Russell King - ARM Linux @ 2018-04-20 12:00 UTC (permalink / raw)
  To: Peter Rosin
  Cc: linux-kernel, David Airlie, Rob Herring, Mark Rutland,
	Nicolas Ferre, Alexandre Belloni, Boris Brezillon, Daniel Vetter,
	Gustavo Padovan, Sean Paul, Laurent Pinchart, Jacopo Mondi,
	dri-devel, devicetree, linux-arm-kernel

On Thu, Apr 19, 2018 at 06:27:51PM +0200, Peter Rosin wrote:
> This makes this driver work with all(?) drivers that are not
> componentized and instead expect to connect to a panel/bridge. That
> said, the only one tested is atmel_hlcdc.
> 
> This hooks the relevant work function previously called by the encoder
> and the component also to the bridge, since the encoder goes away when
> connecting to the bridge interface of the driver and the equivalent of
> bind/unbind of the component is handled by bridge attach/detach.
> 
> The lifetime requirements of a bridge and a component are slightly
> different, which is the reason for struct tda998x_bridge.

As we are talking about bridge stuff, the patch below is what I've had
for a while converting Armada to be able to use a bridge-based tda998x.
As you can see, it's far from satisfactory at the moment.  Specifically:

1) it assumes all bridges are TMDS bridges, because as far as I can see,
   there's no way to know any different.
2) there's no way to really know whether a missing bridge is because we
   should be using the component helpers or that the bridge device
   doesn't exist yet.

diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c
index 262409cae8bf..854d74466dec 100644
--- a/drivers/gpu/drm/armada/armada_drv.c
+++ b/drivers/gpu/drm/armada/armada_drv.c
@@ -20,6 +20,127 @@
 #include <drm/armada_drm.h>
 #include "armada_ioctlP.h"
 
+static const struct drm_encoder_helper_funcs dummy_encoder_helper_funcs = {
+};
+
+static const struct drm_encoder_funcs dummy_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+static int dummy_encoder_add(struct device *dev, struct drm_device *drm,
+			     struct drm_bridge *bridge, int type, u32 crtcs)
+{
+	struct drm_encoder *enc;
+	int ret;
+
+	enc = devm_kzalloc(dev, sizeof(*enc), GFP_KERNEL);
+	if (!enc)
+		return -ENOMEM;
+
+	drm_encoder_helper_add(enc, &dummy_encoder_helper_funcs);
+	ret = drm_encoder_init(drm, enc, &dummy_encoder_funcs, type, NULL);
+	if (ret)
+		return ret;
+
+	enc->possible_crtcs = crtcs;
+	enc->bridge = bridge;
+	bridge->encoder = enc;
+
+	ret = drm_bridge_attach(enc, bridge, NULL);
+	if (ret)
+		dev_err(dev, "drm_bridge_attach() failed: %d\n", ret);
+
+	return ret;
+}
+
+static int hack_of_add_crtc_encoders(struct drm_device *drm,
+				     struct device_node *port)
+{
+	struct device *dev = drm->dev;
+	struct device_node *ep, *remote;
+	struct drm_bridge *bridge;
+	u32 crtcs;
+	int ret;
+
+	for_each_child_of_node(port, ep) {
+		remote = of_graph_get_remote_port_parent(ep);
+		if (!remote || !of_device_is_available(remote) ||
+		    !of_device_is_available(remote->parent)) {
+			of_node_put(remote);
+			continue;
+		}
+
+		bridge = of_drm_find_bridge(remote);
+dev_info(dev, "found remote %s => bridge %p\n", of_node_full_name(remote), bridge);
+		if (!bridge) {
+			of_node_put(remote);
+			continue;
+		}
+
+		crtcs = drm_of_find_possible_crtcs(drm, remote);
+		/* If no CRTCs were found, fall back to our old behaviour */
+		if (crtcs == 0) {
+			dev_warn(dev, "Falling back to first CRTC\n");
+			crtcs = 1 << 0;
+		}
+
+		ret = dummy_encoder_add(dev, drm, bridge, DRM_MODE_ENCODER_TMDS,
+					crtcs);
+		if (ret) {
+			dev_err(dev, "drm_bridge_attach() failed: %d\n", ret);
+			of_node_put(ep);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int hack_create_encoders(struct drm_device *drm)
+{
+	struct device *dev = drm->dev;
+	struct device_node *port = NULL;
+	int i, ret = 0;
+
+	if (dev->of_node) {
+		for (i = 0; ; i++) {
+			port = of_parse_phandle(dev->of_node, "ports", i);
+			if (!port)
+				break;
+
+			if (of_device_is_available(port->parent))
+				ret = hack_of_add_crtc_encoders(drm, port);
+
+			of_node_put(port);
+
+			if (ret)
+				break;
+		}
+	} else if (dev->platform_data) {
+		const char **devices = dev->platform_data;
+		struct device *d;
+
+		for (i = 0; devices[i]; i++) {
+			d = bus_find_device_by_name(&platform_bus_type, NULL,
+						    devices[i]);
+			if (d && d->of_node) {
+				for_each_child_of_node(d->of_node, port) {
+					ret = hack_of_add_crtc_encoders(drm, port);
+					if (ret) {
+						of_node_put(port);
+						break;
+					}
+				}
+			}
+			put_device(d);
+			if (ret)
+				break;
+		}
+	}
+
+	return ret;
+}
+
 static void armada_drm_unref_work(struct work_struct *work)
 {
 	struct armada_private *priv =
@@ -153,6 +274,10 @@ static int armada_drm_bind(struct device *dev)
 	if (ret)
 		goto err_kms;
 
+	ret = hack_create_encoders(&priv->drm);
+	if (ret)
+		goto err_comp;
+
 	ret = drm_vblank_init(&priv->drm, priv->drm.mode_config.num_crtc);
 	if (ret)
 		goto err_comp;
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index b78c0627e7cf..feb6debb1563 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -68,7 +68,7 @@ struct tda998x_priv {
 	wait_queue_head_t edid_delay_waitq;
 	bool edid_delay_active;
 
-	struct drm_encoder encoder;
+	struct drm_bridge bridge;
 	struct drm_connector connector;
 
 	struct tda998x_audio_port audio_port[2];
@@ -80,8 +80,8 @@ struct tda998x_priv {
 #define conn_to_tda998x_priv(x) \
 	container_of(x, struct tda998x_priv, connector)
 
-#define enc_to_tda998x_priv(x) \
-	container_of(x, struct tda998x_priv, encoder)
+#define bridge_to_tda998x_priv(x) \
+	container_of(x, struct tda998x_priv, bridge)
 
 /* The TDA9988 series of devices use a paged register scheme.. to simplify
  * things we encode the page # in upper bits of the register #.  To read/
@@ -753,7 +753,7 @@ static void tda998x_detect_work(struct work_struct *work)
 {
 	struct tda998x_priv *priv =
 		container_of(work, struct tda998x_priv, detect_work);
-	struct drm_device *dev = priv->encoder.dev;
+	struct drm_device *dev = priv->connector.dev;
 
 	if (dev)
 		drm_kms_helper_hotplug_event(dev);
@@ -1262,7 +1262,7 @@ tda998x_connector_best_encoder(struct drm_connector *connector)
 {
 	struct tda998x_priv *priv = conn_to_tda998x_priv(connector);
 
-	return &priv->encoder;
+	return priv->bridge.encoder;
 }
 
 static
@@ -1292,36 +1292,27 @@ static int tda998x_connector_init(struct tda998x_priv *priv,
 	if (ret)
 		return ret;
 
-	drm_mode_connector_attach_encoder(&priv->connector, &priv->encoder);
+	drm_mode_connector_attach_encoder(&priv->connector,
+					  priv->bridge.encoder);
 
 	return 0;
 }
 
-/* DRM encoder functions */
+/* DRM bridge functions */
 
-static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
+static int tda998x_bridge_attach(struct drm_bridge *bridge)
 {
-	struct tda998x_priv *priv = enc_to_tda998x_priv(encoder);
-	bool on;
+	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
+	struct drm_device *drm = bridge->dev;
 
-	/* we only care about on or off: */
-	on = mode == DRM_MODE_DPMS_ON;
-
-	if (on == priv->is_on)
-		return;
+	return tda998x_connector_init(priv, drm);
+}
 
-	if (on) {
-		/* enable video ports, audio will be enabled later */
-		reg_write(priv, REG_ENA_VP_0, 0xff);
-		reg_write(priv, REG_ENA_VP_1, 0xff);
-		reg_write(priv, REG_ENA_VP_2, 0xff);
-		/* set muxing after enabling ports: */
-		reg_write(priv, REG_VIP_CNTRL_0, priv->vip_cntrl_0);
-		reg_write(priv, REG_VIP_CNTRL_1, priv->vip_cntrl_1);
-		reg_write(priv, REG_VIP_CNTRL_2, priv->vip_cntrl_2);
+static void tda998x_bridge_disable(struct drm_bridge *bridge)
+{
+	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
 
-		priv->is_on = true;
-	} else {
+	if (priv->is_on) {
 		/* disable video ports */
 		reg_write(priv, REG_ENA_VP_0, 0x00);
 		reg_write(priv, REG_ENA_VP_1, 0x00);
@@ -1332,11 +1323,11 @@ static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
 }
 
 static void
-tda998x_encoder_mode_set(struct drm_encoder *encoder,
-			 struct drm_display_mode *mode,
-			 struct drm_display_mode *adjusted_mode)
+tda998x_bridge_mode_set(struct drm_bridge *bridge,
+			struct drm_display_mode *mode,
+			struct drm_display_mode *adjusted_mode)
 {
-	struct tda998x_priv *priv = enc_to_tda998x_priv(encoder);
+	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
 	u16 ref_pix, ref_line, n_pix, n_line;
 	u16 hs_pix_s, hs_pix_e;
 	u16 vs1_pix_s, vs1_pix_e, vs1_line_s, vs1_line_e;
@@ -1543,6 +1534,31 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,
 	mutex_unlock(&priv->audio_mutex);
 }
 
+static void tda998x_bridge_enable(struct drm_bridge *bridge)
+{
+	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
+
+	if (!priv->is_on) {
+		/* enable video ports, audio will be enabled later */
+		reg_write(priv, REG_ENA_VP_0, 0xff);
+		reg_write(priv, REG_ENA_VP_1, 0xff);
+		reg_write(priv, REG_ENA_VP_2, 0xff);
+		/* set muxing after enabling ports: */
+		reg_write(priv, REG_VIP_CNTRL_0, priv->vip_cntrl_0);
+		reg_write(priv, REG_VIP_CNTRL_1, priv->vip_cntrl_1);
+		reg_write(priv, REG_VIP_CNTRL_2, priv->vip_cntrl_2);
+
+		priv->is_on = true;
+	}
+}
+
+static const struct drm_bridge_funcs tda998x_bridge_funcs = {
+	.attach = tda998x_bridge_attach,
+	.disable = tda998x_bridge_disable,
+	.mode_set = tda998x_bridge_mode_set,
+	.enable = tda998x_bridge_enable,
+};
+
 static void tda998x_destroy(struct tda998x_priv *priv)
 {
 	/* disable all IRQs and free the IRQ handler */
@@ -1796,35 +1812,6 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv)
 	return ret;
 }
 
-static void tda998x_encoder_prepare(struct drm_encoder *encoder)
-{
-	tda998x_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
-}
-
-static void tda998x_encoder_commit(struct drm_encoder *encoder)
-{
-	tda998x_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
-}
-
-static const struct drm_encoder_helper_funcs tda998x_encoder_helper_funcs = {
-	.dpms = tda998x_encoder_dpms,
-	.prepare = tda998x_encoder_prepare,
-	.commit = tda998x_encoder_commit,
-	.mode_set = tda998x_encoder_mode_set,
-};
-
-static void tda998x_encoder_destroy(struct drm_encoder *encoder)
-{
-	struct tda998x_priv *priv = enc_to_tda998x_priv(encoder);
-
-	tda998x_destroy(priv);
-	drm_encoder_cleanup(encoder);
-}
-
-static const struct drm_encoder_funcs tda998x_encoder_funcs = {
-	.destroy = tda998x_encoder_destroy,
-};
-
 static void tda998x_set_config(struct tda998x_priv *priv,
 			       const struct tda998x_encoder_params *p)
 {
@@ -1882,9 +1869,7 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data)
 {
 	struct tda998x_encoder_params *params = dev->platform_data;
 	struct i2c_client *client = to_i2c_client(dev);
-	struct drm_device *drm = data;
 	struct tda998x_priv *priv;
-	u32 crtcs = 0;
 	int ret;
 
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -1893,16 +1878,6 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data)
 
 	dev_set_drvdata(dev, priv);
 
-	if (dev->of_node)
-		crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
-
-	/* If no CRTCs were found, fall back to our old behaviour */
-	if (crtcs == 0) {
-		dev_warn(dev, "Falling back to first CRTC\n");
-		crtcs = 1 << 0;
-	}
-
-	priv->encoder.possible_crtcs = crtcs;
 	priv->audio_params.config = BIT(2);
 	priv->audio_params.format = AFMT_SPDIF;
 	priv->audio_params.sample_rate = 44100;
@@ -1925,23 +1900,12 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data)
 	if (!dev->of_node && params)
 		tda998x_set_config(priv, params);
 
-	drm_encoder_helper_add(&priv->encoder, &tda998x_encoder_helper_funcs);
-	ret = drm_encoder_init(drm, &priv->encoder, &tda998x_encoder_funcs,
-			       DRM_MODE_ENCODER_TMDS, NULL);
-	if (ret)
-		goto err_encoder;
+	priv->bridge.funcs = &tda998x_bridge_funcs;
+	priv->bridge.of_node = dev->of_node;
 
-	ret = tda998x_connector_init(priv, drm);
-	if (ret)
-		goto err_connector;
+	drm_bridge_add(&priv->bridge);
 
 	return 0;
-
-err_connector:
-	drm_encoder_cleanup(&priv->encoder);
-err_encoder:
-	tda998x_destroy(priv);
-	return ret;
 }
 
 static void tda998x_unbind(struct device *dev, struct device *master,
@@ -1950,7 +1914,7 @@ static void tda998x_unbind(struct device *dev, struct device *master,
 	struct tda998x_priv *priv = dev_get_drvdata(dev);
 
 	drm_connector_cleanup(&priv->connector);
-	drm_encoder_cleanup(&priv->encoder);
+	drm_bridge_remove(&priv->bridge);
 	tda998x_destroy(priv);
 }
 


-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up

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

* [PATCH v3 7/7] drm/i2c: tda998x: register as a drm bridge
@ 2018-04-20 12:00     ` Russell King - ARM Linux
  0 siblings, 0 replies; 67+ messages in thread
From: Russell King - ARM Linux @ 2018-04-20 12:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Apr 19, 2018 at 06:27:51PM +0200, Peter Rosin wrote:
> This makes this driver work with all(?) drivers that are not
> componentized and instead expect to connect to a panel/bridge. That
> said, the only one tested is atmel_hlcdc.
> 
> This hooks the relevant work function previously called by the encoder
> and the component also to the bridge, since the encoder goes away when
> connecting to the bridge interface of the driver and the equivalent of
> bind/unbind of the component is handled by bridge attach/detach.
> 
> The lifetime requirements of a bridge and a component are slightly
> different, which is the reason for struct tda998x_bridge.

As we are talking about bridge stuff, the patch below is what I've had
for a while converting Armada to be able to use a bridge-based tda998x.
As you can see, it's far from satisfactory at the moment.  Specifically:

1) it assumes all bridges are TMDS bridges, because as far as I can see,
   there's no way to know any different.
2) there's no way to really know whether a missing bridge is because we
   should be using the component helpers or that the bridge device
   doesn't exist yet.

diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c
index 262409cae8bf..854d74466dec 100644
--- a/drivers/gpu/drm/armada/armada_drv.c
+++ b/drivers/gpu/drm/armada/armada_drv.c
@@ -20,6 +20,127 @@
 #include <drm/armada_drm.h>
 #include "armada_ioctlP.h"
 
+static const struct drm_encoder_helper_funcs dummy_encoder_helper_funcs = {
+};
+
+static const struct drm_encoder_funcs dummy_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+static int dummy_encoder_add(struct device *dev, struct drm_device *drm,
+			     struct drm_bridge *bridge, int type, u32 crtcs)
+{
+	struct drm_encoder *enc;
+	int ret;
+
+	enc = devm_kzalloc(dev, sizeof(*enc), GFP_KERNEL);
+	if (!enc)
+		return -ENOMEM;
+
+	drm_encoder_helper_add(enc, &dummy_encoder_helper_funcs);
+	ret = drm_encoder_init(drm, enc, &dummy_encoder_funcs, type, NULL);
+	if (ret)
+		return ret;
+
+	enc->possible_crtcs = crtcs;
+	enc->bridge = bridge;
+	bridge->encoder = enc;
+
+	ret = drm_bridge_attach(enc, bridge, NULL);
+	if (ret)
+		dev_err(dev, "drm_bridge_attach() failed: %d\n", ret);
+
+	return ret;
+}
+
+static int hack_of_add_crtc_encoders(struct drm_device *drm,
+				     struct device_node *port)
+{
+	struct device *dev = drm->dev;
+	struct device_node *ep, *remote;
+	struct drm_bridge *bridge;
+	u32 crtcs;
+	int ret;
+
+	for_each_child_of_node(port, ep) {
+		remote = of_graph_get_remote_port_parent(ep);
+		if (!remote || !of_device_is_available(remote) ||
+		    !of_device_is_available(remote->parent)) {
+			of_node_put(remote);
+			continue;
+		}
+
+		bridge = of_drm_find_bridge(remote);
+dev_info(dev, "found remote %s => bridge %p\n", of_node_full_name(remote), bridge);
+		if (!bridge) {
+			of_node_put(remote);
+			continue;
+		}
+
+		crtcs = drm_of_find_possible_crtcs(drm, remote);
+		/* If no CRTCs were found, fall back to our old behaviour */
+		if (crtcs == 0) {
+			dev_warn(dev, "Falling back to first CRTC\n");
+			crtcs = 1 << 0;
+		}
+
+		ret = dummy_encoder_add(dev, drm, bridge, DRM_MODE_ENCODER_TMDS,
+					crtcs);
+		if (ret) {
+			dev_err(dev, "drm_bridge_attach() failed: %d\n", ret);
+			of_node_put(ep);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int hack_create_encoders(struct drm_device *drm)
+{
+	struct device *dev = drm->dev;
+	struct device_node *port = NULL;
+	int i, ret = 0;
+
+	if (dev->of_node) {
+		for (i = 0; ; i++) {
+			port = of_parse_phandle(dev->of_node, "ports", i);
+			if (!port)
+				break;
+
+			if (of_device_is_available(port->parent))
+				ret = hack_of_add_crtc_encoders(drm, port);
+
+			of_node_put(port);
+
+			if (ret)
+				break;
+		}
+	} else if (dev->platform_data) {
+		const char **devices = dev->platform_data;
+		struct device *d;
+
+		for (i = 0; devices[i]; i++) {
+			d = bus_find_device_by_name(&platform_bus_type, NULL,
+						    devices[i]);
+			if (d && d->of_node) {
+				for_each_child_of_node(d->of_node, port) {
+					ret = hack_of_add_crtc_encoders(drm, port);
+					if (ret) {
+						of_node_put(port);
+						break;
+					}
+				}
+			}
+			put_device(d);
+			if (ret)
+				break;
+		}
+	}
+
+	return ret;
+}
+
 static void armada_drm_unref_work(struct work_struct *work)
 {
 	struct armada_private *priv =
@@ -153,6 +274,10 @@ static int armada_drm_bind(struct device *dev)
 	if (ret)
 		goto err_kms;
 
+	ret = hack_create_encoders(&priv->drm);
+	if (ret)
+		goto err_comp;
+
 	ret = drm_vblank_init(&priv->drm, priv->drm.mode_config.num_crtc);
 	if (ret)
 		goto err_comp;
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index b78c0627e7cf..feb6debb1563 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -68,7 +68,7 @@ struct tda998x_priv {
 	wait_queue_head_t edid_delay_waitq;
 	bool edid_delay_active;
 
-	struct drm_encoder encoder;
+	struct drm_bridge bridge;
 	struct drm_connector connector;
 
 	struct tda998x_audio_port audio_port[2];
@@ -80,8 +80,8 @@ struct tda998x_priv {
 #define conn_to_tda998x_priv(x) \
 	container_of(x, struct tda998x_priv, connector)
 
-#define enc_to_tda998x_priv(x) \
-	container_of(x, struct tda998x_priv, encoder)
+#define bridge_to_tda998x_priv(x) \
+	container_of(x, struct tda998x_priv, bridge)
 
 /* The TDA9988 series of devices use a paged register scheme.. to simplify
  * things we encode the page # in upper bits of the register #.  To read/
@@ -753,7 +753,7 @@ static void tda998x_detect_work(struct work_struct *work)
 {
 	struct tda998x_priv *priv =
 		container_of(work, struct tda998x_priv, detect_work);
-	struct drm_device *dev = priv->encoder.dev;
+	struct drm_device *dev = priv->connector.dev;
 
 	if (dev)
 		drm_kms_helper_hotplug_event(dev);
@@ -1262,7 +1262,7 @@ tda998x_connector_best_encoder(struct drm_connector *connector)
 {
 	struct tda998x_priv *priv = conn_to_tda998x_priv(connector);
 
-	return &priv->encoder;
+	return priv->bridge.encoder;
 }
 
 static
@@ -1292,36 +1292,27 @@ static int tda998x_connector_init(struct tda998x_priv *priv,
 	if (ret)
 		return ret;
 
-	drm_mode_connector_attach_encoder(&priv->connector, &priv->encoder);
+	drm_mode_connector_attach_encoder(&priv->connector,
+					  priv->bridge.encoder);
 
 	return 0;
 }
 
-/* DRM encoder functions */
+/* DRM bridge functions */
 
-static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
+static int tda998x_bridge_attach(struct drm_bridge *bridge)
 {
-	struct tda998x_priv *priv = enc_to_tda998x_priv(encoder);
-	bool on;
+	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
+	struct drm_device *drm = bridge->dev;
 
-	/* we only care about on or off: */
-	on = mode == DRM_MODE_DPMS_ON;
-
-	if (on == priv->is_on)
-		return;
+	return tda998x_connector_init(priv, drm);
+}
 
-	if (on) {
-		/* enable video ports, audio will be enabled later */
-		reg_write(priv, REG_ENA_VP_0, 0xff);
-		reg_write(priv, REG_ENA_VP_1, 0xff);
-		reg_write(priv, REG_ENA_VP_2, 0xff);
-		/* set muxing after enabling ports: */
-		reg_write(priv, REG_VIP_CNTRL_0, priv->vip_cntrl_0);
-		reg_write(priv, REG_VIP_CNTRL_1, priv->vip_cntrl_1);
-		reg_write(priv, REG_VIP_CNTRL_2, priv->vip_cntrl_2);
+static void tda998x_bridge_disable(struct drm_bridge *bridge)
+{
+	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
 
-		priv->is_on = true;
-	} else {
+	if (priv->is_on) {
 		/* disable video ports */
 		reg_write(priv, REG_ENA_VP_0, 0x00);
 		reg_write(priv, REG_ENA_VP_1, 0x00);
@@ -1332,11 +1323,11 @@ static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
 }
 
 static void
-tda998x_encoder_mode_set(struct drm_encoder *encoder,
-			 struct drm_display_mode *mode,
-			 struct drm_display_mode *adjusted_mode)
+tda998x_bridge_mode_set(struct drm_bridge *bridge,
+			struct drm_display_mode *mode,
+			struct drm_display_mode *adjusted_mode)
 {
-	struct tda998x_priv *priv = enc_to_tda998x_priv(encoder);
+	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
 	u16 ref_pix, ref_line, n_pix, n_line;
 	u16 hs_pix_s, hs_pix_e;
 	u16 vs1_pix_s, vs1_pix_e, vs1_line_s, vs1_line_e;
@@ -1543,6 +1534,31 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,
 	mutex_unlock(&priv->audio_mutex);
 }
 
+static void tda998x_bridge_enable(struct drm_bridge *bridge)
+{
+	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
+
+	if (!priv->is_on) {
+		/* enable video ports, audio will be enabled later */
+		reg_write(priv, REG_ENA_VP_0, 0xff);
+		reg_write(priv, REG_ENA_VP_1, 0xff);
+		reg_write(priv, REG_ENA_VP_2, 0xff);
+		/* set muxing after enabling ports: */
+		reg_write(priv, REG_VIP_CNTRL_0, priv->vip_cntrl_0);
+		reg_write(priv, REG_VIP_CNTRL_1, priv->vip_cntrl_1);
+		reg_write(priv, REG_VIP_CNTRL_2, priv->vip_cntrl_2);
+
+		priv->is_on = true;
+	}
+}
+
+static const struct drm_bridge_funcs tda998x_bridge_funcs = {
+	.attach = tda998x_bridge_attach,
+	.disable = tda998x_bridge_disable,
+	.mode_set = tda998x_bridge_mode_set,
+	.enable = tda998x_bridge_enable,
+};
+
 static void tda998x_destroy(struct tda998x_priv *priv)
 {
 	/* disable all IRQs and free the IRQ handler */
@@ -1796,35 +1812,6 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv)
 	return ret;
 }
 
-static void tda998x_encoder_prepare(struct drm_encoder *encoder)
-{
-	tda998x_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
-}
-
-static void tda998x_encoder_commit(struct drm_encoder *encoder)
-{
-	tda998x_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
-}
-
-static const struct drm_encoder_helper_funcs tda998x_encoder_helper_funcs = {
-	.dpms = tda998x_encoder_dpms,
-	.prepare = tda998x_encoder_prepare,
-	.commit = tda998x_encoder_commit,
-	.mode_set = tda998x_encoder_mode_set,
-};
-
-static void tda998x_encoder_destroy(struct drm_encoder *encoder)
-{
-	struct tda998x_priv *priv = enc_to_tda998x_priv(encoder);
-
-	tda998x_destroy(priv);
-	drm_encoder_cleanup(encoder);
-}
-
-static const struct drm_encoder_funcs tda998x_encoder_funcs = {
-	.destroy = tda998x_encoder_destroy,
-};
-
 static void tda998x_set_config(struct tda998x_priv *priv,
 			       const struct tda998x_encoder_params *p)
 {
@@ -1882,9 +1869,7 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data)
 {
 	struct tda998x_encoder_params *params = dev->platform_data;
 	struct i2c_client *client = to_i2c_client(dev);
-	struct drm_device *drm = data;
 	struct tda998x_priv *priv;
-	u32 crtcs = 0;
 	int ret;
 
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -1893,16 +1878,6 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data)
 
 	dev_set_drvdata(dev, priv);
 
-	if (dev->of_node)
-		crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
-
-	/* If no CRTCs were found, fall back to our old behaviour */
-	if (crtcs == 0) {
-		dev_warn(dev, "Falling back to first CRTC\n");
-		crtcs = 1 << 0;
-	}
-
-	priv->encoder.possible_crtcs = crtcs;
 	priv->audio_params.config = BIT(2);
 	priv->audio_params.format = AFMT_SPDIF;
 	priv->audio_params.sample_rate = 44100;
@@ -1925,23 +1900,12 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data)
 	if (!dev->of_node && params)
 		tda998x_set_config(priv, params);
 
-	drm_encoder_helper_add(&priv->encoder, &tda998x_encoder_helper_funcs);
-	ret = drm_encoder_init(drm, &priv->encoder, &tda998x_encoder_funcs,
-			       DRM_MODE_ENCODER_TMDS, NULL);
-	if (ret)
-		goto err_encoder;
+	priv->bridge.funcs = &tda998x_bridge_funcs;
+	priv->bridge.of_node = dev->of_node;
 
-	ret = tda998x_connector_init(priv, drm);
-	if (ret)
-		goto err_connector;
+	drm_bridge_add(&priv->bridge);
 
 	return 0;
-
-err_connector:
-	drm_encoder_cleanup(&priv->encoder);
-err_encoder:
-	tda998x_destroy(priv);
-	return ret;
 }
 
 static void tda998x_unbind(struct device *dev, struct device *master,
@@ -1950,7 +1914,7 @@ static void tda998x_unbind(struct device *dev, struct device *master,
 	struct tda998x_priv *priv = dev_get_drvdata(dev);
 
 	drm_connector_cleanup(&priv->connector);
-	drm_encoder_cleanup(&priv->encoder);
+	drm_bridge_remove(&priv->bridge);
 	tda998x_destroy(priv);
 }
 


-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up

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

* Re: [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
  2018-04-20 11:38         ` jacopo mondi
@ 2018-04-20 12:55           ` Peter Rosin
  -1 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-20 12:55 UTC (permalink / raw)
  To: jacopo mondi
  Cc: Laurent Pinchart, linux-kernel, David Airlie, Rob Herring,
	Mark Rutland, Nicolas Ferre, Alexandre Belloni, Boris Brezillon,
	Daniel Vetter, Gustavo Padovan, Sean Paul, Russell King,
	Jacopo Mondi, dri-devel, devicetree, linux-arm-kernel

On 2018-04-20 13:38, jacopo mondi wrote:
> Hi Peter,
> 
> On Fri, Apr 20, 2018 at 01:05:21PM +0200, Peter Rosin wrote:
>> On 2018-04-20 12:18, Laurent Pinchart wrote:
>>> Hello,
>>>
>>> On Friday, 20 April 2018 11:52:35 EEST jacopo mondi wrote:
>>>> Hi Peter,
>>>>     I've been a bit a pain in the arse for you recently, but please
>>>> bear with me a bit more, and sorry for jumping late on the band wagon.
>>>>
>>>> On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
>>>>> Hi!
>>>>>
>>>>> I naively thought that since there was support for both nxp,tda19988 (in
>>>>> the tda998x driver) and the atmel-hlcdc, things would be a smooth ride.
>>>>> But it wasn't, so I started looking around and realized I had to fix
>>>>> things.
>>>>>
>>>>> In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
>>>>> component, but now in v3 I fix things by making the tda998x driver
>>>>> a bridge instead. This was after a suggestion from Boris Brezillion
>>
>> That should be Brezillon, sorry for being sloppy with the spelling.
>>
>>>>> (the atmel-hlcdc maintainer), so there was some risk of bias ... but
>>>>> after comparing what was needed, I too find the bridge approach better.
>>>>>
>>>>> In addition to the above, our PCB interface between the SAMA5D3 and the
>>>>> HDMI encoder is only using 16 bits, and this has to be described
>>>>> somewhere, or the atmel-hlcdc driver have no chance of selecting the
>>>>> correct output mode. Since I have similar problems with a ds90c185 lvds
>>>>> encoder I added patches to override the atmel-hlcdc output format via
>>>>> DT properties compatible with the media video-interface binding and
>>>>> things start to play together.
>>>>>
>>>>> Since this series superseeds the bridge series [1], I have included the
>>>>> leftover bindings patch for the ti,ds90c185 here.
>>>>
>>>> I feel like this series would look better if it would make use of the
>>>> proposed bridge media bus format support I have recently sent out [1]
>>>> (and which was not there when you first sent v1).
>>>>
>>>> I understand your fundamental problem here is that the bus format
>>>> that should be reported by your bridge is different from the ones
>>>> actually supported by the TDA19988 chip, as the wirings ground some
>>>> of the input pins.
>>>>
>>>> Although this is defintely something that could be described in the
>>>> bridge's own OF node with the 'bus_width' property, and what I would do,
>>>> now that you have made a bridge out from the tda19988 driver, is:
>>>>
>>>> 1) Set the bridge accepted input bus_format parsing its pin
>>>> configuration, or default it if that's not implemented yet.
>>>> This will likely be rgb888. You can do that using the trivial
>>>> support for bridge input image formats implemented by my series.
>>>> 2) Specify in the bridge endpoint a 'bus_width' of <16>
>>>> 3) In your atmel-hlcd get both the image format of the bridge (rgb888)
>>>> and parse the remote endpoint property 'bus_width' and get the <16>
>>>> value back.
>>>
>>> Parsing properties of remote nodes should be avoided as much as possible, as
>>> they need to be interpreted in the context of the DT bindings related to the
>>> compatible string applicable to that node. I'd rather have the bus_width
>>> property in the local endpoint node.
>>
>> In addition to that, my view of this binding
>>
>> 	endpoint {
>> 		bus-type = <0>;
> 
> bus-type is used by v4l2_fwnode helpers to decide which type of bus
> they're dealing with iirc. Here it seems to me it has no added
> value, also because in your bindings description "it shall be 0" and
> it is not parsed anywhere in you code, but no big deal....

bus-type is indeed parsed and verified to be zero which means auto-detect
according to the video-interfaces binding. An auto-detect bus-type with
a given bus-width means a parallel interface IIUC.

>From patch 3/7:

	if (of_property_read_u32(node, "bus-type", &bus_type))
		return 0;
	if (bus_type != 0)
		return -EINVAL;


>> 		bus-widht = <16>;
>> 	};
>>
>> is that it always means rgb565. See further below.
>>
>>>> 4) Set the correct format in the atmel hlcd driver to accommodate a
>>>> bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
>>>> or are there other possible combinations I am missing?)
>>>>
>>>> I would consider this better mostly because in this series you are
>>>> creating a semantic for the whole DRM subsystem on the 'bus_width'
>>>> property, where numerical values as '12', '16' etc are arbitrary tied
>>>> to the selection of a media bus format. At least you should use a
>>>> common set of defines [1] between the device tree and the driver,
>>>> but this looks anyway fragile imho.
>>>
>>> This I agree with though. Combining the remote bus format with the local bus
>>> width should fix the problem without having to parse remote properties.
>>
>> My thinking was that the binding with bus-type = <0> and bus-width = <bpp>
>> would mean a parallel bus (type 0 means auto-detect and with a bus-width that
>> auto-detect means a parallel bus) and the most natural/common interpretation
>> of that bus-width. For bus widths of 12, 16, 18, 24, 30 etc I think that
>> would be rgb444, rgb565, rgb666, rgb888, rgb101010 (or, I'm first so I get
>> to define the default). If you have some other interpretation of a bus with
>> that width, you'd need to extend the video-interface binding with some way
>> of saying what you need, perhaps using some kind of data mapping or something
>> to say e.g. bgr666. And you'd need some kind of indicator if you have YUV
>> signals instead of RGB, and LVDS isn't a completely parallel bus, so you'd
>> need something for that. Etc.
> 
> The fundamental issue here is that you're tying the bus with to an
> image format. Why <16> can't be, say, MEDIA_BUS_FMT_YVYU8_1X16? it
> spans to 16 bits, doesn't it? And I'm sorry but the 'I'm first so I
> get to define defaults' argument doesn't apply here.

I never said that <16> could not be something YUV. I said that <16> without
any further information is RGB. But you are right, the fundamental issue
is that I want to specify the full format in the endpoint node, while you
do not for some reason I don't understand. And maybe saying that "<16>
without more info is RGB" is too presumptuous, but then I think that the
right fix is adding something clearly indicating RGB is the way to go, so
that there is a way for endpoints to specify RGB565 (or whatever is needed).

> So, it is my opinion you need to expose an image format somewhere. And
> it is my opinion again, which can be very wrong ofc, that this place
> is the bridge driver.

I don't see why the input side is better than the output side when it
comes to specifying these details? The input side is as likely to have
different options as the output side.

> You need to adjust the output to accommodate wirings? You can use the
> bus_width on the hlcd side, as Laurent suggested, but the bus width
> does not tie to any image format at all, even more if you're making
> that decision in a drm-wide function.
> 
>>
>> Because the word from Rob was that there should be one common binding that
>> describes video interfaces. I started an implementation that interprets that
>> binding in a drm context in
>> [PATCH 3/7] drm: of: introduce drm_of_media_bus_fmt
> 
> As usual, one should try to reuse as much as possible of the existing
> bindings. That's a totally different thing compared to assign to a bus
> width property an associated image format for the whole DRM subsystem
> 
> ot: those properties should be moved outside of
> media/video_interfaces.txt sooner or later, to a more generic place...
> 
>>
>> With that view, any input format specification of the bridge is not helpful
>> for me since what the bridge specifies (without help) is going to be wrong
> 
> No it's not useless. I can have an encoder that can provide both YUV
> and RGB formats. If your bridge accepts RGB I want to know that, and
> the bus_width is unrelated imho.

I didn't say useless *period*, I said not helpful *for me*. What I mean is
that since I have an encoder that can only output RGB formats, asking the
bridge if it expects RGB is rather useless. It adds nothing whatsoever.

Cheers,
Peter

>> anyway. End result, I need to specify the format manually on either the
>> bridge or the atmel-hlcdc side, and I happen to think that the correct side
>> is with the atmel-hlcdc, because that is where my issue originates. In short,
>> the "drm: bridge: Add support for static image formats" series is unrelated
>> as far as I can tell.
> 
> I may be biased on this, so I let other to judge and provide more
> suggestions.
> 
> Thanks
>    j
> 

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

* [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
@ 2018-04-20 12:55           ` Peter Rosin
  0 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-20 12:55 UTC (permalink / raw)
  To: linux-arm-kernel

On 2018-04-20 13:38, jacopo mondi wrote:
> Hi Peter,
> 
> On Fri, Apr 20, 2018 at 01:05:21PM +0200, Peter Rosin wrote:
>> On 2018-04-20 12:18, Laurent Pinchart wrote:
>>> Hello,
>>>
>>> On Friday, 20 April 2018 11:52:35 EEST jacopo mondi wrote:
>>>> Hi Peter,
>>>>     I've been a bit a pain in the arse for you recently, but please
>>>> bear with me a bit more, and sorry for jumping late on the band wagon.
>>>>
>>>> On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
>>>>> Hi!
>>>>>
>>>>> I naively thought that since there was support for both nxp,tda19988 (in
>>>>> the tda998x driver) and the atmel-hlcdc, things would be a smooth ride.
>>>>> But it wasn't, so I started looking around and realized I had to fix
>>>>> things.
>>>>>
>>>>> In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
>>>>> component, but now in v3 I fix things by making the tda998x driver
>>>>> a bridge instead. This was after a suggestion from Boris Brezillion
>>
>> That should be Brezillon, sorry for being sloppy with the spelling.
>>
>>>>> (the atmel-hlcdc maintainer), so there was some risk of bias ... but
>>>>> after comparing what was needed, I too find the bridge approach better.
>>>>>
>>>>> In addition to the above, our PCB interface between the SAMA5D3 and the
>>>>> HDMI encoder is only using 16 bits, and this has to be described
>>>>> somewhere, or the atmel-hlcdc driver have no chance of selecting the
>>>>> correct output mode. Since I have similar problems with a ds90c185 lvds
>>>>> encoder I added patches to override the atmel-hlcdc output format via
>>>>> DT properties compatible with the media video-interface binding and
>>>>> things start to play together.
>>>>>
>>>>> Since this series superseeds the bridge series [1], I have included the
>>>>> leftover bindings patch for the ti,ds90c185 here.
>>>>
>>>> I feel like this series would look better if it would make use of the
>>>> proposed bridge media bus format support I have recently sent out [1]
>>>> (and which was not there when you first sent v1).
>>>>
>>>> I understand your fundamental problem here is that the bus format
>>>> that should be reported by your bridge is different from the ones
>>>> actually supported by the TDA19988 chip, as the wirings ground some
>>>> of the input pins.
>>>>
>>>> Although this is defintely something that could be described in the
>>>> bridge's own OF node with the 'bus_width' property, and what I would do,
>>>> now that you have made a bridge out from the tda19988 driver, is:
>>>>
>>>> 1) Set the bridge accepted input bus_format parsing its pin
>>>> configuration, or default it if that's not implemented yet.
>>>> This will likely be rgb888. You can do that using the trivial
>>>> support for bridge input image formats implemented by my series.
>>>> 2) Specify in the bridge endpoint a 'bus_width' of <16>
>>>> 3) In your atmel-hlcd get both the image format of the bridge (rgb888)
>>>> and parse the remote endpoint property 'bus_width' and get the <16>
>>>> value back.
>>>
>>> Parsing properties of remote nodes should be avoided as much as possible, as
>>> they need to be interpreted in the context of the DT bindings related to the
>>> compatible string applicable to that node. I'd rather have the bus_width
>>> property in the local endpoint node.
>>
>> In addition to that, my view of this binding
>>
>> 	endpoint {
>> 		bus-type = <0>;
> 
> bus-type is used by v4l2_fwnode helpers to decide which type of bus
> they're dealing with iirc. Here it seems to me it has no added
> value, also because in your bindings description "it shall be 0" and
> it is not parsed anywhere in you code, but no big deal....

bus-type is indeed parsed and verified to be zero which means auto-detect
according to the video-interfaces binding. An auto-detect bus-type with
a given bus-width means a parallel interface IIUC.

>From patch 3/7:

	if (of_property_read_u32(node, "bus-type", &bus_type))
		return 0;
	if (bus_type != 0)
		return -EINVAL;


>> 		bus-widht = <16>;
>> 	};
>>
>> is that it always means rgb565. See further below.
>>
>>>> 4) Set the correct format in the atmel hlcd driver to accommodate a
>>>> bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
>>>> or are there other possible combinations I am missing?)
>>>>
>>>> I would consider this better mostly because in this series you are
>>>> creating a semantic for the whole DRM subsystem on the 'bus_width'
>>>> property, where numerical values as '12', '16' etc are arbitrary tied
>>>> to the selection of a media bus format. At least you should use a
>>>> common set of defines [1] between the device tree and the driver,
>>>> but this looks anyway fragile imho.
>>>
>>> This I agree with though. Combining the remote bus format with the local bus
>>> width should fix the problem without having to parse remote properties.
>>
>> My thinking was that the binding with bus-type = <0> and bus-width = <bpp>
>> would mean a parallel bus (type 0 means auto-detect and with a bus-width that
>> auto-detect means a parallel bus) and the most natural/common interpretation
>> of that bus-width. For bus widths of 12, 16, 18, 24, 30 etc I think that
>> would be rgb444, rgb565, rgb666, rgb888, rgb101010 (or, I'm first so I get
>> to define the default). If you have some other interpretation of a bus with
>> that width, you'd need to extend the video-interface binding with some way
>> of saying what you need, perhaps using some kind of data mapping or something
>> to say e.g. bgr666. And you'd need some kind of indicator if you have YUV
>> signals instead of RGB, and LVDS isn't a completely parallel bus, so you'd
>> need something for that. Etc.
> 
> The fundamental issue here is that you're tying the bus with to an
> image format. Why <16> can't be, say, MEDIA_BUS_FMT_YVYU8_1X16? it
> spans to 16 bits, doesn't it? And I'm sorry but the 'I'm first so I
> get to define defaults' argument doesn't apply here.

I never said that <16> could not be something YUV. I said that <16> without
any further information is RGB. But you are right, the fundamental issue
is that I want to specify the full format in the endpoint node, while you
do not for some reason I don't understand. And maybe saying that "<16>
without more info is RGB" is too presumptuous, but then I think that the
right fix is adding something clearly indicating RGB is the way to go, so
that there is a way for endpoints to specify RGB565 (or whatever is needed).

> So, it is my opinion you need to expose an image format somewhere. And
> it is my opinion again, which can be very wrong ofc, that this place
> is the bridge driver.

I don't see why the input side is better than the output side when it
comes to specifying these details? The input side is as likely to have
different options as the output side.

> You need to adjust the output to accommodate wirings? You can use the
> bus_width on the hlcd side, as Laurent suggested, but the bus width
> does not tie to any image format at all, even more if you're making
> that decision in a drm-wide function.
> 
>>
>> Because the word from Rob was that there should be one common binding that
>> describes video interfaces. I started an implementation that interprets that
>> binding in a drm context in
>> [PATCH 3/7] drm: of: introduce drm_of_media_bus_fmt
> 
> As usual, one should try to reuse as much as possible of the existing
> bindings. That's a totally different thing compared to assign to a bus
> width property an associated image format for the whole DRM subsystem
> 
> ot: those properties should be moved outside of
> media/video_interfaces.txt sooner or later, to a more generic place...
> 
>>
>> With that view, any input format specification of the bridge is not helpful
>> for me since what the bridge specifies (without help) is going to be wrong
> 
> No it's not useless. I can have an encoder that can provide both YUV
> and RGB formats. If your bridge accepts RGB I want to know that, and
> the bus_width is unrelated imho.

I didn't say useless *period*, I said not helpful *for me*. What I mean is
that since I have an encoder that can only output RGB formats, asking the
bridge if it expects RGB is rather useless. It adds nothing whatsoever.

Cheers,
Peter

>> anyway. End result, I need to specify the format manually on either the
>> bridge or the atmel-hlcdc side, and I happen to think that the correct side
>> is with the atmel-hlcdc, because that is where my issue originates. In short,
>> the "drm: bridge: Add support for static image formats" series is unrelated
>> as far as I can tell.
> 
> I may be biased on this, so I let other to judge and provide more
> suggestions.
> 
> Thanks
>    j
> 

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

* Re: [PATCH v3 7/7] drm/i2c: tda998x: register as a drm bridge
  2018-04-20 10:53         ` Russell King - ARM Linux
@ 2018-04-20 13:09           ` Peter Rosin
  -1 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-20 13:09 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: kbuild test robot, kbuild-all, linux-kernel, David Airlie,
	Rob Herring, Mark Rutland, Nicolas Ferre, Alexandre Belloni,
	Boris Brezillon, Daniel Vetter, Gustavo Padovan, Sean Paul,
	Laurent Pinchart, Jacopo Mondi, dri-devel, devicetree,
	linux-arm-kernel

On 2018-04-20 12:53, Russell King - ARM Linux wrote:
> On Fri, Apr 20, 2018 at 12:49:42PM +0200, Peter Rosin wrote:
>> On 2018-04-20 12:41, kbuild test robot wrote:
>>> Hi Peter,
>>>
>>> I love your patch! Yet something to improve:
>>
>> Yup, right you are!
>>
>>> [auto build test ERROR on drm/drm-next]
>>> [also build test ERROR on v4.17-rc1 next-20180420]
>>> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>>>
>>> url:    https://github.com/0day-ci/linux/commits/Peter-Rosin/Add-tda998x-HDMI-support-to-atmel-hlcdc/20180420-160131
>>> base:   git://people.freedesktop.org/~airlied/linux.git drm-next
>>> config: i386-randconfig-a0-201815 (attached as .config)
>>> compiler: gcc-4.9 (Debian 4.9.4-2) 4.9.4
>>> reproduce:
>>>         # save the attached .config to linux build tree
>>>         make ARCH=i386 
>>>
>>> All errors (new ones prefixed by >>):
>>>
>>>    drivers/gpu/drm/i2c/tda998x_drv.c: In function 'tda998x_probe':
>>>>> drivers/gpu/drm/i2c/tda998x_drv.c:1859:16: error: 'struct drm_bridge' has no member named 'of_node'
>>>      bridge->bridge.of_node = dev->of_node;
>>>                    ^
>>
>> Anybody got a better fix than this?
>>
>> #ifdef CONFIG_OF
>> 	bridge->bridge.of_node = dev->of_node;
>> #endif
> 
> How about the bridge code provides a helper to do this, something like:
> 
> static inline void bridge_set_device(struct drm_bridge *bridge,
> 				     struct device *dev)
> {
> #ifdef CONFIG_OF
> 	bridge->of_node = dev->of_node;
> #endif
> }
> 
> which (a) nicely hides the firmware flavour, and (b) hides the ifdef in
> the bridge header where it belongs.  If the bridge code needs to be
> converted to fwnode in the future, at least this would be abstracted
> from the drivers.
> 

Hmm, I looked around and found numerous other #ifdefs for this, so my plan
is to just add one more. Fixing up all these ifdefs is orthogonal and can
be done later.

Cheers,
Peter

PS. I also noted that I had forgotten to remove a couple of dev_info calls
in this patch. Will remove for v4.

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

* [PATCH v3 7/7] drm/i2c: tda998x: register as a drm bridge
@ 2018-04-20 13:09           ` Peter Rosin
  0 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-20 13:09 UTC (permalink / raw)
  To: linux-arm-kernel

On 2018-04-20 12:53, Russell King - ARM Linux wrote:
> On Fri, Apr 20, 2018 at 12:49:42PM +0200, Peter Rosin wrote:
>> On 2018-04-20 12:41, kbuild test robot wrote:
>>> Hi Peter,
>>>
>>> I love your patch! Yet something to improve:
>>
>> Yup, right you are!
>>
>>> [auto build test ERROR on drm/drm-next]
>>> [also build test ERROR on v4.17-rc1 next-20180420]
>>> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>>>
>>> url:    https://github.com/0day-ci/linux/commits/Peter-Rosin/Add-tda998x-HDMI-support-to-atmel-hlcdc/20180420-160131
>>> base:   git://people.freedesktop.org/~airlied/linux.git drm-next
>>> config: i386-randconfig-a0-201815 (attached as .config)
>>> compiler: gcc-4.9 (Debian 4.9.4-2) 4.9.4
>>> reproduce:
>>>         # save the attached .config to linux build tree
>>>         make ARCH=i386 
>>>
>>> All errors (new ones prefixed by >>):
>>>
>>>    drivers/gpu/drm/i2c/tda998x_drv.c: In function 'tda998x_probe':
>>>>> drivers/gpu/drm/i2c/tda998x_drv.c:1859:16: error: 'struct drm_bridge' has no member named 'of_node'
>>>      bridge->bridge.of_node = dev->of_node;
>>>                    ^
>>
>> Anybody got a better fix than this?
>>
>> #ifdef CONFIG_OF
>> 	bridge->bridge.of_node = dev->of_node;
>> #endif
> 
> How about the bridge code provides a helper to do this, something like:
> 
> static inline void bridge_set_device(struct drm_bridge *bridge,
> 				     struct device *dev)
> {
> #ifdef CONFIG_OF
> 	bridge->of_node = dev->of_node;
> #endif
> }
> 
> which (a) nicely hides the firmware flavour, and (b) hides the ifdef in
> the bridge header where it belongs.  If the bridge code needs to be
> converted to fwnode in the future, at least this would be abstracted
> from the drivers.
> 

Hmm, I looked around and found numerous other #ifdefs for this, so my plan
is to just add one more. Fixing up all these ifdefs is orthogonal and can
be done later.

Cheers,
Peter

PS. I also noted that I had forgotten to remove a couple of dev_info calls
in this patch. Will remove for v4.

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

* Re: [PATCH v3 7/7] drm/i2c: tda998x: register as a drm bridge
  2018-04-20 10:24       ` Russell King - ARM Linux
@ 2018-04-20 13:28         ` Peter Rosin
  -1 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-20 13:28 UTC (permalink / raw)
  To: Russell King - ARM Linux, Laurent Pinchart
  Cc: dri-devel, Mark Rutland, Boris Brezillon, Alexandre Belloni,
	devicetree, David Airlie, linux-kernel, Rob Herring,
	Jacopo Mondi, Daniel Vetter, linux-arm-kernel

On 2018-04-20 12:24, Russell King - ARM Linux wrote:
> On Fri, Apr 20, 2018 at 01:06:49PM +0300, Laurent Pinchart wrote:
>> Hi Peter,
>>
>> Thank you for the patch.
>>
>> On Thursday, 19 April 2018 19:27:51 EEST Peter Rosin wrote:
>>> This makes this driver work with all(?) drivers that are not
>>> componentized and instead expect to connect to a panel/bridge. That
>>> said, the only one tested is atmel_hlcdc.
>>>
>>> This hooks the relevant work function previously called by the encoder
>>> and the component also to the bridge, since the encoder goes away when
>>> connecting to the bridge interface of the driver and the equivalent of
>>> bind/unbind of the component is handled by bridge attach/detach.
>>>
>>> The lifetime requirements of a bridge and a component are slightly
>>> different, which is the reason for struct tda998x_bridge.
>>
>> Couldn't you move the allocation and initialization (tda998x_create) of the 
>> tda998x_priv structure to probe time ? I think you wouldn't need a separate 
>> structure in that case. Unless I'm mistaken there would be an added benefit of 
>> separating component and bridge initialization, resulting in the encoder not 
>> being initialized at all if the component isn't used. You wouldn't need to add 
>> a local_encoder parameter to the tda998x_init() function.
> 
> No, I don't like that idea one bit, as I've stated in the past about the
> component API.  The same (probably) goes for the bridge stuff too.
> 
> Consider the following:
> 
> Your DRM system is initialised.  You then remove a module, which results
> in the DRM system being torn down.  You re-insert the module (eg, having
> made a change to it).  The DRM system is then re-initialised.
> 
> At this point, what is the state of variables such as priv->is_on if
> you allocate the structure at probe time?
> 
> What about all the other variables in the driver private structure - are
> you sure that the driver can cope with random values from the previous
> "usage" remaining there?
> 
> At the moment, this isn't a concern for the driver because we
> dev_kzalloc() the structure in the bind callback.  Move that to the
> probe function, and the structure is no longer re-initialised each
> time, and so it retains the previous state.  The driver is not setup
> to cope with that.
> 
> So, to work around that, you would need to reinitialise _everything_
> in the structure that the driver requires, which IMHO is a very
> open to bugs (eg, if a member is missed, or added without the
> necessary re-initialisation), _especially_ when this is not a path
> that will get regular testing.
> 
> If you want to do this for a subset of data, it would be much better
> to separate them into independent structures (maybe one embedded into
> the other) so that this problem can not occur.  That way, a subset
> of the data can be memset() when bound to the rest of the DRM system
> ensuring a consistent driver state and still achieve what you're
> suggesting.

This was the exact reason I added struct tda998x_bridge. It seemed
very risky to move the tda998x_create call (or some of its meat) to
the probe function. Even if that could be done I think it should
definitely be a separate patch.

Cheers,
Peter

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

* [PATCH v3 7/7] drm/i2c: tda998x: register as a drm bridge
@ 2018-04-20 13:28         ` Peter Rosin
  0 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-20 13:28 UTC (permalink / raw)
  To: linux-arm-kernel

On 2018-04-20 12:24, Russell King - ARM Linux wrote:
> On Fri, Apr 20, 2018 at 01:06:49PM +0300, Laurent Pinchart wrote:
>> Hi Peter,
>>
>> Thank you for the patch.
>>
>> On Thursday, 19 April 2018 19:27:51 EEST Peter Rosin wrote:
>>> This makes this driver work with all(?) drivers that are not
>>> componentized and instead expect to connect to a panel/bridge. That
>>> said, the only one tested is atmel_hlcdc.
>>>
>>> This hooks the relevant work function previously called by the encoder
>>> and the component also to the bridge, since the encoder goes away when
>>> connecting to the bridge interface of the driver and the equivalent of
>>> bind/unbind of the component is handled by bridge attach/detach.
>>>
>>> The lifetime requirements of a bridge and a component are slightly
>>> different, which is the reason for struct tda998x_bridge.
>>
>> Couldn't you move the allocation and initialization (tda998x_create) of the 
>> tda998x_priv structure to probe time ? I think you wouldn't need a separate 
>> structure in that case. Unless I'm mistaken there would be an added benefit of 
>> separating component and bridge initialization, resulting in the encoder not 
>> being initialized at all if the component isn't used. You wouldn't need to add 
>> a local_encoder parameter to the tda998x_init() function.
> 
> No, I don't like that idea one bit, as I've stated in the past about the
> component API.  The same (probably) goes for the bridge stuff too.
> 
> Consider the following:
> 
> Your DRM system is initialised.  You then remove a module, which results
> in the DRM system being torn down.  You re-insert the module (eg, having
> made a change to it).  The DRM system is then re-initialised.
> 
> At this point, what is the state of variables such as priv->is_on if
> you allocate the structure at probe time?
> 
> What about all the other variables in the driver private structure - are
> you sure that the driver can cope with random values from the previous
> "usage" remaining there?
> 
> At the moment, this isn't a concern for the driver because we
> dev_kzalloc() the structure in the bind callback.  Move that to the
> probe function, and the structure is no longer re-initialised each
> time, and so it retains the previous state.  The driver is not setup
> to cope with that.
> 
> So, to work around that, you would need to reinitialise _everything_
> in the structure that the driver requires, which IMHO is a very
> open to bugs (eg, if a member is missed, or added without the
> necessary re-initialisation), _especially_ when this is not a path
> that will get regular testing.
> 
> If you want to do this for a subset of data, it would be much better
> to separate them into independent structures (maybe one embedded into
> the other) so that this problem can not occur.  That way, a subset
> of the data can be memset() when bound to the rest of the DRM system
> ensuring a consistent driver state and still achieve what you're
> suggesting.

This was the exact reason I added struct tda998x_bridge. It seemed
very risky to move the tda998x_create call (or some of its meat) to
the probe function. Even if that could be done I think it should
definitely be a separate patch.

Cheers,
Peter

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

* Re: [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
  2018-04-20 11:22       ` jacopo mondi
  (?)
@ 2018-04-21  8:20         ` Laurent Pinchart
  -1 siblings, 0 replies; 67+ messages in thread
From: Laurent Pinchart @ 2018-04-21  8:20 UTC (permalink / raw)
  To: jacopo mondi
  Cc: Peter Rosin, linux-kernel, David Airlie, Rob Herring,
	Mark Rutland, Nicolas Ferre, Alexandre Belloni, Boris Brezillon,
	Daniel Vetter, Gustavo Padovan, Sean Paul, Russell King,
	Jacopo Mondi, dri-devel, devicetree, linux-arm-kernel

Hi Jacopo,

On Friday, 20 April 2018 14:22:04 EEST jacopo mondi wrote:
> On Fri, Apr 20, 2018 at 01:18:13PM +0300, Laurent Pinchart wrote:
> > On Friday, 20 April 2018 11:52:35 EEST jacopo mondi wrote:
> > > Hi Peter,
> > > 
> > > I've been a bit a pain in the arse for you recently, but please
> > > bear with me a bit more, and sorry for jumping late on the band wagon.
> > > 
> > > On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
> > > > Hi!
> > > > 
> > > > I naively thought that since there was support for both nxp,tda19988
> > > > (in the tda998x driver) and the atmel-hlcdc, things would be a smooth
> > > > ride. But it wasn't, so I started looking around and realized I had to
> > > > fix things.
> > > > 
> > > > In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
> > > > component, but now in v3 I fix things by making the tda998x driver
> > > > a bridge instead. This was after a suggestion from Boris Brezillion
> > > > (the atmel-hlcdc maintainer), so there was some risk of bias ... but
> > > > after comparing what was needed, I too find the bridge approach
> > > > better.
> > > > 
> > > > In addition to the above, our PCB interface between the SAMA5D3 and
> > > > the HDMI encoder is only using 16 bits, and this has to be described
> > > > somewhere, or the atmel-hlcdc driver have no chance of selecting the
> > > > correct output mode. Since I have similar problems with a ds90c185
> > > > lvds encoder I added patches to override the atmel-hlcdc output format
> > > > via DT properties compatible with the media video-interface binding
> > > > and things start to play together.
> > > > 
> > > > Since this series superseeds the bridge series [1], I have included
> > > > the leftover bindings patch for the ti,ds90c185 here.
> > > 
> > > I feel like this series would look better if it would make use of the
> > > proposed bridge media bus format support I have recently sent out [1]
> > > (and which was not there when you first sent v1).
> > > 
> > > I understand your fundamental problem here is that the bus format
> > > that should be reported by your bridge is different from the ones
> > > actually supported by the TDA19988 chip, as the wirings ground some
> > > of the input pins.
> > > 
> > > Although this is defintely something that could be described in the
> > > bridge's own OF node with the 'bus_width' property, and what I would do,
> > > now that you have made a bridge out from the tda19988 driver, is:
> > > 
> > > 1) Set the bridge accepted input bus_format parsing its pin
> > > configuration, or default it if that's not implemented yet.
> > > This will likely be rgb888. You can do that using the trivial
> > > support for bridge input image formats implemented by my series.
> > > 2) Specify in the bridge endpoint a 'bus_width' of <16>
> > > 3) In your atmel-hlcd get both the image format of the bridge (rgb888)
> > > and parse the remote endpoint property 'bus_width' and get the <16>
> > > value back.
> > 
> > Parsing properties of remote nodes should be avoided as much as possible,
> > as they need to be interpreted in the context of the DT bindings related
> > to the compatible string applicable to that node. I'd rather have the
> > bus_width property in the local endpoint node.
> 
> Right, I see...
> Well, in Peter's case, the bus width, being a consequence of
> wirings, can be described safely in both endpoints, right?

If we look at it from the endpoints' point of view, the display controller has 
to output a 16-bit format, and the HDMI encoder receives a 24-bit format. The 
conversion is due to PCB wiring so there's no DT node to describe that. I thus 
believe the right description to be bus-width = <16> on the display controller 
side, and bus-width = <24> on the HDMI encoder side.

This being said, even if the bus-width property was set to 16 on both sides, 
what I frown upon is parsing a property of the HDMI encoder DT node in the 
display controller driver.

> > > 4) Set the correct format in the atmel hlcd driver to accommodate a
> > > bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
> > > or are there other possible combinations I am missing?)
> > > 
> > > I would consider this better mostly because in this series you are
> > > creating a semantic for the whole DRM subsystem on the 'bus_width'
> > > property, where numerical values as '12', '16' etc are arbitrary tied
> > > to the selection of a media bus format. At least you should use a
> > > common set of defines [1] between the device tree and the driver,
> > > but this looks anyway fragile imho.
> > 
> > This I agree with though. Combining the remote bus format with the local
> > bus width should fix the problem without having to parse remote
> > properties.
> > 
> > > Have I maybe missed some parts of the problem you are trying to solve
> > > here?
> > > 
> > > [1] drm: bridge: Add support for static image formats
> > > 
> > >     https://lwn.net/Articles/752296/
> > > 
> > > [2] include/uapi/linux/media-bus-format.h
> > > 
> > > > Anyway, this series solves some real issues for my HW.
> > > > 
> > > > Changes since v2   https://lkml.org/lkml/2018/4/17/385
> > > > - patch 2/7 fixed spelling and added an example
> > > > - patch 4/7 parse the DT up front and store the result indexed by
> > > > encoder
> > > > - old patch 5/6 and 6/6 dropped
> > > > - patch 5-7/7 are new and makes the tda998x driver a drm_bridge
> > > > 
> > > > Changes since v1   https://lkml.org/lkml/2018/4/9/294
> > > > - added reviewed-by from Rob to patch 1/6
> > > > - patch 2/6 changed so that the bus format override is in the endpoint
> > > > 
> > > >   DT node, and follows the binding of media video-interfaces.
> > > > 
> > > > - patch 3/6 is new, it adds drm_of_media_bus_fmt which parses above
> > > > 
> > > >   media video-interface binding (partially).
> > > > 
> > > > - patch 4/6 now makes use of the above helper (and also fixes problems
> > > > 
> > > >   with the 3/5 patch from v1 when no override was specified).
> > > > 
> > > > - do not mention unrelated connector display_info details in the cover
> > > > 
> > > >   letter and commit messages.
> > > > 
> > > > [1]
> > > > "Bridge" series v2   https://lkml.org/lkml/2018/3/26/610
> > > > "Bridge" series v1   https://lkml.org/lkml/2018/3/17/221
> > > > 
> > > > Peter Rosin (7):
> > > >   dt-bindings: display: bridge: lvds-transmitter: add ti,ds90c185
> > > >   dt-bindings: display: atmel: optional video-interface of endpoints
> > > >   drm: of: introduce drm_of_media_bus_fmt
> > > >   drm/atmel-hlcdc: support bus-width (12/16/18/24) in endpoint nodes
> > > >   drm/i2c: tda998x: find the drm_device via the drm_connector
> > > >   drm/i2c: tda998x: split encoder and component functions from the
> > > >   work
> > > >   drm/i2c: tda998x: register as a drm bridge
> > > >  
> > > >  .../devicetree/bindings/display/atmel/hlcdc-dc.txt |  26 +++
> > > >  .../bindings/display/bridge/lvds-transmitter.txt   |   8 +-
> > > >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c     |  71 ++++++--
> > > >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h       |   2 +
> > > >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c   |  40 +++-
> > > >  drivers/gpu/drm/drm_of.c                           |  38 ++++
> > > >  drivers/gpu/drm/i2c/tda998x_drv.c                  | 201 ++++++++++--
> > > >  include/drm/drm_of.h                               |   7 +
> > > >  8 files changed, 342 insertions(+), 51 deletions(-)

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
@ 2018-04-21  8:20         ` Laurent Pinchart
  0 siblings, 0 replies; 67+ messages in thread
From: Laurent Pinchart @ 2018-04-21  8:20 UTC (permalink / raw)
  To: jacopo mondi
  Cc: Mark Rutland, Boris Brezillon, Alexandre Belloni, devicetree,
	David Airlie, Nicolas Ferre, dri-devel, linux-kernel,
	Rob Herring, Jacopo Mondi, Daniel Vetter, Peter Rosin,
	Russell King, linux-arm-kernel

Hi Jacopo,

On Friday, 20 April 2018 14:22:04 EEST jacopo mondi wrote:
> On Fri, Apr 20, 2018 at 01:18:13PM +0300, Laurent Pinchart wrote:
> > On Friday, 20 April 2018 11:52:35 EEST jacopo mondi wrote:
> > > Hi Peter,
> > > 
> > > I've been a bit a pain in the arse for you recently, but please
> > > bear with me a bit more, and sorry for jumping late on the band wagon.
> > > 
> > > On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
> > > > Hi!
> > > > 
> > > > I naively thought that since there was support for both nxp,tda19988
> > > > (in the tda998x driver) and the atmel-hlcdc, things would be a smooth
> > > > ride. But it wasn't, so I started looking around and realized I had to
> > > > fix things.
> > > > 
> > > > In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
> > > > component, but now in v3 I fix things by making the tda998x driver
> > > > a bridge instead. This was after a suggestion from Boris Brezillion
> > > > (the atmel-hlcdc maintainer), so there was some risk of bias ... but
> > > > after comparing what was needed, I too find the bridge approach
> > > > better.
> > > > 
> > > > In addition to the above, our PCB interface between the SAMA5D3 and
> > > > the HDMI encoder is only using 16 bits, and this has to be described
> > > > somewhere, or the atmel-hlcdc driver have no chance of selecting the
> > > > correct output mode. Since I have similar problems with a ds90c185
> > > > lvds encoder I added patches to override the atmel-hlcdc output format
> > > > via DT properties compatible with the media video-interface binding
> > > > and things start to play together.
> > > > 
> > > > Since this series superseeds the bridge series [1], I have included
> > > > the leftover bindings patch for the ti,ds90c185 here.
> > > 
> > > I feel like this series would look better if it would make use of the
> > > proposed bridge media bus format support I have recently sent out [1]
> > > (and which was not there when you first sent v1).
> > > 
> > > I understand your fundamental problem here is that the bus format
> > > that should be reported by your bridge is different from the ones
> > > actually supported by the TDA19988 chip, as the wirings ground some
> > > of the input pins.
> > > 
> > > Although this is defintely something that could be described in the
> > > bridge's own OF node with the 'bus_width' property, and what I would do,
> > > now that you have made a bridge out from the tda19988 driver, is:
> > > 
> > > 1) Set the bridge accepted input bus_format parsing its pin
> > > configuration, or default it if that's not implemented yet.
> > > This will likely be rgb888. You can do that using the trivial
> > > support for bridge input image formats implemented by my series.
> > > 2) Specify in the bridge endpoint a 'bus_width' of <16>
> > > 3) In your atmel-hlcd get both the image format of the bridge (rgb888)
> > > and parse the remote endpoint property 'bus_width' and get the <16>
> > > value back.
> > 
> > Parsing properties of remote nodes should be avoided as much as possible,
> > as they need to be interpreted in the context of the DT bindings related
> > to the compatible string applicable to that node. I'd rather have the
> > bus_width property in the local endpoint node.
> 
> Right, I see...
> Well, in Peter's case, the bus width, being a consequence of
> wirings, can be described safely in both endpoints, right?

If we look at it from the endpoints' point of view, the display controller has 
to output a 16-bit format, and the HDMI encoder receives a 24-bit format. The 
conversion is due to PCB wiring so there's no DT node to describe that. I thus 
believe the right description to be bus-width = <16> on the display controller 
side, and bus-width = <24> on the HDMI encoder side.

This being said, even if the bus-width property was set to 16 on both sides, 
what I frown upon is parsing a property of the HDMI encoder DT node in the 
display controller driver.

> > > 4) Set the correct format in the atmel hlcd driver to accommodate a
> > > bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
> > > or are there other possible combinations I am missing?)
> > > 
> > > I would consider this better mostly because in this series you are
> > > creating a semantic for the whole DRM subsystem on the 'bus_width'
> > > property, where numerical values as '12', '16' etc are arbitrary tied
> > > to the selection of a media bus format. At least you should use a
> > > common set of defines [1] between the device tree and the driver,
> > > but this looks anyway fragile imho.
> > 
> > This I agree with though. Combining the remote bus format with the local
> > bus width should fix the problem without having to parse remote
> > properties.
> > 
> > > Have I maybe missed some parts of the problem you are trying to solve
> > > here?
> > > 
> > > [1] drm: bridge: Add support for static image formats
> > > 
> > >     https://lwn.net/Articles/752296/
> > > 
> > > [2] include/uapi/linux/media-bus-format.h
> > > 
> > > > Anyway, this series solves some real issues for my HW.
> > > > 
> > > > Changes since v2   https://lkml.org/lkml/2018/4/17/385
> > > > - patch 2/7 fixed spelling and added an example
> > > > - patch 4/7 parse the DT up front and store the result indexed by
> > > > encoder
> > > > - old patch 5/6 and 6/6 dropped
> > > > - patch 5-7/7 are new and makes the tda998x driver a drm_bridge
> > > > 
> > > > Changes since v1   https://lkml.org/lkml/2018/4/9/294
> > > > - added reviewed-by from Rob to patch 1/6
> > > > - patch 2/6 changed so that the bus format override is in the endpoint
> > > > 
> > > >   DT node, and follows the binding of media video-interfaces.
> > > > 
> > > > - patch 3/6 is new, it adds drm_of_media_bus_fmt which parses above
> > > > 
> > > >   media video-interface binding (partially).
> > > > 
> > > > - patch 4/6 now makes use of the above helper (and also fixes problems
> > > > 
> > > >   with the 3/5 patch from v1 when no override was specified).
> > > > 
> > > > - do not mention unrelated connector display_info details in the cover
> > > > 
> > > >   letter and commit messages.
> > > > 
> > > > [1]
> > > > "Bridge" series v2   https://lkml.org/lkml/2018/3/26/610
> > > > "Bridge" series v1   https://lkml.org/lkml/2018/3/17/221
> > > > 
> > > > Peter Rosin (7):
> > > >   dt-bindings: display: bridge: lvds-transmitter: add ti,ds90c185
> > > >   dt-bindings: display: atmel: optional video-interface of endpoints
> > > >   drm: of: introduce drm_of_media_bus_fmt
> > > >   drm/atmel-hlcdc: support bus-width (12/16/18/24) in endpoint nodes
> > > >   drm/i2c: tda998x: find the drm_device via the drm_connector
> > > >   drm/i2c: tda998x: split encoder and component functions from the
> > > >   work
> > > >   drm/i2c: tda998x: register as a drm bridge
> > > >  
> > > >  .../devicetree/bindings/display/atmel/hlcdc-dc.txt |  26 +++
> > > >  .../bindings/display/bridge/lvds-transmitter.txt   |   8 +-
> > > >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c     |  71 ++++++--
> > > >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h       |   2 +
> > > >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c   |  40 +++-
> > > >  drivers/gpu/drm/drm_of.c                           |  38 ++++
> > > >  drivers/gpu/drm/i2c/tda998x_drv.c                  | 201 ++++++++++--
> > > >  include/drm/drm_of.h                               |   7 +
> > > >  8 files changed, 342 insertions(+), 51 deletions(-)

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

* [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
@ 2018-04-21  8:20         ` Laurent Pinchart
  0 siblings, 0 replies; 67+ messages in thread
From: Laurent Pinchart @ 2018-04-21  8:20 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Jacopo,

On Friday, 20 April 2018 14:22:04 EEST jacopo mondi wrote:
> On Fri, Apr 20, 2018 at 01:18:13PM +0300, Laurent Pinchart wrote:
> > On Friday, 20 April 2018 11:52:35 EEST jacopo mondi wrote:
> > > Hi Peter,
> > > 
> > > I've been a bit a pain in the arse for you recently, but please
> > > bear with me a bit more, and sorry for jumping late on the band wagon.
> > > 
> > > On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
> > > > Hi!
> > > > 
> > > > I naively thought that since there was support for both nxp,tda19988
> > > > (in the tda998x driver) and the atmel-hlcdc, things would be a smooth
> > > > ride. But it wasn't, so I started looking around and realized I had to
> > > > fix things.
> > > > 
> > > > In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
> > > > component, but now in v3 I fix things by making the tda998x driver
> > > > a bridge instead. This was after a suggestion from Boris Brezillion
> > > > (the atmel-hlcdc maintainer), so there was some risk of bias ... but
> > > > after comparing what was needed, I too find the bridge approach
> > > > better.
> > > > 
> > > > In addition to the above, our PCB interface between the SAMA5D3 and
> > > > the HDMI encoder is only using 16 bits, and this has to be described
> > > > somewhere, or the atmel-hlcdc driver have no chance of selecting the
> > > > correct output mode. Since I have similar problems with a ds90c185
> > > > lvds encoder I added patches to override the atmel-hlcdc output format
> > > > via DT properties compatible with the media video-interface binding
> > > > and things start to play together.
> > > > 
> > > > Since this series superseeds the bridge series [1], I have included
> > > > the leftover bindings patch for the ti,ds90c185 here.
> > > 
> > > I feel like this series would look better if it would make use of the
> > > proposed bridge media bus format support I have recently sent out [1]
> > > (and which was not there when you first sent v1).
> > > 
> > > I understand your fundamental problem here is that the bus format
> > > that should be reported by your bridge is different from the ones
> > > actually supported by the TDA19988 chip, as the wirings ground some
> > > of the input pins.
> > > 
> > > Although this is defintely something that could be described in the
> > > bridge's own OF node with the 'bus_width' property, and what I would do,
> > > now that you have made a bridge out from the tda19988 driver, is:
> > > 
> > > 1) Set the bridge accepted input bus_format parsing its pin
> > > configuration, or default it if that's not implemented yet.
> > > This will likely be rgb888. You can do that using the trivial
> > > support for bridge input image formats implemented by my series.
> > > 2) Specify in the bridge endpoint a 'bus_width' of <16>
> > > 3) In your atmel-hlcd get both the image format of the bridge (rgb888)
> > > and parse the remote endpoint property 'bus_width' and get the <16>
> > > value back.
> > 
> > Parsing properties of remote nodes should be avoided as much as possible,
> > as they need to be interpreted in the context of the DT bindings related
> > to the compatible string applicable to that node. I'd rather have the
> > bus_width property in the local endpoint node.
> 
> Right, I see...
> Well, in Peter's case, the bus width, being a consequence of
> wirings, can be described safely in both endpoints, right?

If we look at it from the endpoints' point of view, the display controller has 
to output a 16-bit format, and the HDMI encoder receives a 24-bit format. The 
conversion is due to PCB wiring so there's no DT node to describe that. I thus 
believe the right description to be bus-width = <16> on the display controller 
side, and bus-width = <24> on the HDMI encoder side.

This being said, even if the bus-width property was set to 16 on both sides, 
what I frown upon is parsing a property of the HDMI encoder DT node in the 
display controller driver.

> > > 4) Set the correct format in the atmel hlcd driver to accommodate a
> > > bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
> > > or are there other possible combinations I am missing?)
> > > 
> > > I would consider this better mostly because in this series you are
> > > creating a semantic for the whole DRM subsystem on the 'bus_width'
> > > property, where numerical values as '12', '16' etc are arbitrary tied
> > > to the selection of a media bus format. At least you should use a
> > > common set of defines [1] between the device tree and the driver,
> > > but this looks anyway fragile imho.
> > 
> > This I agree with though. Combining the remote bus format with the local
> > bus width should fix the problem without having to parse remote
> > properties.
> > 
> > > Have I maybe missed some parts of the problem you are trying to solve
> > > here?
> > > 
> > > [1] drm: bridge: Add support for static image formats
> > > 
> > >     https://lwn.net/Articles/752296/
> > > 
> > > [2] include/uapi/linux/media-bus-format.h
> > > 
> > > > Anyway, this series solves some real issues for my HW.
> > > > 
> > > > Changes since v2   https://lkml.org/lkml/2018/4/17/385
> > > > - patch 2/7 fixed spelling and added an example
> > > > - patch 4/7 parse the DT up front and store the result indexed by
> > > > encoder
> > > > - old patch 5/6 and 6/6 dropped
> > > > - patch 5-7/7 are new and makes the tda998x driver a drm_bridge
> > > > 
> > > > Changes since v1   https://lkml.org/lkml/2018/4/9/294
> > > > - added reviewed-by from Rob to patch 1/6
> > > > - patch 2/6 changed so that the bus format override is in the endpoint
> > > > 
> > > >   DT node, and follows the binding of media video-interfaces.
> > > > 
> > > > - patch 3/6 is new, it adds drm_of_media_bus_fmt which parses above
> > > > 
> > > >   media video-interface binding (partially).
> > > > 
> > > > - patch 4/6 now makes use of the above helper (and also fixes problems
> > > > 
> > > >   with the 3/5 patch from v1 when no override was specified).
> > > > 
> > > > - do not mention unrelated connector display_info details in the cover
> > > > 
> > > >   letter and commit messages.
> > > > 
> > > > [1]
> > > > "Bridge" series v2   https://lkml.org/lkml/2018/3/26/610
> > > > "Bridge" series v1   https://lkml.org/lkml/2018/3/17/221
> > > > 
> > > > Peter Rosin (7):
> > > >   dt-bindings: display: bridge: lvds-transmitter: add ti,ds90c185
> > > >   dt-bindings: display: atmel: optional video-interface of endpoints
> > > >   drm: of: introduce drm_of_media_bus_fmt
> > > >   drm/atmel-hlcdc: support bus-width (12/16/18/24) in endpoint nodes
> > > >   drm/i2c: tda998x: find the drm_device via the drm_connector
> > > >   drm/i2c: tda998x: split encoder and component functions from the
> > > >   work
> > > >   drm/i2c: tda998x: register as a drm bridge
> > > >  
> > > >  .../devicetree/bindings/display/atmel/hlcdc-dc.txt |  26 +++
> > > >  .../bindings/display/bridge/lvds-transmitter.txt   |   8 +-
> > > >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c     |  71 ++++++--
> > > >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h       |   2 +
> > > >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c   |  40 +++-
> > > >  drivers/gpu/drm/drm_of.c                           |  38 ++++
> > > >  drivers/gpu/drm/i2c/tda998x_drv.c                  | 201 ++++++++++--
> > > >  include/drm/drm_of.h                               |   7 +
> > > >  8 files changed, 342 insertions(+), 51 deletions(-)

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
  2018-04-20 12:55           ` Peter Rosin
  (?)
@ 2018-04-21  8:38             ` Laurent Pinchart
  -1 siblings, 0 replies; 67+ messages in thread
From: Laurent Pinchart @ 2018-04-21  8:38 UTC (permalink / raw)
  To: Peter Rosin
  Cc: jacopo mondi, linux-kernel, David Airlie, Rob Herring,
	Mark Rutland, Nicolas Ferre, Alexandre Belloni, Boris Brezillon,
	Daniel Vetter, Gustavo Padovan, Sean Paul, Russell King,
	Jacopo Mondi, dri-devel, devicetree, linux-arm-kernel

Hi Peter,

On Friday, 20 April 2018 15:55:50 EEST Peter Rosin wrote:
> On 2018-04-20 13:38, jacopo mondi wrote:
> > On Fri, Apr 20, 2018 at 01:05:21PM +0200, Peter Rosin wrote:
> >> On 2018-04-20 12:18, Laurent Pinchart wrote:
> >>> On Friday, 20 April 2018 11:52:35 EEST jacopo mondi wrote:
> >>>> Hi Peter,
> >>>> 
> >>>> I've been a bit a pain in the arse for you recently, but please
> >>>> bear with me a bit more, and sorry for jumping late on the band wagon.
> >>>> 
> >>>> On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
> >>>>> Hi!
> >>>>> 
> >>>>> I naively thought that since there was support for both nxp,tda19988
> >>>>> (in the tda998x driver) and the atmel-hlcdc, things would be a smooth
> >>>>> ride. But it wasn't, so I started looking around and realized I had to
> >>>>> fix things.
> >>>>> 
> >>>>> In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
> >>>>> component, but now in v3 I fix things by making the tda998x driver
> >>>>> a bridge instead. This was after a suggestion from Boris Brezillion
> >> 
> >> That should be Brezillon, sorry for being sloppy with the spelling.
> >> 
> >>>>> (the atmel-hlcdc maintainer), so there was some risk of bias ... but
> >>>>> after comparing what was needed, I too find the bridge approach
> >>>>> better.
> >>>>> 
> >>>>> In addition to the above, our PCB interface between the SAMA5D3 and
> >>>>> the HDMI encoder is only using 16 bits, and this has to be described
> >>>>> somewhere, or the atmel-hlcdc driver have no chance of selecting the
> >>>>> correct output mode. Since I have similar problems with a ds90c185
> >>>>> lvds encoder I added patches to override the atmel-hlcdc output format
> >>>>> via DT properties compatible with the media video-interface binding
> >>>>> and things start to play together.
> >>>>> 
> >>>>> Since this series superseeds the bridge series [1], I have included
> >>>>> the leftover bindings patch for the ti,ds90c185 here.
> >>>> 
> >>>> I feel like this series would look better if it would make use of the
> >>>> proposed bridge media bus format support I have recently sent out [1]
> >>>> (and which was not there when you first sent v1).
> >>>> 
> >>>> I understand your fundamental problem here is that the bus format
> >>>> that should be reported by your bridge is different from the ones
> >>>> actually supported by the TDA19988 chip, as the wirings ground some
> >>>> of the input pins.
> >>>> 
> >>>> Although this is defintely something that could be described in the
> >>>> bridge's own OF node with the 'bus_width' property, and what I would
> >>>> do, now that you have made a bridge out from the tda19988 driver, is:
> >>>> 
> >>>> 1) Set the bridge accepted input bus_format parsing its pin
> >>>> configuration, or default it if that's not implemented yet.
> >>>> This will likely be rgb888. You can do that using the trivial
> >>>> support for bridge input image formats implemented by my series.
> >>>> 2) Specify in the bridge endpoint a 'bus_width' of <16>
> >>>> 3) In your atmel-hlcd get both the image format of the bridge (rgb888)
> >>>> and parse the remote endpoint property 'bus_width' and get the <16>
> >>>> value back.
> >>> 
> >>> Parsing properties of remote nodes should be avoided as much as
> >>> possible, as they need to be interpreted in the context of the DT
> >>> bindings related to the compatible string applicable to that node. I'd
> >>> rather have the bus_width property in the local endpoint node.
> >> 
> >> In addition to that, my view of this binding
> >> 
> >> 	endpoint {
> >> 		bus-type = <0>;
> > 
> > bus-type is used by v4l2_fwnode helpers to decide which type of bus
> > they're dealing with iirc. Here it seems to me it has no added
> > value, also because in your bindings description "it shall be 0" and
> > it is not parsed anywhere in you code, but no big deal....
> 
> bus-type is indeed parsed and verified to be zero which means auto-detect
> according to the video-interfaces binding. An auto-detect bus-type with
> a given bus-width means a parallel interface IIUC.

I believe you could leave it out though. Your display controller only supports 
parallel buses, so there's no need to specify the bus type explicitly.

> From patch 3/7:
> 
> 	if (of_property_read_u32(node, "bus-type", &bus_type))
> 		return 0;
> 	if (bus_type != 0)
> 		return -EINVAL;
> 
> >> 		bus-widht = <16>;
> >> 	};
> >> 
> >> is that it always means rgb565. See further below.
> >> 
> >>>> 4) Set the correct format in the atmel hlcd driver to accommodate a
> >>>> bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
> >>>> or are there other possible combinations I am missing?)
> >>>> 
> >>>> I would consider this better mostly because in this series you are
> >>>> creating a semantic for the whole DRM subsystem on the 'bus_width'
> >>>> property, where numerical values as '12', '16' etc are arbitrary tied
> >>>> to the selection of a media bus format. At least you should use a
> >>>> common set of defines [1] between the device tree and the driver,
> >>>> but this looks anyway fragile imho.
> >>> 
> >>> This I agree with though. Combining the remote bus format with the local
> >>> bus width should fix the problem without having to parse remote
> >>> properties.
> >> 
> >> My thinking was that the binding with bus-type = <0> and bus-width =
> >> <bpp> would mean a parallel bus (type 0 means auto-detect and with a bus-
> >> width that auto-detect means a parallel bus) and the most natural/common
> >> interpretation of that bus-width. For bus widths of 12, 16, 18, 24, 30
> >> etc I think that would be rgb444, rgb565, rgb666, rgb888, rgb101010 (or,
> >> I'm first so I get to define the default). If you have some other
> >> interpretation of a bus with that width, you'd need to extend the
> >> video-interface binding with some way of saying what you need, perhaps
> >> using some kind of data mapping or something to say e.g. bgr666. And
> >> you'd need some kind of indicator if you have YUV signals instead of
> >> RGB, and LVDS isn't a completely parallel bus, so you'd need something
> >> for that. Etc.
> > 
> > The fundamental issue here is that you're tying the bus with to an
> > image format. Why <16> can't be, say, MEDIA_BUS_FMT_YVYU8_1X16? it
> > spans to 16 bits, doesn't it? And I'm sorry but the 'I'm first so I
> > get to define defaults' argument doesn't apply here.
> 
> I never said that <16> could not be something YUV. I said that <16> without
> any further information is RGB. But you are right, the fundamental issue
> is that I want to specify the full format in the endpoint node, while you
> do not for some reason I don't understand. And maybe saying that "<16>
> without more info is RGB" is too presumptuous, but then I think that the
> right fix is adding something clearly indicating RGB is the way to go, so
> that there is a way for endpoints to specify RGB565 (or whatever is needed).

I think that would lack genericity though. I could easily imagine a setup 
similar to yours where the bridge can accept different types of parallel 
formats (RGB, BGR, YUV, ...). While the bus width is a property of the PCB 
routing and is thus fixed, the format wouldn't be a property of the platform 
but would be dynamic. I believe that combining the bus-width DT property that 
carries static platform information with the dynamic format reported by the 
bridge (through the API proposed by Jacopo) would then be a more generic 
approach.

You don't have to depend on Jacopo's patch series though, I would be totally 
fine with assuming that a 16-bit width means RGB565 in the atmel-hlcdc driver. 
What I'm not comfortable with is hardcoding that assumption in the helper 
defined in patch 3/7. I would thus propose moving that code to the atmel-hlcdc 
driver for now, and creating a generic helper that uses both bus-width and the 
format queried from the bridge when Jacopo's series makes it to mainline. 
Would that be an acceptable approach for you ?

> > So, it is my opinion you need to expose an image format somewhere. And
> > it is my opinion again, which can be very wrong ofc, that this place
> > is the bridge driver.
> 
> I don't see why the input side is better than the output side when it
> comes to specifying these details? The input side is as likely to have
> different options as the output side.

DRM/KMS is built upon a sink to source model, where userspace specifies the 
format on the connector at the output of a pipeline, and the formats along the 
chain of bridges are then computed automatically. That's why we usually query 
formats supported by sinks and configure sources accordingly.

> > You need to adjust the output to accommodate wirings? You can use the
> > bus_width on the hlcd side, as Laurent suggested, but the bus width
> > does not tie to any image format at all, even more if you're making
> > that decision in a drm-wide function.
> > 
> >> Because the word from Rob was that there should be one common binding
> >> that describes video interfaces. I started an implementation that
> >> interprets that binding in a drm context in
> >> [PATCH 3/7] drm: of: introduce drm_of_media_bus_fmt
> > 
> > As usual, one should try to reuse as much as possible of the existing
> > bindings. That's a totally different thing compared to assign to a bus
> > width property an associated image format for the whole DRM subsystem
> > 
> > ot: those properties should be moved outside of
> > media/video_interfaces.txt sooner or later, to a more generic place...
> > 
> >> With that view, any input format specification of the bridge is not
> >> helpful for me since what the bridge specifies (without help) is going to
> >> be wrong
> > 
> > No it's not useless. I can have an encoder that can provide both YUV
> > and RGB formats. If your bridge accepts RGB I want to know that, and
> > the bus_width is unrelated imho.
> 
> I didn't say useless *period*, I said not helpful *for me*. What I mean is
> that since I have an encoder that can only output RGB formats, asking the
> bridge if it expects RGB is rather useless. It adds nothing whatsoever.
> 
> >> anyway. End result, I need to specify the format manually on either the
> >> bridge or the atmel-hlcdc side, and I happen to think that the correct
> >> side
> >> is with the atmel-hlcdc, because that is where my issue originates. In
> >> short, the "drm: bridge: Add support for static image formats" series is
> >> unrelated as far as I can tell.
> > 
> > I may be biased on this, so I let other to judge and provide more
> > suggestions.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
@ 2018-04-21  8:38             ` Laurent Pinchart
  0 siblings, 0 replies; 67+ messages in thread
From: Laurent Pinchart @ 2018-04-21  8:38 UTC (permalink / raw)
  To: Peter Rosin
  Cc: Mark Rutland, Boris Brezillon, jacopo mondi, Alexandre Belloni,
	devicetree, David Airlie, linux-kernel, dri-devel, Nicolas Ferre,
	Rob Herring, Jacopo Mondi, Daniel Vetter, Russell King,
	linux-arm-kernel

Hi Peter,

On Friday, 20 April 2018 15:55:50 EEST Peter Rosin wrote:
> On 2018-04-20 13:38, jacopo mondi wrote:
> > On Fri, Apr 20, 2018 at 01:05:21PM +0200, Peter Rosin wrote:
> >> On 2018-04-20 12:18, Laurent Pinchart wrote:
> >>> On Friday, 20 April 2018 11:52:35 EEST jacopo mondi wrote:
> >>>> Hi Peter,
> >>>> 
> >>>> I've been a bit a pain in the arse for you recently, but please
> >>>> bear with me a bit more, and sorry for jumping late on the band wagon.
> >>>> 
> >>>> On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
> >>>>> Hi!
> >>>>> 
> >>>>> I naively thought that since there was support for both nxp,tda19988
> >>>>> (in the tda998x driver) and the atmel-hlcdc, things would be a smooth
> >>>>> ride. But it wasn't, so I started looking around and realized I had to
> >>>>> fix things.
> >>>>> 
> >>>>> In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
> >>>>> component, but now in v3 I fix things by making the tda998x driver
> >>>>> a bridge instead. This was after a suggestion from Boris Brezillion
> >> 
> >> That should be Brezillon, sorry for being sloppy with the spelling.
> >> 
> >>>>> (the atmel-hlcdc maintainer), so there was some risk of bias ... but
> >>>>> after comparing what was needed, I too find the bridge approach
> >>>>> better.
> >>>>> 
> >>>>> In addition to the above, our PCB interface between the SAMA5D3 and
> >>>>> the HDMI encoder is only using 16 bits, and this has to be described
> >>>>> somewhere, or the atmel-hlcdc driver have no chance of selecting the
> >>>>> correct output mode. Since I have similar problems with a ds90c185
> >>>>> lvds encoder I added patches to override the atmel-hlcdc output format
> >>>>> via DT properties compatible with the media video-interface binding
> >>>>> and things start to play together.
> >>>>> 
> >>>>> Since this series superseeds the bridge series [1], I have included
> >>>>> the leftover bindings patch for the ti,ds90c185 here.
> >>>> 
> >>>> I feel like this series would look better if it would make use of the
> >>>> proposed bridge media bus format support I have recently sent out [1]
> >>>> (and which was not there when you first sent v1).
> >>>> 
> >>>> I understand your fundamental problem here is that the bus format
> >>>> that should be reported by your bridge is different from the ones
> >>>> actually supported by the TDA19988 chip, as the wirings ground some
> >>>> of the input pins.
> >>>> 
> >>>> Although this is defintely something that could be described in the
> >>>> bridge's own OF node with the 'bus_width' property, and what I would
> >>>> do, now that you have made a bridge out from the tda19988 driver, is:
> >>>> 
> >>>> 1) Set the bridge accepted input bus_format parsing its pin
> >>>> configuration, or default it if that's not implemented yet.
> >>>> This will likely be rgb888. You can do that using the trivial
> >>>> support for bridge input image formats implemented by my series.
> >>>> 2) Specify in the bridge endpoint a 'bus_width' of <16>
> >>>> 3) In your atmel-hlcd get both the image format of the bridge (rgb888)
> >>>> and parse the remote endpoint property 'bus_width' and get the <16>
> >>>> value back.
> >>> 
> >>> Parsing properties of remote nodes should be avoided as much as
> >>> possible, as they need to be interpreted in the context of the DT
> >>> bindings related to the compatible string applicable to that node. I'd
> >>> rather have the bus_width property in the local endpoint node.
> >> 
> >> In addition to that, my view of this binding
> >> 
> >> 	endpoint {
> >> 		bus-type = <0>;
> > 
> > bus-type is used by v4l2_fwnode helpers to decide which type of bus
> > they're dealing with iirc. Here it seems to me it has no added
> > value, also because in your bindings description "it shall be 0" and
> > it is not parsed anywhere in you code, but no big deal....
> 
> bus-type is indeed parsed and verified to be zero which means auto-detect
> according to the video-interfaces binding. An auto-detect bus-type with
> a given bus-width means a parallel interface IIUC.

I believe you could leave it out though. Your display controller only supports 
parallel buses, so there's no need to specify the bus type explicitly.

> From patch 3/7:
> 
> 	if (of_property_read_u32(node, "bus-type", &bus_type))
> 		return 0;
> 	if (bus_type != 0)
> 		return -EINVAL;
> 
> >> 		bus-widht = <16>;
> >> 	};
> >> 
> >> is that it always means rgb565. See further below.
> >> 
> >>>> 4) Set the correct format in the atmel hlcd driver to accommodate a
> >>>> bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
> >>>> or are there other possible combinations I am missing?)
> >>>> 
> >>>> I would consider this better mostly because in this series you are
> >>>> creating a semantic for the whole DRM subsystem on the 'bus_width'
> >>>> property, where numerical values as '12', '16' etc are arbitrary tied
> >>>> to the selection of a media bus format. At least you should use a
> >>>> common set of defines [1] between the device tree and the driver,
> >>>> but this looks anyway fragile imho.
> >>> 
> >>> This I agree with though. Combining the remote bus format with the local
> >>> bus width should fix the problem without having to parse remote
> >>> properties.
> >> 
> >> My thinking was that the binding with bus-type = <0> and bus-width =
> >> <bpp> would mean a parallel bus (type 0 means auto-detect and with a bus-
> >> width that auto-detect means a parallel bus) and the most natural/common
> >> interpretation of that bus-width. For bus widths of 12, 16, 18, 24, 30
> >> etc I think that would be rgb444, rgb565, rgb666, rgb888, rgb101010 (or,
> >> I'm first so I get to define the default). If you have some other
> >> interpretation of a bus with that width, you'd need to extend the
> >> video-interface binding with some way of saying what you need, perhaps
> >> using some kind of data mapping or something to say e.g. bgr666. And
> >> you'd need some kind of indicator if you have YUV signals instead of
> >> RGB, and LVDS isn't a completely parallel bus, so you'd need something
> >> for that. Etc.
> > 
> > The fundamental issue here is that you're tying the bus with to an
> > image format. Why <16> can't be, say, MEDIA_BUS_FMT_YVYU8_1X16? it
> > spans to 16 bits, doesn't it? And I'm sorry but the 'I'm first so I
> > get to define defaults' argument doesn't apply here.
> 
> I never said that <16> could not be something YUV. I said that <16> without
> any further information is RGB. But you are right, the fundamental issue
> is that I want to specify the full format in the endpoint node, while you
> do not for some reason I don't understand. And maybe saying that "<16>
> without more info is RGB" is too presumptuous, but then I think that the
> right fix is adding something clearly indicating RGB is the way to go, so
> that there is a way for endpoints to specify RGB565 (or whatever is needed).

I think that would lack genericity though. I could easily imagine a setup 
similar to yours where the bridge can accept different types of parallel 
formats (RGB, BGR, YUV, ...). While the bus width is a property of the PCB 
routing and is thus fixed, the format wouldn't be a property of the platform 
but would be dynamic. I believe that combining the bus-width DT property that 
carries static platform information with the dynamic format reported by the 
bridge (through the API proposed by Jacopo) would then be a more generic 
approach.

You don't have to depend on Jacopo's patch series though, I would be totally 
fine with assuming that a 16-bit width means RGB565 in the atmel-hlcdc driver. 
What I'm not comfortable with is hardcoding that assumption in the helper 
defined in patch 3/7. I would thus propose moving that code to the atmel-hlcdc 
driver for now, and creating a generic helper that uses both bus-width and the 
format queried from the bridge when Jacopo's series makes it to mainline. 
Would that be an acceptable approach for you ?

> > So, it is my opinion you need to expose an image format somewhere. And
> > it is my opinion again, which can be very wrong ofc, that this place
> > is the bridge driver.
> 
> I don't see why the input side is better than the output side when it
> comes to specifying these details? The input side is as likely to have
> different options as the output side.

DRM/KMS is built upon a sink to source model, where userspace specifies the 
format on the connector at the output of a pipeline, and the formats along the 
chain of bridges are then computed automatically. That's why we usually query 
formats supported by sinks and configure sources accordingly.

> > You need to adjust the output to accommodate wirings? You can use the
> > bus_width on the hlcd side, as Laurent suggested, but the bus width
> > does not tie to any image format at all, even more if you're making
> > that decision in a drm-wide function.
> > 
> >> Because the word from Rob was that there should be one common binding
> >> that describes video interfaces. I started an implementation that
> >> interprets that binding in a drm context in
> >> [PATCH 3/7] drm: of: introduce drm_of_media_bus_fmt
> > 
> > As usual, one should try to reuse as much as possible of the existing
> > bindings. That's a totally different thing compared to assign to a bus
> > width property an associated image format for the whole DRM subsystem
> > 
> > ot: those properties should be moved outside of
> > media/video_interfaces.txt sooner or later, to a more generic place...
> > 
> >> With that view, any input format specification of the bridge is not
> >> helpful for me since what the bridge specifies (without help) is going to
> >> be wrong
> > 
> > No it's not useless. I can have an encoder that can provide both YUV
> > and RGB formats. If your bridge accepts RGB I want to know that, and
> > the bus_width is unrelated imho.
> 
> I didn't say useless *period*, I said not helpful *for me*. What I mean is
> that since I have an encoder that can only output RGB formats, asking the
> bridge if it expects RGB is rather useless. It adds nothing whatsoever.
> 
> >> anyway. End result, I need to specify the format manually on either the
> >> bridge or the atmel-hlcdc side, and I happen to think that the correct
> >> side
> >> is with the atmel-hlcdc, because that is where my issue originates. In
> >> short, the "drm: bridge: Add support for static image formats" series is
> >> unrelated as far as I can tell.
> > 
> > I may be biased on this, so I let other to judge and provide more
> > suggestions.

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

* [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
@ 2018-04-21  8:38             ` Laurent Pinchart
  0 siblings, 0 replies; 67+ messages in thread
From: Laurent Pinchart @ 2018-04-21  8:38 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Peter,

On Friday, 20 April 2018 15:55:50 EEST Peter Rosin wrote:
> On 2018-04-20 13:38, jacopo mondi wrote:
> > On Fri, Apr 20, 2018 at 01:05:21PM +0200, Peter Rosin wrote:
> >> On 2018-04-20 12:18, Laurent Pinchart wrote:
> >>> On Friday, 20 April 2018 11:52:35 EEST jacopo mondi wrote:
> >>>> Hi Peter,
> >>>> 
> >>>> I've been a bit a pain in the arse for you recently, but please
> >>>> bear with me a bit more, and sorry for jumping late on the band wagon.
> >>>> 
> >>>> On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
> >>>>> Hi!
> >>>>> 
> >>>>> I naively thought that since there was support for both nxp,tda19988
> >>>>> (in the tda998x driver) and the atmel-hlcdc, things would be a smooth
> >>>>> ride. But it wasn't, so I started looking around and realized I had to
> >>>>> fix things.
> >>>>> 
> >>>>> In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
> >>>>> component, but now in v3 I fix things by making the tda998x driver
> >>>>> a bridge instead. This was after a suggestion from Boris Brezillion
> >> 
> >> That should be Brezillon, sorry for being sloppy with the spelling.
> >> 
> >>>>> (the atmel-hlcdc maintainer), so there was some risk of bias ... but
> >>>>> after comparing what was needed, I too find the bridge approach
> >>>>> better.
> >>>>> 
> >>>>> In addition to the above, our PCB interface between the SAMA5D3 and
> >>>>> the HDMI encoder is only using 16 bits, and this has to be described
> >>>>> somewhere, or the atmel-hlcdc driver have no chance of selecting the
> >>>>> correct output mode. Since I have similar problems with a ds90c185
> >>>>> lvds encoder I added patches to override the atmel-hlcdc output format
> >>>>> via DT properties compatible with the media video-interface binding
> >>>>> and things start to play together.
> >>>>> 
> >>>>> Since this series superseeds the bridge series [1], I have included
> >>>>> the leftover bindings patch for the ti,ds90c185 here.
> >>>> 
> >>>> I feel like this series would look better if it would make use of the
> >>>> proposed bridge media bus format support I have recently sent out [1]
> >>>> (and which was not there when you first sent v1).
> >>>> 
> >>>> I understand your fundamental problem here is that the bus format
> >>>> that should be reported by your bridge is different from the ones
> >>>> actually supported by the TDA19988 chip, as the wirings ground some
> >>>> of the input pins.
> >>>> 
> >>>> Although this is defintely something that could be described in the
> >>>> bridge's own OF node with the 'bus_width' property, and what I would
> >>>> do, now that you have made a bridge out from the tda19988 driver, is:
> >>>> 
> >>>> 1) Set the bridge accepted input bus_format parsing its pin
> >>>> configuration, or default it if that's not implemented yet.
> >>>> This will likely be rgb888. You can do that using the trivial
> >>>> support for bridge input image formats implemented by my series.
> >>>> 2) Specify in the bridge endpoint a 'bus_width' of <16>
> >>>> 3) In your atmel-hlcd get both the image format of the bridge (rgb888)
> >>>> and parse the remote endpoint property 'bus_width' and get the <16>
> >>>> value back.
> >>> 
> >>> Parsing properties of remote nodes should be avoided as much as
> >>> possible, as they need to be interpreted in the context of the DT
> >>> bindings related to the compatible string applicable to that node. I'd
> >>> rather have the bus_width property in the local endpoint node.
> >> 
> >> In addition to that, my view of this binding
> >> 
> >> 	endpoint {
> >> 		bus-type = <0>;
> > 
> > bus-type is used by v4l2_fwnode helpers to decide which type of bus
> > they're dealing with iirc. Here it seems to me it has no added
> > value, also because in your bindings description "it shall be 0" and
> > it is not parsed anywhere in you code, but no big deal....
> 
> bus-type is indeed parsed and verified to be zero which means auto-detect
> according to the video-interfaces binding. An auto-detect bus-type with
> a given bus-width means a parallel interface IIUC.

I believe you could leave it out though. Your display controller only supports 
parallel buses, so there's no need to specify the bus type explicitly.

> From patch 3/7:
> 
> 	if (of_property_read_u32(node, "bus-type", &bus_type))
> 		return 0;
> 	if (bus_type != 0)
> 		return -EINVAL;
> 
> >> 		bus-widht = <16>;
> >> 	};
> >> 
> >> is that it always means rgb565. See further below.
> >> 
> >>>> 4) Set the correct format in the atmel hlcd driver to accommodate a
> >>>> bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
> >>>> or are there other possible combinations I am missing?)
> >>>> 
> >>>> I would consider this better mostly because in this series you are
> >>>> creating a semantic for the whole DRM subsystem on the 'bus_width'
> >>>> property, where numerical values as '12', '16' etc are arbitrary tied
> >>>> to the selection of a media bus format. At least you should use a
> >>>> common set of defines [1] between the device tree and the driver,
> >>>> but this looks anyway fragile imho.
> >>> 
> >>> This I agree with though. Combining the remote bus format with the local
> >>> bus width should fix the problem without having to parse remote
> >>> properties.
> >> 
> >> My thinking was that the binding with bus-type = <0> and bus-width =
> >> <bpp> would mean a parallel bus (type 0 means auto-detect and with a bus-
> >> width that auto-detect means a parallel bus) and the most natural/common
> >> interpretation of that bus-width. For bus widths of 12, 16, 18, 24, 30
> >> etc I think that would be rgb444, rgb565, rgb666, rgb888, rgb101010 (or,
> >> I'm first so I get to define the default). If you have some other
> >> interpretation of a bus with that width, you'd need to extend the
> >> video-interface binding with some way of saying what you need, perhaps
> >> using some kind of data mapping or something to say e.g. bgr666. And
> >> you'd need some kind of indicator if you have YUV signals instead of
> >> RGB, and LVDS isn't a completely parallel bus, so you'd need something
> >> for that. Etc.
> > 
> > The fundamental issue here is that you're tying the bus with to an
> > image format. Why <16> can't be, say, MEDIA_BUS_FMT_YVYU8_1X16? it
> > spans to 16 bits, doesn't it? And I'm sorry but the 'I'm first so I
> > get to define defaults' argument doesn't apply here.
> 
> I never said that <16> could not be something YUV. I said that <16> without
> any further information is RGB. But you are right, the fundamental issue
> is that I want to specify the full format in the endpoint node, while you
> do not for some reason I don't understand. And maybe saying that "<16>
> without more info is RGB" is too presumptuous, but then I think that the
> right fix is adding something clearly indicating RGB is the way to go, so
> that there is a way for endpoints to specify RGB565 (or whatever is needed).

I think that would lack genericity though. I could easily imagine a setup 
similar to yours where the bridge can accept different types of parallel 
formats (RGB, BGR, YUV, ...). While the bus width is a property of the PCB 
routing and is thus fixed, the format wouldn't be a property of the platform 
but would be dynamic. I believe that combining the bus-width DT property that 
carries static platform information with the dynamic format reported by the 
bridge (through the API proposed by Jacopo) would then be a more generic 
approach.

You don't have to depend on Jacopo's patch series though, I would be totally 
fine with assuming that a 16-bit width means RGB565 in the atmel-hlcdc driver. 
What I'm not comfortable with is hardcoding that assumption in the helper 
defined in patch 3/7. I would thus propose moving that code to the atmel-hlcdc 
driver for now, and creating a generic helper that uses both bus-width and the 
format queried from the bridge when Jacopo's series makes it to mainline. 
Would that be an acceptable approach for you ?

> > So, it is my opinion you need to expose an image format somewhere. And
> > it is my opinion again, which can be very wrong ofc, that this place
> > is the bridge driver.
> 
> I don't see why the input side is better than the output side when it
> comes to specifying these details? The input side is as likely to have
> different options as the output side.

DRM/KMS is built upon a sink to source model, where userspace specifies the 
format on the connector at the output of a pipeline, and the formats along the 
chain of bridges are then computed automatically. That's why we usually query 
formats supported by sinks and configure sources accordingly.

> > You need to adjust the output to accommodate wirings? You can use the
> > bus_width on the hlcd side, as Laurent suggested, but the bus width
> > does not tie to any image format at all, even more if you're making
> > that decision in a drm-wide function.
> > 
> >> Because the word from Rob was that there should be one common binding
> >> that describes video interfaces. I started an implementation that
> >> interprets that binding in a drm context in
> >> [PATCH 3/7] drm: of: introduce drm_of_media_bus_fmt
> > 
> > As usual, one should try to reuse as much as possible of the existing
> > bindings. That's a totally different thing compared to assign to a bus
> > width property an associated image format for the whole DRM subsystem
> > 
> > ot: those properties should be moved outside of
> > media/video_interfaces.txt sooner or later, to a more generic place...
> > 
> >> With that view, any input format specification of the bridge is not
> >> helpful for me since what the bridge specifies (without help) is going to
> >> be wrong
> > 
> > No it's not useless. I can have an encoder that can provide both YUV
> > and RGB formats. If your bridge accepts RGB I want to know that, and
> > the bus_width is unrelated imho.
> 
> I didn't say useless *period*, I said not helpful *for me*. What I mean is
> that since I have an encoder that can only output RGB formats, asking the
> bridge if it expects RGB is rather useless. It adds nothing whatsoever.
> 
> >> anyway. End result, I need to specify the format manually on either the
> >> bridge or the atmel-hlcdc side, and I happen to think that the correct
> >> side
> >> is with the atmel-hlcdc, because that is where my issue originates. In
> >> short, the "drm: bridge: Add support for static image formats" series is
> >> unrelated as far as I can tell.
> > 
> > I may be biased on this, so I let other to judge and provide more
> > suggestions.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
  2018-04-21  8:38             ` Laurent Pinchart
@ 2018-04-21 15:05               ` Peter Rosin
  -1 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-21 15:05 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: jacopo mondi, linux-kernel, David Airlie, Rob Herring,
	Mark Rutland, Nicolas Ferre, Alexandre Belloni, Boris Brezillon,
	Daniel Vetter, Gustavo Padovan, Sean Paul, Russell King,
	Jacopo Mondi, dri-devel, devicetree, linux-arm-kernel

On 2018-04-21 10:38, Laurent Pinchart wrote:
> Hi Peter,
> 
> On Friday, 20 April 2018 15:55:50 EEST Peter Rosin wrote:
>> On 2018-04-20 13:38, jacopo mondi wrote:
>>> On Fri, Apr 20, 2018 at 01:05:21PM +0200, Peter Rosin wrote:
>>>> On 2018-04-20 12:18, Laurent Pinchart wrote:
>>>>> On Friday, 20 April 2018 11:52:35 EEST jacopo mondi wrote:
>>>>>> Hi Peter,
>>>>>>
>>>>>> I've been a bit a pain in the arse for you recently, but please
>>>>>> bear with me a bit more, and sorry for jumping late on the band wagon.
>>>>>>
>>>>>> On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
>>>>>>> Hi!
>>>>>>>
>>>>>>> I naively thought that since there was support for both nxp,tda19988
>>>>>>> (in the tda998x driver) and the atmel-hlcdc, things would be a smooth
>>>>>>> ride. But it wasn't, so I started looking around and realized I had to
>>>>>>> fix things.
>>>>>>>
>>>>>>> In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
>>>>>>> component, but now in v3 I fix things by making the tda998x driver
>>>>>>> a bridge instead. This was after a suggestion from Boris Brezillion
>>>>
>>>> That should be Brezillon, sorry for being sloppy with the spelling.
>>>>
>>>>>>> (the atmel-hlcdc maintainer), so there was some risk of bias ... but
>>>>>>> after comparing what was needed, I too find the bridge approach
>>>>>>> better.
>>>>>>>
>>>>>>> In addition to the above, our PCB interface between the SAMA5D3 and
>>>>>>> the HDMI encoder is only using 16 bits, and this has to be described
>>>>>>> somewhere, or the atmel-hlcdc driver have no chance of selecting the
>>>>>>> correct output mode. Since I have similar problems with a ds90c185
>>>>>>> lvds encoder I added patches to override the atmel-hlcdc output format
>>>>>>> via DT properties compatible with the media video-interface binding
>>>>>>> and things start to play together.
>>>>>>>
>>>>>>> Since this series superseeds the bridge series [1], I have included
>>>>>>> the leftover bindings patch for the ti,ds90c185 here.
>>>>>>
>>>>>> I feel like this series would look better if it would make use of the
>>>>>> proposed bridge media bus format support I have recently sent out [1]
>>>>>> (and which was not there when you first sent v1).
>>>>>>
>>>>>> I understand your fundamental problem here is that the bus format
>>>>>> that should be reported by your bridge is different from the ones
>>>>>> actually supported by the TDA19988 chip, as the wirings ground some
>>>>>> of the input pins.
>>>>>>
>>>>>> Although this is defintely something that could be described in the
>>>>>> bridge's own OF node with the 'bus_width' property, and what I would
>>>>>> do, now that you have made a bridge out from the tda19988 driver, is:
>>>>>>
>>>>>> 1) Set the bridge accepted input bus_format parsing its pin
>>>>>> configuration, or default it if that's not implemented yet.
>>>>>> This will likely be rgb888. You can do that using the trivial
>>>>>> support for bridge input image formats implemented by my series.
>>>>>> 2) Specify in the bridge endpoint a 'bus_width' of <16>
>>>>>> 3) In your atmel-hlcd get both the image format of the bridge (rgb888)
>>>>>> and parse the remote endpoint property 'bus_width' and get the <16>
>>>>>> value back.
>>>>>
>>>>> Parsing properties of remote nodes should be avoided as much as
>>>>> possible, as they need to be interpreted in the context of the DT
>>>>> bindings related to the compatible string applicable to that node. I'd
>>>>> rather have the bus_width property in the local endpoint node.
>>>>
>>>> In addition to that, my view of this binding
>>>>
>>>> 	endpoint {
>>>> 		bus-type = <0>;
>>>
>>> bus-type is used by v4l2_fwnode helpers to decide which type of bus
>>> they're dealing with iirc. Here it seems to me it has no added
>>> value, also because in your bindings description "it shall be 0" and
>>> it is not parsed anywhere in you code, but no big deal....
>>
>> bus-type is indeed parsed and verified to be zero which means auto-detect
>> according to the video-interfaces binding. An auto-detect bus-type with
>> a given bus-width means a parallel interface IIUC.
> 
> I believe you could leave it out though. Your display controller only supports 
> parallel buses, so there's no need to specify the bus type explicitly.

You need it if you want to verify that you conform to the video-interfaces
binding. And that verification is only needed *if* we want to build upon
the drm_of_media_bus_fmt function so that it eventually support other formats.

Where I'm coming from is this discussion with Rob:
https://lkml.org/lkml/2018/4/9/286

I interpreted that as is seen in patch 2/7 and 3/7 in v3 (and v2). True,
I might have read too much into his desire to have something generic,
and that the generic bit only applied to the binding, but 2/7 and 3/7
was how I interpreted that conversation.

>> From patch 3/7:
>>
>> 	if (of_property_read_u32(node, "bus-type", &bus_type))
>> 		return 0;
>> 	if (bus_type != 0)
>> 		return -EINVAL;
>>
>>>> 		bus-widht = <16>;
>>>> 	};
>>>>
>>>> is that it always means rgb565. See further below.
>>>>
>>>>>> 4) Set the correct format in the atmel hlcd driver to accommodate a
>>>>>> bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
>>>>>> or are there other possible combinations I am missing?)
>>>>>>
>>>>>> I would consider this better mostly because in this series you are
>>>>>> creating a semantic for the whole DRM subsystem on the 'bus_width'
>>>>>> property, where numerical values as '12', '16' etc are arbitrary tied
>>>>>> to the selection of a media bus format. At least you should use a
>>>>>> common set of defines [1] between the device tree and the driver,
>>>>>> but this looks anyway fragile imho.
>>>>>
>>>>> This I agree with though. Combining the remote bus format with the local
>>>>> bus width should fix the problem without having to parse remote
>>>>> properties.
>>>>
>>>> My thinking was that the binding with bus-type = <0> and bus-width =
>>>> <bpp> would mean a parallel bus (type 0 means auto-detect and with a bus-
>>>> width that auto-detect means a parallel bus) and the most natural/common
>>>> interpretation of that bus-width. For bus widths of 12, 16, 18, 24, 30
>>>> etc I think that would be rgb444, rgb565, rgb666, rgb888, rgb101010 (or,
>>>> I'm first so I get to define the default). If you have some other
>>>> interpretation of a bus with that width, you'd need to extend the
>>>> video-interface binding with some way of saying what you need, perhaps
>>>> using some kind of data mapping or something to say e.g. bgr666. And
>>>> you'd need some kind of indicator if you have YUV signals instead of
>>>> RGB, and LVDS isn't a completely parallel bus, so you'd need something
>>>> for that. Etc.
>>>
>>> The fundamental issue here is that you're tying the bus with to an
>>> image format. Why <16> can't be, say, MEDIA_BUS_FMT_YVYU8_1X16? it
>>> spans to 16 bits, doesn't it? And I'm sorry but the 'I'm first so I
>>> get to define defaults' argument doesn't apply here.
>>
>> I never said that <16> could not be something YUV. I said that <16> without
>> any further information is RGB. But you are right, the fundamental issue
>> is that I want to specify the full format in the endpoint node, while you
>> do not for some reason I don't understand. And maybe saying that "<16>
>> without more info is RGB" is too presumptuous, but then I think that the
>> right fix is adding something clearly indicating RGB is the way to go, so
>> that there is a way for endpoints to specify RGB565 (or whatever is needed).
> 
> I think that would lack genericity though. I could easily imagine a setup 
> similar to yours where the bridge can accept different types of parallel 
> formats (RGB, BGR, YUV, ...). While the bus width is a property of the PCB 
> routing and is thus fixed, the format wouldn't be a property of the platform 
> but would be dynamic. I believe that combining the bus-width DT property that 
> carries static platform information with the dynamic format reported by the 
> bridge (through the API proposed by Jacopo) would then be a more generic 
> approach.

This is a valid argument.

> You don't have to depend on Jacopo's patch series though, I would be totally 
> fine with assuming that a 16-bit width means RGB565 in the atmel-hlcdc driver. 
> What I'm not comfortable with is hardcoding that assumption in the helper 
> defined in patch 3/7. I would thus propose moving that code to the atmel-hlcdc 
> driver for now, and creating a generic helper that uses both bus-width and the 
> format queried from the bridge when Jacopo's series makes it to mainline. 
> Would that be an acceptable approach for you ?

I just want something acceptable that lets me set a few bits in a damn
register to my liking, ok? :-)

I'll re-spin with the meat of drm_of_media_bus_fmt moved to a static
function in the atmel-hlcdc driver (and squashed with 4/7).

Cheers,
Peter

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

* [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc
@ 2018-04-21 15:05               ` Peter Rosin
  0 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-21 15:05 UTC (permalink / raw)
  To: linux-arm-kernel

On 2018-04-21 10:38, Laurent Pinchart wrote:
> Hi Peter,
> 
> On Friday, 20 April 2018 15:55:50 EEST Peter Rosin wrote:
>> On 2018-04-20 13:38, jacopo mondi wrote:
>>> On Fri, Apr 20, 2018 at 01:05:21PM +0200, Peter Rosin wrote:
>>>> On 2018-04-20 12:18, Laurent Pinchart wrote:
>>>>> On Friday, 20 April 2018 11:52:35 EEST jacopo mondi wrote:
>>>>>> Hi Peter,
>>>>>>
>>>>>> I've been a bit a pain in the arse for you recently, but please
>>>>>> bear with me a bit more, and sorry for jumping late on the band wagon.
>>>>>>
>>>>>> On Thu, Apr 19, 2018 at 06:27:44PM +0200, Peter Rosin wrote:
>>>>>>> Hi!
>>>>>>>
>>>>>>> I naively thought that since there was support for both nxp,tda19988
>>>>>>> (in the tda998x driver) and the atmel-hlcdc, things would be a smooth
>>>>>>> ride. But it wasn't, so I started looking around and realized I had to
>>>>>>> fix things.
>>>>>>>
>>>>>>> In v1 and v2 I fixed things by making the atmel-hlcdc driver a master
>>>>>>> component, but now in v3 I fix things by making the tda998x driver
>>>>>>> a bridge instead. This was after a suggestion from Boris Brezillion
>>>>
>>>> That should be Brezillon, sorry for being sloppy with the spelling.
>>>>
>>>>>>> (the atmel-hlcdc maintainer), so there was some risk of bias ... but
>>>>>>> after comparing what was needed, I too find the bridge approach
>>>>>>> better.
>>>>>>>
>>>>>>> In addition to the above, our PCB interface between the SAMA5D3 and
>>>>>>> the HDMI encoder is only using 16 bits, and this has to be described
>>>>>>> somewhere, or the atmel-hlcdc driver have no chance of selecting the
>>>>>>> correct output mode. Since I have similar problems with a ds90c185
>>>>>>> lvds encoder I added patches to override the atmel-hlcdc output format
>>>>>>> via DT properties compatible with the media video-interface binding
>>>>>>> and things start to play together.
>>>>>>>
>>>>>>> Since this series superseeds the bridge series [1], I have included
>>>>>>> the leftover bindings patch for the ti,ds90c185 here.
>>>>>>
>>>>>> I feel like this series would look better if it would make use of the
>>>>>> proposed bridge media bus format support I have recently sent out [1]
>>>>>> (and which was not there when you first sent v1).
>>>>>>
>>>>>> I understand your fundamental problem here is that the bus format
>>>>>> that should be reported by your bridge is different from the ones
>>>>>> actually supported by the TDA19988 chip, as the wirings ground some
>>>>>> of the input pins.
>>>>>>
>>>>>> Although this is defintely something that could be described in the
>>>>>> bridge's own OF node with the 'bus_width' property, and what I would
>>>>>> do, now that you have made a bridge out from the tda19988 driver, is:
>>>>>>
>>>>>> 1) Set the bridge accepted input bus_format parsing its pin
>>>>>> configuration, or default it if that's not implemented yet.
>>>>>> This will likely be rgb888. You can do that using the trivial
>>>>>> support for bridge input image formats implemented by my series.
>>>>>> 2) Specify in the bridge endpoint a 'bus_width' of <16>
>>>>>> 3) In your atmel-hlcd get both the image format of the bridge (rgb888)
>>>>>> and parse the remote endpoint property 'bus_width' and get the <16>
>>>>>> value back.
>>>>>
>>>>> Parsing properties of remote nodes should be avoided as much as
>>>>> possible, as they need to be interpreted in the context of the DT
>>>>> bindings related to the compatible string applicable to that node. I'd
>>>>> rather have the bus_width property in the local endpoint node.
>>>>
>>>> In addition to that, my view of this binding
>>>>
>>>> 	endpoint {
>>>> 		bus-type = <0>;
>>>
>>> bus-type is used by v4l2_fwnode helpers to decide which type of bus
>>> they're dealing with iirc. Here it seems to me it has no added
>>> value, also because in your bindings description "it shall be 0" and
>>> it is not parsed anywhere in you code, but no big deal....
>>
>> bus-type is indeed parsed and verified to be zero which means auto-detect
>> according to the video-interfaces binding. An auto-detect bus-type with
>> a given bus-width means a parallel interface IIUC.
> 
> I believe you could leave it out though. Your display controller only supports 
> parallel buses, so there's no need to specify the bus type explicitly.

You need it if you want to verify that you conform to the video-interfaces
binding. And that verification is only needed *if* we want to build upon
the drm_of_media_bus_fmt function so that it eventually support other formats.

Where I'm coming from is this discussion with Rob:
https://lkml.org/lkml/2018/4/9/286

I interpreted that as is seen in patch 2/7 and 3/7 in v3 (and v2). True,
I might have read too much into his desire to have something generic,
and that the generic bit only applied to the binding, but 2/7 and 3/7
was how I interpreted that conversation.

>> From patch 3/7:
>>
>> 	if (of_property_read_u32(node, "bus-type", &bus_type))
>> 		return 0;
>> 	if (bus_type != 0)
>> 		return -EINVAL;
>>
>>>> 		bus-widht = <16>;
>>>> 	};
>>>>
>>>> is that it always means rgb565. See further below.
>>>>
>>>>>> 4) Set the correct format in the atmel hlcd driver to accommodate a
>>>>>> bridge that wants rgb888 on a 16 bit wide bus (that would be rgb565,
>>>>>> or are there other possible combinations I am missing?)
>>>>>>
>>>>>> I would consider this better mostly because in this series you are
>>>>>> creating a semantic for the whole DRM subsystem on the 'bus_width'
>>>>>> property, where numerical values as '12', '16' etc are arbitrary tied
>>>>>> to the selection of a media bus format. At least you should use a
>>>>>> common set of defines [1] between the device tree and the driver,
>>>>>> but this looks anyway fragile imho.
>>>>>
>>>>> This I agree with though. Combining the remote bus format with the local
>>>>> bus width should fix the problem without having to parse remote
>>>>> properties.
>>>>
>>>> My thinking was that the binding with bus-type = <0> and bus-width =
>>>> <bpp> would mean a parallel bus (type 0 means auto-detect and with a bus-
>>>> width that auto-detect means a parallel bus) and the most natural/common
>>>> interpretation of that bus-width. For bus widths of 12, 16, 18, 24, 30
>>>> etc I think that would be rgb444, rgb565, rgb666, rgb888, rgb101010 (or,
>>>> I'm first so I get to define the default). If you have some other
>>>> interpretation of a bus with that width, you'd need to extend the
>>>> video-interface binding with some way of saying what you need, perhaps
>>>> using some kind of data mapping or something to say e.g. bgr666. And
>>>> you'd need some kind of indicator if you have YUV signals instead of
>>>> RGB, and LVDS isn't a completely parallel bus, so you'd need something
>>>> for that. Etc.
>>>
>>> The fundamental issue here is that you're tying the bus with to an
>>> image format. Why <16> can't be, say, MEDIA_BUS_FMT_YVYU8_1X16? it
>>> spans to 16 bits, doesn't it? And I'm sorry but the 'I'm first so I
>>> get to define defaults' argument doesn't apply here.
>>
>> I never said that <16> could not be something YUV. I said that <16> without
>> any further information is RGB. But you are right, the fundamental issue
>> is that I want to specify the full format in the endpoint node, while you
>> do not for some reason I don't understand. And maybe saying that "<16>
>> without more info is RGB" is too presumptuous, but then I think that the
>> right fix is adding something clearly indicating RGB is the way to go, so
>> that there is a way for endpoints to specify RGB565 (or whatever is needed).
> 
> I think that would lack genericity though. I could easily imagine a setup 
> similar to yours where the bridge can accept different types of parallel 
> formats (RGB, BGR, YUV, ...). While the bus width is a property of the PCB 
> routing and is thus fixed, the format wouldn't be a property of the platform 
> but would be dynamic. I believe that combining the bus-width DT property that 
> carries static platform information with the dynamic format reported by the 
> bridge (through the API proposed by Jacopo) would then be a more generic 
> approach.

This is a valid argument.

> You don't have to depend on Jacopo's patch series though, I would be totally 
> fine with assuming that a 16-bit width means RGB565 in the atmel-hlcdc driver. 
> What I'm not comfortable with is hardcoding that assumption in the helper 
> defined in patch 3/7. I would thus propose moving that code to the atmel-hlcdc 
> driver for now, and creating a generic helper that uses both bus-width and the 
> format queried from the bridge when Jacopo's series makes it to mainline. 
> Would that be an acceptable approach for you ?

I just want something acceptable that lets me set a few bits in a damn
register to my liking, ok? :-)

I'll re-spin with the meat of drm_of_media_bus_fmt moved to a static
function in the atmel-hlcdc driver (and squashed with 4/7).

Cheers,
Peter

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

* Re: [PATCH v3 4/7] drm/atmel-hlcdc: support bus-width (12/16/18/24) in endpoint nodes
  2018-04-19 16:27   ` Peter Rosin
  (?)
@ 2018-04-21 16:19     ` Boris Brezillon
  -1 siblings, 0 replies; 67+ messages in thread
From: Boris Brezillon @ 2018-04-21 16:19 UTC (permalink / raw)
  To: Peter Rosin
  Cc: linux-kernel, David Airlie, Rob Herring, Mark Rutland,
	Nicolas Ferre, Alexandre Belloni, Boris Brezillon, Daniel Vetter,
	Gustavo Padovan, Sean Paul, Russell King, Laurent Pinchart,
	Jacopo Mondi, dri-devel, devicetree, linux-arm-kernel

On Thu, 19 Apr 2018 18:27:48 +0200
Peter Rosin <peda@axentia.se> wrote:

> This beats the heuristic that the connector is involved in what format
> should be output for cases where this fails.
> 
> E.g. if there is a bridge that changes format between the encoder and the
> connector, or if some of the RGB pins between the lcd controller and the
> encoder are not routed on the PCB.
> 
> This is critical for the devices that have the "conflicting output
> formats" issue (SAM9N12, SAM9X5, SAMA5D3), since the most significant
> RGB bits move around depending on the selected output mode. For
> devices that do not have the "conflicting output formats" issue
> (SAMA5D2, SAMA5D4), this is completely irrelevant.
> 
> Signed-off-by: Peter Rosin <peda@axentia.se>
> ---
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c   | 71 +++++++++++++++++-------
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h     |  2 +
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 40 ++++++++++++-
>  3 files changed, 92 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
> index d73281095fac..b4e7f5b6f497 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
> @@ -226,6 +226,56 @@ static void atmel_hlcdc_crtc_atomic_enable(struct drm_crtc *c,
>  #define ATMEL_HLCDC_RGB888_OUTPUT	BIT(3)
>  #define ATMEL_HLCDC_OUTPUT_MODE_MASK	GENMASK(3, 0)
>  
> +static int atmel_hlcdc_connector_output_mode(struct drm_connector_state *state)
> +{
> +	struct drm_connector *connector = state->connector;
> +	struct atmel_hlcdc_dc *dc = connector->dev->dev_private;
> +	struct drm_encoder *encoder;
> +	struct drm_display_info *info = &connector->display_info;
> +	unsigned int supported_fmts = 0;
> +	int j;
> +
> +	encoder = state->best_encoder;
> +	if (!encoder)
> +		encoder = connector->encoder;
> +
> +	switch (dc->bus_fmt[encoder->index]) {
> +	case 0:
> +		break;
> +	case MEDIA_BUS_FMT_RGB444_1X12:
> +		return ATMEL_HLCDC_RGB444_OUTPUT;
> +	case MEDIA_BUS_FMT_RGB565_1X16:
> +		return ATMEL_HLCDC_RGB565_OUTPUT;
> +	case MEDIA_BUS_FMT_RGB666_1X18:
> +		return ATMEL_HLCDC_RGB666_OUTPUT;
> +	case MEDIA_BUS_FMT_RGB888_1X24:
> +		return ATMEL_HLCDC_RGB888_OUTPUT;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	for (j = 0; j < info->num_bus_formats; j++) {
> +		switch (info->bus_formats[j]) {
> +		case MEDIA_BUS_FMT_RGB444_1X12:
> +			supported_fmts |= ATMEL_HLCDC_RGB444_OUTPUT;
> +			break;
> +		case MEDIA_BUS_FMT_RGB565_1X16:
> +			supported_fmts |= ATMEL_HLCDC_RGB565_OUTPUT;
> +			break;
> +		case MEDIA_BUS_FMT_RGB666_1X18:
> +			supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT;
> +			break;
> +		case MEDIA_BUS_FMT_RGB888_1X24:
> +			supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT;
> +			break;
> +		default:
> +			break;
> +		}
> +	}
> +
> +	return supported_fmts;
> +}
> +
>  static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state)
>  {
>  	unsigned int output_fmts = ATMEL_HLCDC_OUTPUT_MODE_MASK;
> @@ -238,31 +288,12 @@ static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state)
>  	crtc = drm_crtc_to_atmel_hlcdc_crtc(state->crtc);
>  
>  	for_each_new_connector_in_state(state->state, connector, cstate, i) {
> -		struct drm_display_info *info = &connector->display_info;
>  		unsigned int supported_fmts = 0;
> -		int j;
>  
>  		if (!cstate->crtc)
>  			continue;
>  
> -		for (j = 0; j < info->num_bus_formats; j++) {
> -			switch (info->bus_formats[j]) {
> -			case MEDIA_BUS_FMT_RGB444_1X12:
> -				supported_fmts |= ATMEL_HLCDC_RGB444_OUTPUT;
> -				break;
> -			case MEDIA_BUS_FMT_RGB565_1X16:
> -				supported_fmts |= ATMEL_HLCDC_RGB565_OUTPUT;
> -				break;
> -			case MEDIA_BUS_FMT_RGB666_1X18:
> -				supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT;
> -				break;
> -			case MEDIA_BUS_FMT_RGB888_1X24:
> -				supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT;
> -				break;
> -			default:
> -				break;
> -			}
> -		}
> +		supported_fmts = atmel_hlcdc_connector_output_mode(cstate);
>  
>  		if (crtc->dc->desc->conflicting_output_formats)
>  			output_fmts &= supported_fmts;
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
> index ab32d5b268d2..be2d180dd169 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
> @@ -365,6 +365,7 @@ struct atmel_hlcdc_plane_properties {
>   * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
>   * @fbdev: framebuffer device attached to the Display Controller
>   * @crtc: CRTC provided by the display controller
> + * @bus_fmt: Array of bus format overrides, per connector.
>   * @planes: instantiated planes
>   * @layers: active HLCDC layers
>   * @wq: display controller workqueue
> @@ -376,6 +377,7 @@ struct atmel_hlcdc_dc {
>  	struct dma_pool *dscrpool;
>  	struct atmel_hlcdc *hlcdc;
>  	struct drm_crtc *crtc;
> +	int *bus_fmt;

Looks like this bus_fmt information should be attached to the
atmel_hlcdc_rgb_output object, since the property is placed in the
endpoint representing the DPI encoder output.

You could then parse the format in atmel_hlcdc_attach_endpoint() and
provide a helper to retrieve the hardcoded bus-format attached to an
encoder:

  int atmel_hlcdc_encoder_get_bus_fmt(struct drm_encoder *encoder);

and if it returns zero you can fallback to bus formats
defined in drm_display_info, as you do in this patch.

>  	struct atmel_hlcdc_layer *layers[ATMEL_HLCDC_MAX_LAYERS];
>  	struct workqueue_struct *wq;
>  	struct {
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> index 8db51fb131db..8787e2890c93 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> @@ -77,10 +77,48 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint)
>  
>  int atmel_hlcdc_create_outputs(struct drm_device *dev)
>  {
> +	struct atmel_hlcdc_dc *dc = dev->dev_private;
> +	struct device_node *ep;
> +	int count = of_graph_get_endpoint_count(dev->dev->of_node);
>  	int endpoint, ret = 0;
>  
> -	for (endpoint = 0; !ret; endpoint++)
> +	/*
> +	 * Assume that each endpoint will create a single encoder
> +	 * so that the encoder index can be used as index into
> +	 * this bus_fmt array.
> +	 */
> +	dc->bus_fmt = devm_kzalloc(dev->dev, count * sizeof(*dc->bus_fmt),
> +				   GFP_KERNEL);
> +	if (!dc->bus_fmt)
> +		return -ENOMEM;
> +
> +	for (endpoint = 0; !ret; endpoint++) {
> +		ep = of_graph_get_endpoint_by_regs(dev->dev->of_node, 0,
> +						   endpoint);
> +		if (!ep) {
> +			ret = -ENODEV;
> +			break;
> +		}
> +
> +		dc->bus_fmt[endpoint] = drm_of_media_bus_fmt(ep);
> +
> +		switch (dc->bus_fmt[endpoint]) {
> +		case 0:
> +		case MEDIA_BUS_FMT_RGB444_1X12:
> +		case MEDIA_BUS_FMT_RGB565_1X16:
> +		case MEDIA_BUS_FMT_RGB666_1X18:
> +		case MEDIA_BUS_FMT_RGB888_1X24:
> +			break;
> +		default:
> +			ret = dc->bus_fmt[endpoint];
> +			if (ret > 0)
> +				ret = -EINVAL;
> +		}
> +		if (ret < 0)
> +			break;
> +
>  		ret = atmel_hlcdc_attach_endpoint(dev, endpoint);
> +	}
>  
>  	/* At least one device was successfully attached.*/
>  	if (ret == -ENODEV && endpoint)

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

* Re: [PATCH v3 4/7] drm/atmel-hlcdc: support bus-width (12/16/18/24) in endpoint nodes
@ 2018-04-21 16:19     ` Boris Brezillon
  0 siblings, 0 replies; 67+ messages in thread
From: Boris Brezillon @ 2018-04-21 16:19 UTC (permalink / raw)
  To: Peter Rosin
  Cc: Mark Rutland, Boris Brezillon, Alexandre Belloni, devicetree,
	David Airlie, linux-kernel, dri-devel, Nicolas Ferre,
	Rob Herring, Laurent Pinchart, Daniel Vetter, Jacopo Mondi,
	Russell King, linux-arm-kernel

On Thu, 19 Apr 2018 18:27:48 +0200
Peter Rosin <peda@axentia.se> wrote:

> This beats the heuristic that the connector is involved in what format
> should be output for cases where this fails.
> 
> E.g. if there is a bridge that changes format between the encoder and the
> connector, or if some of the RGB pins between the lcd controller and the
> encoder are not routed on the PCB.
> 
> This is critical for the devices that have the "conflicting output
> formats" issue (SAM9N12, SAM9X5, SAMA5D3), since the most significant
> RGB bits move around depending on the selected output mode. For
> devices that do not have the "conflicting output formats" issue
> (SAMA5D2, SAMA5D4), this is completely irrelevant.
> 
> Signed-off-by: Peter Rosin <peda@axentia.se>
> ---
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c   | 71 +++++++++++++++++-------
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h     |  2 +
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 40 ++++++++++++-
>  3 files changed, 92 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
> index d73281095fac..b4e7f5b6f497 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
> @@ -226,6 +226,56 @@ static void atmel_hlcdc_crtc_atomic_enable(struct drm_crtc *c,
>  #define ATMEL_HLCDC_RGB888_OUTPUT	BIT(3)
>  #define ATMEL_HLCDC_OUTPUT_MODE_MASK	GENMASK(3, 0)
>  
> +static int atmel_hlcdc_connector_output_mode(struct drm_connector_state *state)
> +{
> +	struct drm_connector *connector = state->connector;
> +	struct atmel_hlcdc_dc *dc = connector->dev->dev_private;
> +	struct drm_encoder *encoder;
> +	struct drm_display_info *info = &connector->display_info;
> +	unsigned int supported_fmts = 0;
> +	int j;
> +
> +	encoder = state->best_encoder;
> +	if (!encoder)
> +		encoder = connector->encoder;
> +
> +	switch (dc->bus_fmt[encoder->index]) {
> +	case 0:
> +		break;
> +	case MEDIA_BUS_FMT_RGB444_1X12:
> +		return ATMEL_HLCDC_RGB444_OUTPUT;
> +	case MEDIA_BUS_FMT_RGB565_1X16:
> +		return ATMEL_HLCDC_RGB565_OUTPUT;
> +	case MEDIA_BUS_FMT_RGB666_1X18:
> +		return ATMEL_HLCDC_RGB666_OUTPUT;
> +	case MEDIA_BUS_FMT_RGB888_1X24:
> +		return ATMEL_HLCDC_RGB888_OUTPUT;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	for (j = 0; j < info->num_bus_formats; j++) {
> +		switch (info->bus_formats[j]) {
> +		case MEDIA_BUS_FMT_RGB444_1X12:
> +			supported_fmts |= ATMEL_HLCDC_RGB444_OUTPUT;
> +			break;
> +		case MEDIA_BUS_FMT_RGB565_1X16:
> +			supported_fmts |= ATMEL_HLCDC_RGB565_OUTPUT;
> +			break;
> +		case MEDIA_BUS_FMT_RGB666_1X18:
> +			supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT;
> +			break;
> +		case MEDIA_BUS_FMT_RGB888_1X24:
> +			supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT;
> +			break;
> +		default:
> +			break;
> +		}
> +	}
> +
> +	return supported_fmts;
> +}
> +
>  static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state)
>  {
>  	unsigned int output_fmts = ATMEL_HLCDC_OUTPUT_MODE_MASK;
> @@ -238,31 +288,12 @@ static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state)
>  	crtc = drm_crtc_to_atmel_hlcdc_crtc(state->crtc);
>  
>  	for_each_new_connector_in_state(state->state, connector, cstate, i) {
> -		struct drm_display_info *info = &connector->display_info;
>  		unsigned int supported_fmts = 0;
> -		int j;
>  
>  		if (!cstate->crtc)
>  			continue;
>  
> -		for (j = 0; j < info->num_bus_formats; j++) {
> -			switch (info->bus_formats[j]) {
> -			case MEDIA_BUS_FMT_RGB444_1X12:
> -				supported_fmts |= ATMEL_HLCDC_RGB444_OUTPUT;
> -				break;
> -			case MEDIA_BUS_FMT_RGB565_1X16:
> -				supported_fmts |= ATMEL_HLCDC_RGB565_OUTPUT;
> -				break;
> -			case MEDIA_BUS_FMT_RGB666_1X18:
> -				supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT;
> -				break;
> -			case MEDIA_BUS_FMT_RGB888_1X24:
> -				supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT;
> -				break;
> -			default:
> -				break;
> -			}
> -		}
> +		supported_fmts = atmel_hlcdc_connector_output_mode(cstate);
>  
>  		if (crtc->dc->desc->conflicting_output_formats)
>  			output_fmts &= supported_fmts;
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
> index ab32d5b268d2..be2d180dd169 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
> @@ -365,6 +365,7 @@ struct atmel_hlcdc_plane_properties {
>   * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
>   * @fbdev: framebuffer device attached to the Display Controller
>   * @crtc: CRTC provided by the display controller
> + * @bus_fmt: Array of bus format overrides, per connector.
>   * @planes: instantiated planes
>   * @layers: active HLCDC layers
>   * @wq: display controller workqueue
> @@ -376,6 +377,7 @@ struct atmel_hlcdc_dc {
>  	struct dma_pool *dscrpool;
>  	struct atmel_hlcdc *hlcdc;
>  	struct drm_crtc *crtc;
> +	int *bus_fmt;

Looks like this bus_fmt information should be attached to the
atmel_hlcdc_rgb_output object, since the property is placed in the
endpoint representing the DPI encoder output.

You could then parse the format in atmel_hlcdc_attach_endpoint() and
provide a helper to retrieve the hardcoded bus-format attached to an
encoder:

  int atmel_hlcdc_encoder_get_bus_fmt(struct drm_encoder *encoder);

and if it returns zero you can fallback to bus formats
defined in drm_display_info, as you do in this patch.

>  	struct atmel_hlcdc_layer *layers[ATMEL_HLCDC_MAX_LAYERS];
>  	struct workqueue_struct *wq;
>  	struct {
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> index 8db51fb131db..8787e2890c93 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> @@ -77,10 +77,48 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint)
>  
>  int atmel_hlcdc_create_outputs(struct drm_device *dev)
>  {
> +	struct atmel_hlcdc_dc *dc = dev->dev_private;
> +	struct device_node *ep;
> +	int count = of_graph_get_endpoint_count(dev->dev->of_node);
>  	int endpoint, ret = 0;
>  
> -	for (endpoint = 0; !ret; endpoint++)
> +	/*
> +	 * Assume that each endpoint will create a single encoder
> +	 * so that the encoder index can be used as index into
> +	 * this bus_fmt array.
> +	 */
> +	dc->bus_fmt = devm_kzalloc(dev->dev, count * sizeof(*dc->bus_fmt),
> +				   GFP_KERNEL);
> +	if (!dc->bus_fmt)
> +		return -ENOMEM;
> +
> +	for (endpoint = 0; !ret; endpoint++) {
> +		ep = of_graph_get_endpoint_by_regs(dev->dev->of_node, 0,
> +						   endpoint);
> +		if (!ep) {
> +			ret = -ENODEV;
> +			break;
> +		}
> +
> +		dc->bus_fmt[endpoint] = drm_of_media_bus_fmt(ep);
> +
> +		switch (dc->bus_fmt[endpoint]) {
> +		case 0:
> +		case MEDIA_BUS_FMT_RGB444_1X12:
> +		case MEDIA_BUS_FMT_RGB565_1X16:
> +		case MEDIA_BUS_FMT_RGB666_1X18:
> +		case MEDIA_BUS_FMT_RGB888_1X24:
> +			break;
> +		default:
> +			ret = dc->bus_fmt[endpoint];
> +			if (ret > 0)
> +				ret = -EINVAL;
> +		}
> +		if (ret < 0)
> +			break;
> +
>  		ret = atmel_hlcdc_attach_endpoint(dev, endpoint);
> +	}
>  
>  	/* At least one device was successfully attached.*/
>  	if (ret == -ENODEV && endpoint)

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

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

* [PATCH v3 4/7] drm/atmel-hlcdc: support bus-width (12/16/18/24) in endpoint nodes
@ 2018-04-21 16:19     ` Boris Brezillon
  0 siblings, 0 replies; 67+ messages in thread
From: Boris Brezillon @ 2018-04-21 16:19 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 19 Apr 2018 18:27:48 +0200
Peter Rosin <peda@axentia.se> wrote:

> This beats the heuristic that the connector is involved in what format
> should be output for cases where this fails.
> 
> E.g. if there is a bridge that changes format between the encoder and the
> connector, or if some of the RGB pins between the lcd controller and the
> encoder are not routed on the PCB.
> 
> This is critical for the devices that have the "conflicting output
> formats" issue (SAM9N12, SAM9X5, SAMA5D3), since the most significant
> RGB bits move around depending on the selected output mode. For
> devices that do not have the "conflicting output formats" issue
> (SAMA5D2, SAMA5D4), this is completely irrelevant.
> 
> Signed-off-by: Peter Rosin <peda@axentia.se>
> ---
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c   | 71 +++++++++++++++++-------
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h     |  2 +
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 40 ++++++++++++-
>  3 files changed, 92 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
> index d73281095fac..b4e7f5b6f497 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
> @@ -226,6 +226,56 @@ static void atmel_hlcdc_crtc_atomic_enable(struct drm_crtc *c,
>  #define ATMEL_HLCDC_RGB888_OUTPUT	BIT(3)
>  #define ATMEL_HLCDC_OUTPUT_MODE_MASK	GENMASK(3, 0)
>  
> +static int atmel_hlcdc_connector_output_mode(struct drm_connector_state *state)
> +{
> +	struct drm_connector *connector = state->connector;
> +	struct atmel_hlcdc_dc *dc = connector->dev->dev_private;
> +	struct drm_encoder *encoder;
> +	struct drm_display_info *info = &connector->display_info;
> +	unsigned int supported_fmts = 0;
> +	int j;
> +
> +	encoder = state->best_encoder;
> +	if (!encoder)
> +		encoder = connector->encoder;
> +
> +	switch (dc->bus_fmt[encoder->index]) {
> +	case 0:
> +		break;
> +	case MEDIA_BUS_FMT_RGB444_1X12:
> +		return ATMEL_HLCDC_RGB444_OUTPUT;
> +	case MEDIA_BUS_FMT_RGB565_1X16:
> +		return ATMEL_HLCDC_RGB565_OUTPUT;
> +	case MEDIA_BUS_FMT_RGB666_1X18:
> +		return ATMEL_HLCDC_RGB666_OUTPUT;
> +	case MEDIA_BUS_FMT_RGB888_1X24:
> +		return ATMEL_HLCDC_RGB888_OUTPUT;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	for (j = 0; j < info->num_bus_formats; j++) {
> +		switch (info->bus_formats[j]) {
> +		case MEDIA_BUS_FMT_RGB444_1X12:
> +			supported_fmts |= ATMEL_HLCDC_RGB444_OUTPUT;
> +			break;
> +		case MEDIA_BUS_FMT_RGB565_1X16:
> +			supported_fmts |= ATMEL_HLCDC_RGB565_OUTPUT;
> +			break;
> +		case MEDIA_BUS_FMT_RGB666_1X18:
> +			supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT;
> +			break;
> +		case MEDIA_BUS_FMT_RGB888_1X24:
> +			supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT;
> +			break;
> +		default:
> +			break;
> +		}
> +	}
> +
> +	return supported_fmts;
> +}
> +
>  static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state)
>  {
>  	unsigned int output_fmts = ATMEL_HLCDC_OUTPUT_MODE_MASK;
> @@ -238,31 +288,12 @@ static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state)
>  	crtc = drm_crtc_to_atmel_hlcdc_crtc(state->crtc);
>  
>  	for_each_new_connector_in_state(state->state, connector, cstate, i) {
> -		struct drm_display_info *info = &connector->display_info;
>  		unsigned int supported_fmts = 0;
> -		int j;
>  
>  		if (!cstate->crtc)
>  			continue;
>  
> -		for (j = 0; j < info->num_bus_formats; j++) {
> -			switch (info->bus_formats[j]) {
> -			case MEDIA_BUS_FMT_RGB444_1X12:
> -				supported_fmts |= ATMEL_HLCDC_RGB444_OUTPUT;
> -				break;
> -			case MEDIA_BUS_FMT_RGB565_1X16:
> -				supported_fmts |= ATMEL_HLCDC_RGB565_OUTPUT;
> -				break;
> -			case MEDIA_BUS_FMT_RGB666_1X18:
> -				supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT;
> -				break;
> -			case MEDIA_BUS_FMT_RGB888_1X24:
> -				supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT;
> -				break;
> -			default:
> -				break;
> -			}
> -		}
> +		supported_fmts = atmel_hlcdc_connector_output_mode(cstate);
>  
>  		if (crtc->dc->desc->conflicting_output_formats)
>  			output_fmts &= supported_fmts;
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
> index ab32d5b268d2..be2d180dd169 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
> @@ -365,6 +365,7 @@ struct atmel_hlcdc_plane_properties {
>   * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
>   * @fbdev: framebuffer device attached to the Display Controller
>   * @crtc: CRTC provided by the display controller
> + * @bus_fmt: Array of bus format overrides, per connector.
>   * @planes: instantiated planes
>   * @layers: active HLCDC layers
>   * @wq: display controller workqueue
> @@ -376,6 +377,7 @@ struct atmel_hlcdc_dc {
>  	struct dma_pool *dscrpool;
>  	struct atmel_hlcdc *hlcdc;
>  	struct drm_crtc *crtc;
> +	int *bus_fmt;

Looks like this bus_fmt information should be attached to the
atmel_hlcdc_rgb_output object, since the property is placed in the
endpoint representing the DPI encoder output.

You could then parse the format in atmel_hlcdc_attach_endpoint() and
provide a helper to retrieve the hardcoded bus-format attached to an
encoder:

  int atmel_hlcdc_encoder_get_bus_fmt(struct drm_encoder *encoder);

and if it returns zero you can fallback to bus formats
defined in drm_display_info, as you do in this patch.

>  	struct atmel_hlcdc_layer *layers[ATMEL_HLCDC_MAX_LAYERS];
>  	struct workqueue_struct *wq;
>  	struct {
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> index 8db51fb131db..8787e2890c93 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> @@ -77,10 +77,48 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint)
>  
>  int atmel_hlcdc_create_outputs(struct drm_device *dev)
>  {
> +	struct atmel_hlcdc_dc *dc = dev->dev_private;
> +	struct device_node *ep;
> +	int count = of_graph_get_endpoint_count(dev->dev->of_node);
>  	int endpoint, ret = 0;
>  
> -	for (endpoint = 0; !ret; endpoint++)
> +	/*
> +	 * Assume that each endpoint will create a single encoder
> +	 * so that the encoder index can be used as index into
> +	 * this bus_fmt array.
> +	 */
> +	dc->bus_fmt = devm_kzalloc(dev->dev, count * sizeof(*dc->bus_fmt),
> +				   GFP_KERNEL);
> +	if (!dc->bus_fmt)
> +		return -ENOMEM;
> +
> +	for (endpoint = 0; !ret; endpoint++) {
> +		ep = of_graph_get_endpoint_by_regs(dev->dev->of_node, 0,
> +						   endpoint);
> +		if (!ep) {
> +			ret = -ENODEV;
> +			break;
> +		}
> +
> +		dc->bus_fmt[endpoint] = drm_of_media_bus_fmt(ep);
> +
> +		switch (dc->bus_fmt[endpoint]) {
> +		case 0:
> +		case MEDIA_BUS_FMT_RGB444_1X12:
> +		case MEDIA_BUS_FMT_RGB565_1X16:
> +		case MEDIA_BUS_FMT_RGB666_1X18:
> +		case MEDIA_BUS_FMT_RGB888_1X24:
> +			break;
> +		default:
> +			ret = dc->bus_fmt[endpoint];
> +			if (ret > 0)
> +				ret = -EINVAL;
> +		}
> +		if (ret < 0)
> +			break;
> +
>  		ret = atmel_hlcdc_attach_endpoint(dev, endpoint);
> +	}
>  
>  	/* At least one device was successfully attached.*/
>  	if (ret == -ENODEV && endpoint)

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

* Re: [PATCH v3 4/7] drm/atmel-hlcdc: support bus-width (12/16/18/24) in endpoint nodes
  2018-04-21 16:19     ` Boris Brezillon
@ 2018-04-21 22:13       ` Peter Rosin
  -1 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-21 22:13 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: linux-kernel, David Airlie, Rob Herring, Mark Rutland,
	Nicolas Ferre, Alexandre Belloni, Boris Brezillon, Daniel Vetter,
	Gustavo Padovan, Sean Paul, Russell King, Laurent Pinchart,
	Jacopo Mondi, dri-devel, devicetree, linux-arm-kernel

On 2018-04-21 18:19, Boris Brezillon wrote:
> On Thu, 19 Apr 2018 18:27:48 +0200
> Peter Rosin <peda@axentia.se> wrote:
> 
>> This beats the heuristic that the connector is involved in what format
>> should be output for cases where this fails.
>>
>> E.g. if there is a bridge that changes format between the encoder and the
>> connector, or if some of the RGB pins between the lcd controller and the
>> encoder are not routed on the PCB.
>>
>> This is critical for the devices that have the "conflicting output
>> formats" issue (SAM9N12, SAM9X5, SAMA5D3), since the most significant
>> RGB bits move around depending on the selected output mode. For
>> devices that do not have the "conflicting output formats" issue
>> (SAMA5D2, SAMA5D4), this is completely irrelevant.
>>
>> Signed-off-by: Peter Rosin <peda@axentia.se>
>> ---
>>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c   | 71 +++++++++++++++++-------
>>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h     |  2 +
>>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 40 ++++++++++++-
>>  3 files changed, 92 insertions(+), 21 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
>> index d73281095fac..b4e7f5b6f497 100644
>> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
>> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
>> @@ -226,6 +226,56 @@ static void atmel_hlcdc_crtc_atomic_enable(struct drm_crtc *c,
>>  #define ATMEL_HLCDC_RGB888_OUTPUT	BIT(3)
>>  #define ATMEL_HLCDC_OUTPUT_MODE_MASK	GENMASK(3, 0)
>>  
>> +static int atmel_hlcdc_connector_output_mode(struct drm_connector_state *state)
>> +{
>> +	struct drm_connector *connector = state->connector;
>> +	struct atmel_hlcdc_dc *dc = connector->dev->dev_private;
>> +	struct drm_encoder *encoder;
>> +	struct drm_display_info *info = &connector->display_info;
>> +	unsigned int supported_fmts = 0;
>> +	int j;
>> +
>> +	encoder = state->best_encoder;
>> +	if (!encoder)
>> +		encoder = connector->encoder;
>> +
>> +	switch (dc->bus_fmt[encoder->index]) {
>> +	case 0:
>> +		break;
>> +	case MEDIA_BUS_FMT_RGB444_1X12:
>> +		return ATMEL_HLCDC_RGB444_OUTPUT;
>> +	case MEDIA_BUS_FMT_RGB565_1X16:
>> +		return ATMEL_HLCDC_RGB565_OUTPUT;
>> +	case MEDIA_BUS_FMT_RGB666_1X18:
>> +		return ATMEL_HLCDC_RGB666_OUTPUT;
>> +	case MEDIA_BUS_FMT_RGB888_1X24:
>> +		return ATMEL_HLCDC_RGB888_OUTPUT;
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +
>> +	for (j = 0; j < info->num_bus_formats; j++) {
>> +		switch (info->bus_formats[j]) {
>> +		case MEDIA_BUS_FMT_RGB444_1X12:
>> +			supported_fmts |= ATMEL_HLCDC_RGB444_OUTPUT;
>> +			break;
>> +		case MEDIA_BUS_FMT_RGB565_1X16:
>> +			supported_fmts |= ATMEL_HLCDC_RGB565_OUTPUT;
>> +			break;
>> +		case MEDIA_BUS_FMT_RGB666_1X18:
>> +			supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT;
>> +			break;
>> +		case MEDIA_BUS_FMT_RGB888_1X24:
>> +			supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT;
>> +			break;
>> +		default:
>> +			break;
>> +		}
>> +	}
>> +
>> +	return supported_fmts;
>> +}
>> +
>>  static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state)
>>  {
>>  	unsigned int output_fmts = ATMEL_HLCDC_OUTPUT_MODE_MASK;
>> @@ -238,31 +288,12 @@ static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state)
>>  	crtc = drm_crtc_to_atmel_hlcdc_crtc(state->crtc);
>>  
>>  	for_each_new_connector_in_state(state->state, connector, cstate, i) {
>> -		struct drm_display_info *info = &connector->display_info;
>>  		unsigned int supported_fmts = 0;
>> -		int j;
>>  
>>  		if (!cstate->crtc)
>>  			continue;
>>  
>> -		for (j = 0; j < info->num_bus_formats; j++) {
>> -			switch (info->bus_formats[j]) {
>> -			case MEDIA_BUS_FMT_RGB444_1X12:
>> -				supported_fmts |= ATMEL_HLCDC_RGB444_OUTPUT;
>> -				break;
>> -			case MEDIA_BUS_FMT_RGB565_1X16:
>> -				supported_fmts |= ATMEL_HLCDC_RGB565_OUTPUT;
>> -				break;
>> -			case MEDIA_BUS_FMT_RGB666_1X18:
>> -				supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT;
>> -				break;
>> -			case MEDIA_BUS_FMT_RGB888_1X24:
>> -				supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT;
>> -				break;
>> -			default:
>> -				break;
>> -			}
>> -		}
>> +		supported_fmts = atmel_hlcdc_connector_output_mode(cstate);
>>  
>>  		if (crtc->dc->desc->conflicting_output_formats)
>>  			output_fmts &= supported_fmts;
>> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
>> index ab32d5b268d2..be2d180dd169 100644
>> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
>> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
>> @@ -365,6 +365,7 @@ struct atmel_hlcdc_plane_properties {
>>   * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
>>   * @fbdev: framebuffer device attached to the Display Controller
>>   * @crtc: CRTC provided by the display controller
>> + * @bus_fmt: Array of bus format overrides, per connector.
>>   * @planes: instantiated planes
>>   * @layers: active HLCDC layers
>>   * @wq: display controller workqueue
>> @@ -376,6 +377,7 @@ struct atmel_hlcdc_dc {
>>  	struct dma_pool *dscrpool;
>>  	struct atmel_hlcdc *hlcdc;
>>  	struct drm_crtc *crtc;
>> +	int *bus_fmt;
> 
> Looks like this bus_fmt information should be attached to the
> atmel_hlcdc_rgb_output object, since the property is placed in the
> endpoint representing the DPI encoder output.
> 
> You could then parse the format in atmel_hlcdc_attach_endpoint() and
> provide a helper to retrieve the hardcoded bus-format attached to an
> encoder:
> 
>   int atmel_hlcdc_encoder_get_bus_fmt(struct drm_encoder *encoder);
> 
> and if it returns zero you can fallback to bus formats
> defined in drm_display_info, as you do in this patch.

Good suggestion. However, it appears the atmel_hlcdc_rgb_output object
was removed in 4.13. But I'm bringing it back like this

struct atmel_hlcdc_rgb_output {
	struct drm_encoder encoder;
	int bus_fmt;
};

and adjusting the code to match that. It all looks nice and tidy, methinks.

v4 coming up Monday, if nothing unexpected happens.

Cheers,
Peter

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

* [PATCH v3 4/7] drm/atmel-hlcdc: support bus-width (12/16/18/24) in endpoint nodes
@ 2018-04-21 22:13       ` Peter Rosin
  0 siblings, 0 replies; 67+ messages in thread
From: Peter Rosin @ 2018-04-21 22:13 UTC (permalink / raw)
  To: linux-arm-kernel

On 2018-04-21 18:19, Boris Brezillon wrote:
> On Thu, 19 Apr 2018 18:27:48 +0200
> Peter Rosin <peda@axentia.se> wrote:
> 
>> This beats the heuristic that the connector is involved in what format
>> should be output for cases where this fails.
>>
>> E.g. if there is a bridge that changes format between the encoder and the
>> connector, or if some of the RGB pins between the lcd controller and the
>> encoder are not routed on the PCB.
>>
>> This is critical for the devices that have the "conflicting output
>> formats" issue (SAM9N12, SAM9X5, SAMA5D3), since the most significant
>> RGB bits move around depending on the selected output mode. For
>> devices that do not have the "conflicting output formats" issue
>> (SAMA5D2, SAMA5D4), this is completely irrelevant.
>>
>> Signed-off-by: Peter Rosin <peda@axentia.se>
>> ---
>>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c   | 71 +++++++++++++++++-------
>>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h     |  2 +
>>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 40 ++++++++++++-
>>  3 files changed, 92 insertions(+), 21 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
>> index d73281095fac..b4e7f5b6f497 100644
>> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
>> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
>> @@ -226,6 +226,56 @@ static void atmel_hlcdc_crtc_atomic_enable(struct drm_crtc *c,
>>  #define ATMEL_HLCDC_RGB888_OUTPUT	BIT(3)
>>  #define ATMEL_HLCDC_OUTPUT_MODE_MASK	GENMASK(3, 0)
>>  
>> +static int atmel_hlcdc_connector_output_mode(struct drm_connector_state *state)
>> +{
>> +	struct drm_connector *connector = state->connector;
>> +	struct atmel_hlcdc_dc *dc = connector->dev->dev_private;
>> +	struct drm_encoder *encoder;
>> +	struct drm_display_info *info = &connector->display_info;
>> +	unsigned int supported_fmts = 0;
>> +	int j;
>> +
>> +	encoder = state->best_encoder;
>> +	if (!encoder)
>> +		encoder = connector->encoder;
>> +
>> +	switch (dc->bus_fmt[encoder->index]) {
>> +	case 0:
>> +		break;
>> +	case MEDIA_BUS_FMT_RGB444_1X12:
>> +		return ATMEL_HLCDC_RGB444_OUTPUT;
>> +	case MEDIA_BUS_FMT_RGB565_1X16:
>> +		return ATMEL_HLCDC_RGB565_OUTPUT;
>> +	case MEDIA_BUS_FMT_RGB666_1X18:
>> +		return ATMEL_HLCDC_RGB666_OUTPUT;
>> +	case MEDIA_BUS_FMT_RGB888_1X24:
>> +		return ATMEL_HLCDC_RGB888_OUTPUT;
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +
>> +	for (j = 0; j < info->num_bus_formats; j++) {
>> +		switch (info->bus_formats[j]) {
>> +		case MEDIA_BUS_FMT_RGB444_1X12:
>> +			supported_fmts |= ATMEL_HLCDC_RGB444_OUTPUT;
>> +			break;
>> +		case MEDIA_BUS_FMT_RGB565_1X16:
>> +			supported_fmts |= ATMEL_HLCDC_RGB565_OUTPUT;
>> +			break;
>> +		case MEDIA_BUS_FMT_RGB666_1X18:
>> +			supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT;
>> +			break;
>> +		case MEDIA_BUS_FMT_RGB888_1X24:
>> +			supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT;
>> +			break;
>> +		default:
>> +			break;
>> +		}
>> +	}
>> +
>> +	return supported_fmts;
>> +}
>> +
>>  static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state)
>>  {
>>  	unsigned int output_fmts = ATMEL_HLCDC_OUTPUT_MODE_MASK;
>> @@ -238,31 +288,12 @@ static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state)
>>  	crtc = drm_crtc_to_atmel_hlcdc_crtc(state->crtc);
>>  
>>  	for_each_new_connector_in_state(state->state, connector, cstate, i) {
>> -		struct drm_display_info *info = &connector->display_info;
>>  		unsigned int supported_fmts = 0;
>> -		int j;
>>  
>>  		if (!cstate->crtc)
>>  			continue;
>>  
>> -		for (j = 0; j < info->num_bus_formats; j++) {
>> -			switch (info->bus_formats[j]) {
>> -			case MEDIA_BUS_FMT_RGB444_1X12:
>> -				supported_fmts |= ATMEL_HLCDC_RGB444_OUTPUT;
>> -				break;
>> -			case MEDIA_BUS_FMT_RGB565_1X16:
>> -				supported_fmts |= ATMEL_HLCDC_RGB565_OUTPUT;
>> -				break;
>> -			case MEDIA_BUS_FMT_RGB666_1X18:
>> -				supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT;
>> -				break;
>> -			case MEDIA_BUS_FMT_RGB888_1X24:
>> -				supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT;
>> -				break;
>> -			default:
>> -				break;
>> -			}
>> -		}
>> +		supported_fmts = atmel_hlcdc_connector_output_mode(cstate);
>>  
>>  		if (crtc->dc->desc->conflicting_output_formats)
>>  			output_fmts &= supported_fmts;
>> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
>> index ab32d5b268d2..be2d180dd169 100644
>> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
>> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
>> @@ -365,6 +365,7 @@ struct atmel_hlcdc_plane_properties {
>>   * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
>>   * @fbdev: framebuffer device attached to the Display Controller
>>   * @crtc: CRTC provided by the display controller
>> + * @bus_fmt: Array of bus format overrides, per connector.
>>   * @planes: instantiated planes
>>   * @layers: active HLCDC layers
>>   * @wq: display controller workqueue
>> @@ -376,6 +377,7 @@ struct atmel_hlcdc_dc {
>>  	struct dma_pool *dscrpool;
>>  	struct atmel_hlcdc *hlcdc;
>>  	struct drm_crtc *crtc;
>> +	int *bus_fmt;
> 
> Looks like this bus_fmt information should be attached to the
> atmel_hlcdc_rgb_output object, since the property is placed in the
> endpoint representing the DPI encoder output.
> 
> You could then parse the format in atmel_hlcdc_attach_endpoint() and
> provide a helper to retrieve the hardcoded bus-format attached to an
> encoder:
> 
>   int atmel_hlcdc_encoder_get_bus_fmt(struct drm_encoder *encoder);
> 
> and if it returns zero you can fallback to bus formats
> defined in drm_display_info, as you do in this patch.

Good suggestion. However, it appears the atmel_hlcdc_rgb_output object
was removed in 4.13. But I'm bringing it back like this

struct atmel_hlcdc_rgb_output {
	struct drm_encoder encoder;
	int bus_fmt;
};

and adjusting the code to match that. It all looks nice and tidy, methinks.

v4 coming up Monday, if nothing unexpected happens.

Cheers,
Peter

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

end of thread, other threads:[~2018-04-21 22:13 UTC | newest]

Thread overview: 67+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-19 16:27 [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc Peter Rosin
2018-04-19 16:27 ` Peter Rosin
2018-04-19 16:27 ` [PATCH v3 1/7] dt-bindings: display: bridge: lvds-transmitter: add ti,ds90c185 Peter Rosin
2018-04-19 16:27   ` [PATCH v3 1/7] dt-bindings: display: bridge: lvds-transmitter: add ti, ds90c185 Peter Rosin
2018-04-19 16:27 ` [PATCH v3 2/7] dt-bindings: display: atmel: optional video-interface of endpoints Peter Rosin
2018-04-19 16:27   ` Peter Rosin
2018-04-19 16:27 ` [PATCH v3 3/7] drm: of: introduce drm_of_media_bus_fmt Peter Rosin
2018-04-19 16:27   ` Peter Rosin
2018-04-19 16:27 ` [PATCH v3 4/7] drm/atmel-hlcdc: support bus-width (12/16/18/24) in endpoint nodes Peter Rosin
2018-04-19 16:27   ` Peter Rosin
2018-04-21 16:19   ` Boris Brezillon
2018-04-21 16:19     ` Boris Brezillon
2018-04-21 16:19     ` Boris Brezillon
2018-04-21 22:13     ` Peter Rosin
2018-04-21 22:13       ` Peter Rosin
2018-04-19 16:27 ` [PATCH v3 5/7] drm/i2c: tda998x: find the drm_device via the drm_connector Peter Rosin
2018-04-19 16:27   ` Peter Rosin
2018-04-20  9:41   ` Laurent Pinchart
2018-04-20  9:41     ` Laurent Pinchart
2018-04-19 16:27 ` [PATCH v3 6/7] drm/i2c: tda998x: split encoder and component functions from the work Peter Rosin
2018-04-19 16:27   ` Peter Rosin
2018-04-20  9:51   ` Laurent Pinchart
2018-04-20  9:51     ` Laurent Pinchart
2018-04-19 16:27 ` [PATCH v3 7/7] drm/i2c: tda998x: register as a drm bridge Peter Rosin
2018-04-19 16:27   ` Peter Rosin
2018-04-20 10:06   ` Laurent Pinchart
2018-04-20 10:06     ` Laurent Pinchart
2018-04-20 10:06     ` Laurent Pinchart
2018-04-20 10:24     ` Russell King - ARM Linux
2018-04-20 10:24       ` Russell King - ARM Linux
2018-04-20 13:28       ` Peter Rosin
2018-04-20 13:28         ` Peter Rosin
2018-04-20 10:41   ` kbuild test robot
2018-04-20 10:41     ` kbuild test robot
2018-04-20 10:41     ` kbuild test robot
2018-04-20 10:49     ` Peter Rosin
2018-04-20 10:49       ` Peter Rosin
2018-04-20 10:53       ` Russell King - ARM Linux
2018-04-20 10:53         ` Russell King - ARM Linux
2018-04-20 13:09         ` Peter Rosin
2018-04-20 13:09           ` Peter Rosin
2018-04-20 12:00   ` Russell King - ARM Linux
2018-04-20 12:00     ` Russell King - ARM Linux
2018-04-20  8:52 ` [PATCH v3 0/7] Add tda998x (HDMI) support to atmel-hlcdc jacopo mondi
2018-04-20  8:52   ` jacopo mondi
2018-04-20  8:52   ` jacopo mondi
2018-04-20 10:18   ` Laurent Pinchart
2018-04-20 10:18     ` Laurent Pinchart
2018-04-20 10:18     ` Laurent Pinchart
2018-04-20 11:05     ` Peter Rosin
2018-04-20 11:05       ` Peter Rosin
2018-04-20 11:38       ` jacopo mondi
2018-04-20 11:38         ` jacopo mondi
2018-04-20 11:38         ` jacopo mondi
2018-04-20 12:55         ` Peter Rosin
2018-04-20 12:55           ` Peter Rosin
2018-04-21  8:38           ` Laurent Pinchart
2018-04-21  8:38             ` Laurent Pinchart
2018-04-21  8:38             ` Laurent Pinchart
2018-04-21 15:05             ` Peter Rosin
2018-04-21 15:05               ` Peter Rosin
2018-04-20 11:22     ` jacopo mondi
2018-04-20 11:22       ` jacopo mondi
2018-04-20 11:22       ` jacopo mondi
2018-04-21  8:20       ` Laurent Pinchart
2018-04-21  8:20         ` Laurent Pinchart
2018-04-21  8:20         ` Laurent Pinchart

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.