Re: [PATCH v5 4/4] drm/bridge: Add the necessary bits to support bus format negotiation

2019-12-23 Thread Jernej Škrabec
Hi!

Dne četrtek, 19. december 2019 ob 11:11:51 CET je Neil Armstrong napisal(a):
> From: Boris Brezillon 
> 
> drm_bridge_state is extended to describe the input and output bus
> configurations. These bus configurations are exposed through the
> drm_bus_cfg struct which encodes the configuration of a physical
> bus between two components in an output pipeline, usually between
> two bridges, an encoder and a bridge, or a bridge and a connector.
> 
> The bus configuration is stored in drm_bridge_state separately for
> the input and output buses, as seen from the point of view of each
> bridge. The bus configuration of a bridge output is usually identical
> to the configuration of the next bridge's input, but may differ if
> the signals are modified between the two bridges, for instance by an
> inverter on the board. The input and output configurations of a
> bridge may differ if the bridge modifies the signals internally,
> for instance by performing format conversion, or*modifying signals
> polarities.
> 
> Bus format negotiation is automated by the core, drivers just have
> to implement the ->atomic_get_{output,input}_bus_fmts() hooks if they
> want to take part to this negotiation. Negotiation happens in reverse
> order, starting from the last element of the chain (the one directly
> connected to the display) up to the first element of the chain (the one
> connected to the encoder).
> During this negotiation all supported formats are tested until we find
> one that works, meaning that the formats array should be in decreasing
> preference order (assuming the driver has a preference order).
> 
> Note that the bus format negotiation works even if some elements in the
> chain don't implement the ->atomic_get_{output,input}_bus_fmts() hooks.
> In that case, the core advertises only MEDIA_BUS_FMT_FIXED and lets
> the previous bridge element decide what to do (most of the time, bridge
> drivers will pick a default bus format or extract this piece of
> information from somewhere else, like a FW property).
> 
> Signed-off-by: Boris Brezillon 
> Signed-off-by: Neil Armstrong 
> ---

Thanks a lot for this work! Just one small nit bellow. Otherwise:

Reviewed by: Jernej Skrabec 

