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