diff mbox series

[4/4] drm/atomic-helper: Add select_output_bus_format callback

Message ID 20240226-dp-live-fmt-v1-4-b78c3f69c9d8@amd.com (mailing list archive)
State New, archived
Headers show
Series Setting live video input format for ZynqMP DPSUB | expand

Commit Message

Klymenko, Anatoliy Feb. 27, 2024, 4:44 a.m. UTC
Add select_output_bus_format to CRTC atomic helpers callbacks. This
callback Will allow CRTC to participate in media bus format negotiation
over connected DRM bridge chain and impose CRTC-specific restrictions.
A good example is CRTC implemented as FPGA soft IP. This kind of CRTC will
most certainly support a single output media bus format, as supporting
multiple runtime options consumes extra FPGA resources. A variety of
options for FPGA are usually achieved by synthesizing IP with different
parameters.

Incorporate select_output_bus_format callback into the format negotiation
stage to fix the input bus format of the first DRM bridge in the chain.

Signed-off-by: Anatoliy Klymenko <anatoliy.klymenko@amd.com>
---
 drivers/gpu/drm/drm_bridge.c             | 19 +++++++++++++++++--
 include/drm/drm_modeset_helper_vtables.h | 31 +++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+), 2 deletions(-)

Comments

Maxime Ripard Feb. 28, 2024, 3:29 p.m. UTC | #1
Hi,