> Changes in v5:
> * None
> 
> Changes in v4:
> * Enhance the doc
> * Fix typos
> * Rename some parameters/fields
> * Reword the commit message
> 
> Changes in v3:
> * Fix the commit message (Reported by Laurent)
> * Document the fact that bus formats should not be directly modified by
>   drivers (Suggested by Laurent)
> * Document the fact that format order matters (Suggested by Laurent)
> * Propagate bus flags by default
> * Document the fact that drivers can tweak bus flags if needed
> * Let ->atomic_get_{output,input}_bus_fmts() allocate the bus format
>   array (Suggested by Laurent)
> * Add a drm_atomic_helper_bridge_propagate_bus_fmt()
> * Mandate that bridge drivers return accurate input_fmts even if they
>   are known to be the first element in the bridge chain
> 
> Changes in v2:
> * Rework things to support more complex use cases
> ---
>  drivers/gpu/drm/drm_bridge.c | 267 ++-
>  include/drm/drm_bridge.h | 124 
>  2 files changed, 390 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index 442804598f60..9cc4b0181f85 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -635,13 +635,261 @@ static int drm_atomic_bridge_check(struct drm_bridge
> *bridge, return 0;
>  }
> 
> +/**
> + * drm_atomic_helper_bridge_propagate_bus_fmt() - Propagate output format
> to + *  the 
input end of a bridge
> + * @bridge: bridge control structure
> + * @bridge_state: new bridge state
> + * @crtc_state: new CRTC state
> + * @conn_state: new connector state
> + * @output_fmt: tested output bus format
> + * @num_input_fmts: will contain the size of the returned array
> + *
> + * This helper is a pluggable implementation of the
> + * _bridge_funcs.atomic_get_input_bus_fmts operation for bridges that
> don't + * modify the bus configuration between their input and their
> output. It + * returns an array of input formats with a single element set
> to @output_fmt. + *
> + * RETURNS:
> + * a valid format array of size @num_input_fmts, or NULL if the allocation
> + * failed
> + */
> +u32 *
> +drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge,
> + struct drm_bridge_state 
*bridge_state,
> + struct drm_crtc_state 
*crtc_state,
> + struct 
drm_connector_state *conn_state,
> + u32 output_fmt,
> + unsigned int 
*num_input_fmts)
> +{
> + u32 *input_fmts;
> +
> + input_fmts = kzalloc(sizeof(*input_fmts), GFP_KERNEL);
> + if (!input_fmts) {
> + 

[PATCH v5 4/4] drm/bridge: Add the necessary bits to support bus format negotiation

2019-12-19 Thread Neil Armstrong
From: Boris Brezillon 

drm_bridge_state is extended to describe the input and output bus
configurations. These bus configurations are exposed through the
drm_bus_cfg struct which encodes the configuration of a physical
bus between two components in an output pipeline, usually between
two bridges, an encoder and a bridge, or a bridge and a connector.

The bus configuration is stored in drm_bridge_state separately for
the input and output buses, as seen from the point of view of each
bridge. The bus configuration of a bridge output is usually identical
to the configuration of the next bridge's input, but may differ if
the signals are modified between the two bridges, for instance by an
inverter on the board. The input and output configurations of a
bridge may differ if the bridge modifies the signals internally,
for instance by performing format conversion, or*modifying signals
polarities.

Bus format negotiation is automated by the core, drivers just have
to implement the ->atomic_get_{output,input}_bus_fmts() hooks if they
want to take part to this negotiation. Negotiation happens in reverse
order, starting from the last element of the chain (the one directly
connected to the display) up to the first element of the chain (the one
connected to the encoder).
During this negotiation all supported formats are tested until we find
one that works, meaning that the formats array should be in decreasing
preference order (assuming the driver has a preference order).

Note that the bus format negotiation works even if some elements in the
chain don't implement the ->atomic_get_{output,input}_bus_fmts() hooks.
In that case, the core advertises only MEDIA_BUS_FMT_FIXED and lets
the previous bridge element decide what to do (most of the time, bridge
drivers will pick a default bus format or extract this piece of
information from somewhere else, like a FW property).

Signed-off-by: Boris Brezillon 
Signed-off-by: Neil Armstrong 
---
Changes in v5:
* None

Changes in v4:
* Enhance the doc
* Fix typos
* Rename some parameters/fields
* Reword the commit message

Changes in v3:
* Fix the commit message (Reported by Laurent)
* Document the fact that bus formats should not be directly modified by
  drivers (Suggested by Laurent)
* Document the fact that format order matters (Suggested by Laurent)
* Propagate bus flags by default
* Document the fact that drivers can tweak bus flags if needed
* Let ->atomic_get_{output,input}_bus_fmts() allocate the bus format
  array (Suggested by Laurent)
* Add a drm_atomic_helper_bridge_propagate_bus_fmt()
* Mandate that bridge drivers return accurate input_fmts even if they
  are known to be the first element in the bridge chain

Changes in v2:
* Rework things to support more complex use cases
---
 drivers/gpu/drm/drm_bridge.c | 267 ++-
 include/drm/drm_bridge.h | 124 
 2 files changed, 390 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 442804598f60..9cc4b0181f85 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -635,13 +635,261 @@ static int drm_atomic_bridge_check(struct drm_bridge 
*bridge,
return 0;
 }
 
+/**
+ * drm_atomic_helper_bridge_propagate_bus_fmt() - Propagate output format to
+ *   the input end of a bridge
+ * @bridge: bridge control structure
+ * @bridge_state: new bridge state
+ * @crtc_state: new CRTC state
+ * @conn_state: new connector state
+ * @output_fmt: tested output bus format
+ * @num_input_fmts: will contain the size of the returned array
+ *
+ * This helper is a pluggable implementation of the
+ * _bridge_funcs.atomic_get_input_bus_fmts operation for bridges that don't
+ * modify the bus configuration between their input and their output. It
+ * returns an array of input formats with a single element set to @output_fmt.
+ *
+ * RETURNS:
+ * a valid format array of size @num_input_fmts, or NULL if the allocation
+ * failed
+ */
+u32 *
+drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge,
+   struct drm_bridge_state *bridge_state,
+   struct drm_crtc_state *crtc_state,
+   struct drm_connector_state *conn_state,
+   u32 output_fmt,
+   unsigned int *num_input_fmts)
+{
+   u32 *input_fmts;
+
+   input_fmts = kzalloc(sizeof(*input_fmts), GFP_KERNEL);
+   if (!input_fmts) {
+   *num_input_fmts = 0;
+   return NULL;
+   }
+
+   *num_input_fmts = 1;
+   input_fmts[0] = output_fmt;
+   return input_fmts;
+}
+EXPORT_SYMBOL(drm_atomic_helper_bridge_propagate_bus_fmt);
+
+static int select_bus_fmt_recursive(struct drm_bridge *first_bridge,
+   struct drm_bridge *cur_bridge,
+