On Mon, Feb 26, 2024 at 08:44:45PM -0800, Anatoliy Klymenko wrote:
> Add select_output_bus_format to CRTC atomic helpers callbacks. This
> callback Will allow CRTC to participate in media bus format negotiation
> over connected DRM bridge chain and impose CRTC-specific restrictions.
> A good example is CRTC implemented as FPGA soft IP. This kind of CRTC will
> most certainly support a single output media bus format, as supporting
> multiple runtime options consumes extra FPGA resources. A variety of
> options for FPGA are usually achieved by synthesizing IP with different
> parameters.
> 
> Incorporate select_output_bus_format callback into the format negotiation
> stage to fix the input bus format of the first DRM bridge in the chain.
> 
> Signed-off-by: Anatoliy Klymenko <anatoliy.klymenko@amd.com>
> ---
>  drivers/gpu/drm/drm_bridge.c             | 19 +++++++++++++++++--
>  include/drm/drm_modeset_helper_vtables.h | 31 +++++++++++++++++++++++++++++++
>  2 files changed, 48 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index 521a71c61b16..453ae3d174b4 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -32,6 +32,7 @@
>  #include <drm/drm_edid.h>
>  #include <drm/drm_encoder.h>
>  #include <drm/drm_file.h>
> +#include <drm/drm_modeset_helper_vtables.h>
>  #include <drm/drm_of.h>
>  #include <drm/drm_print.h>
>  
> @@ -879,7 +880,8 @@ static int select_bus_fmt_recursive(struct drm_bridge *first_bridge,
>  	unsigned int i, num_in_bus_fmts = 0;
>  	struct drm_bridge_state *cur_state;
>  	struct drm_bridge *prev_bridge;
> -	u32 *in_bus_fmts;
> +	struct drm_crtc *crtc = crtc_state->crtc;
> +	u32 *in_bus_fmts, in_fmt;
>  	int ret;
>  
>  	prev_bridge = drm_bridge_get_prev_bridge(cur_bridge);
> @@ -933,7 +935,20 @@ static int select_bus_fmt_recursive(struct drm_bridge *first_bridge,
>  		return -ENOMEM;
>  
>  	if (first_bridge == cur_bridge) {
> -		cur_state->input_bus_cfg.format = in_bus_fmts[0];
> +		in_fmt = in_bus_fmts[0];
> +		if (crtc->helper_private &&
> +		    crtc->helper_private->select_output_bus_format) {
> +			in_fmt = crtc->helper_private->select_output_bus_format(
> +							crtc,
> +							crtc->state,
> +							in_bus_fmts,
> +							num_in_bus_fmts);
> +			if (!in_fmt) {
> +				kfree(in_bus_fmts);
> +				return -ENOTSUPP;
> +			}
> +		}
> +		cur_state->input_bus_cfg.format = in_fmt;

I don't think we should start poking at the CRTC internals, but we
should rather provide a helper here.

>  		cur_state->output_bus_cfg.format = out_bus_fmt;
>  		kfree(in_bus_fmts);
>  		return 0;
> diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
> index 881b03e4dc28..7c21ae1fe3ad 100644
> --- a/include/drm/drm_modeset_helper_vtables.h
> +++ b/include/drm/drm_modeset_helper_vtables.h
> @@ -489,6 +489,37 @@ struct drm_crtc_helper_funcs {
>  				     bool in_vblank_irq, int *vpos, int *hpos,
>  				     ktime_t *stime, ktime_t *etime,
>  				     const struct drm_display_mode *mode);
> +
> +	/**
> +	 * @select_output_bus_format
> +	 *
> +	 * Called by the first connected DRM bridge to negotiate input media
> +	 * bus format. CRTC is expected to pick preferable media formats from
> +	 * the list supported by the DRM bridge chain.

There's nothing restricting it to bridges here. Please rephrase this to
remove the bridge mention. The user is typically going to be the
encoder, and bridges are just an automagic implementation of an encoder.

And generally speaking, I'd really like to have an implementation
available before merging this.

Maxime
Laurent Pinchart Feb. 28, 2024, 4:10 p.m. UTC | #2
On Wed, Feb 28, 2024 at 04:29:33PM +0100, Maxime Ripard wrote:
> On Mon, Feb 26, 2024 at 08:44:45PM -0800, Anatoliy Klymenko wrote:
> > Add select_output_bus_format to CRTC atomic helpers callbacks. This
> > callback Will allow CRTC to participate in media bus format negotiation
> > over connected DRM bridge chain and impose CRTC-specific restrictions.
> > A good example is CRTC implemented as FPGA soft IP. This kind of CRTC will
> > most certainly support a single output media bus format, as supporting
> > multiple runtime options consumes extra FPGA resources. A variety of
> > options for FPGA are usually achieved by synthesizing IP with different
> > parameters.
> > 
> > Incorporate select_output_bus_format callback into the format negotiation
> > stage to fix the input bus format of the first DRM bridge in the chain.
> > 
> > Signed-off-by: Anatoliy Klymenko <anatoliy.klymenko@amd.com>
> > ---
> >  drivers/gpu/drm/drm_bridge.c             | 19 +++++++++++++++++--
> >  include/drm/drm_modeset_helper_vtables.h | 31 +++++++++++++++++++++++++++++++
> >  2 files changed, 48 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> > index 521a71c61b16..453ae3d174b4 100644
> > --- a/drivers/gpu/drm/drm_bridge.c
> > +++ b/drivers/gpu/drm/drm_bridge.c
> > @@ -32,6 +32,7 @@
> >  #include <drm/drm_edid.h>
> >  #include <drm/drm_encoder.h>
> >  #include <drm/drm_file.h>
> > +#include <drm/drm_modeset_helper_vtables.h>
> >  #include <drm/drm_of.h>
> >  #include <drm/drm_print.h>
> >  
> > @@ -879,7 +880,8 @@ static int select_bus_fmt_recursive(struct drm_bridge *first_bridge,
> >  	unsigned int i, num_in_bus_fmts = 0;
> >  	struct drm_bridge_state *cur_state;
> >  	struct drm_bridge *prev_bridge;
> > -	u32 *in_bus_fmts;
> > +	struct drm_crtc *crtc = crtc_state->crtc;
> > +	u32 *in_bus_fmts, in_fmt;
> >  	int ret;
> >  
> >  	prev_bridge = drm_bridge_get_prev_bridge(cur_bridge);
> > @@ -933,7 +935,20 @@ static int select_bus_fmt_recursive(struct drm_bridge *first_bridge,
> >  		return -ENOMEM;
> >  
> >  	if (first_bridge == cur_bridge) {
> > -		cur_state->input_bus_cfg.format = in_bus_fmts[0];
> > +		in_fmt = in_bus_fmts[0];
> > +		if (crtc->helper_private &&
> > +		    crtc->helper_private->select_output_bus_format) {
> > +			in_fmt = crtc->helper_private->select_output_bus_format(
> > +							crtc,
> > +							crtc->state,
> > +							in_bus_fmts,
> > +							num_in_bus_fmts);
> > +			if (!in_fmt) {
> > +				kfree(in_bus_fmts);
> > +				return -ENOTSUPP;
> > +			}
> > +		}
> > +		cur_state->input_bus_cfg.format = in_fmt;
> 
> I don't think we should start poking at the CRTC internals, but we
> should rather provide a helper here.

It would probably look cleaner, yes.

> >  		cur_state->output_bus_cfg.format = out_bus_fmt;
> >  		kfree(in_bus_fmts);
> >  		return 0;
> > diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
> > index 881b03e4dc28..7c21ae1fe3ad 100644
> > --- a/include/drm/drm_modeset_helper_vtables.h
> > +++ b/include/drm/drm_modeset_helper_vtables.h
> > @@ -489,6 +489,37 @@ struct drm_crtc_helper_funcs {
> >  				     bool in_vblank_irq, int *vpos, int *hpos,
> >  				     ktime_t *stime, ktime_t *etime,
> >  				     const struct drm_display_mode *mode);
> > +
> > +	/**
> > +	 * @select_output_bus_format
> > +	 *
> > +	 * Called by the first connected DRM bridge to negotiate input media
> > +	 * bus format. CRTC is expected to pick preferable media formats from
> > +	 * the list supported by the DRM bridge chain.
> 
> There's nothing restricting it to bridges here. Please rephrase this to
> remove the bridge mention. The user is typically going to be the
> encoder, and bridges are just an automagic implementation of an encoder.
> 
> And generally speaking, I'd really like to have an implementation
> available before merging this.

There's a downstream implementation in the Xilinx kernel, which would
indeed be nice to upstream. This shouldn't block patches 1/4 to 3/4
though, those can be merged once review comments are taken into account.
diff mbox series

Patch

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 521a71c61b16..453ae3d174b4 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -32,6 +32,7 @@ 
 #include <drm/drm_edid.h>
 #include <drm/drm_encoder.h>
 #include <drm/drm_file.h>
+#include <drm/drm_modeset_helper_vtables.h>
 #include <drm/drm_of.h>
 #include <drm/drm_print.h>
 
@@ -879,7 +880,8 @@  static int select_bus_fmt_recursive(struct drm_bridge *first_bridge,
 	unsigned int i, num_in_bus_fmts = 0;
 	struct drm_bridge_state *cur_state;
 	struct drm_bridge *prev_bridge;
-	u32 *in_bus_fmts;
+	struct drm_crtc *crtc = crtc_state->crtc;
+	u32 *in_bus_fmts, in_fmt;
 	int ret;
 
 	prev_bridge = drm_bridge_get_prev_bridge(cur_bridge);
@@ -933,7 +935,20 @@  static int select_bus_fmt_recursive(struct drm_bridge *first_bridge,
 		return -ENOMEM;
 
 	if (first_bridge == cur_bridge) {
-		cur_state->input_bus_cfg.format = in_bus_fmts[0];
+		in_fmt = in_bus_fmts[0];
+		if (crtc->helper_private &&
+		    crtc->helper_private->select_output_bus_format) {
+			in_fmt = crtc->helper_private->select_output_bus_format(
+							crtc,
+							crtc->state,
+							in_bus_fmts,
+							num_in_bus_fmts);
+			if (!in_fmt) {
+				kfree(in_bus_fmts);
+				return -ENOTSUPP;
+			}
+		}
+		cur_state->input_bus_cfg.format = in_fmt;
 		cur_state->output_bus_cfg.format = out_bus_fmt;
 		kfree(in_bus_fmts);
 		return 0;
diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
index 881b03e4dc28..7c21ae1fe3ad 100644
--- a/include/drm/drm_modeset_helper_vtables.h
+++ b/include/drm/drm_modeset_helper_vtables.h
@@ -489,6 +489,37 @@  struct drm_crtc_helper_funcs {
 				     bool in_vblank_irq, int *vpos, int *hpos,
 				     ktime_t *stime, ktime_t *etime,
 				     const struct drm_display_mode *mode);
+
+	/**
+	 * @select_output_bus_format
+	 *
+	 * Called by the first connected DRM bridge to negotiate input media
+	 * bus format. CRTC is expected to pick preferable media formats from
+	 * the list supported by the DRM bridge chain.
+	 *
+	 * This callback is optional.
+	 *
+	 * Parameters:
+	 *
+	 * crtc:
+	 *     The CRTC.
+	 * crcs_state:
+	 *     New CRTC state.
+	 * supported_fmts:
+	 *     List of input bus formats supported by the bridge.
+	 * num_supported_fmts:
+	 *     Number of formats in the list.
+	 *
+	 * Returns:
+	 *
+	 * Preferred bus format from the list or 0 if CRTC doesn't support any
+	 * from the provided list.
+	 *
+	 */
+	u32 (*select_output_bus_format)(struct drm_crtc *crtc,
+					struct drm_crtc_state *crtc_state,
+					const u32 *supported_fmts,
+					int num_supported_fmts);
 };
 
 /**