Re: [PATCH v5 2/9] drm/bridge-connector: switch to using drmm allocations

2024-06-10 Thread Maxime Ripard
Hi,

+Hans

On Mon, Jun 10, 2024 at 02:46:03PM GMT, Dmitry Baryshkov wrote:
> On Mon, 10 Jun 2024 at 11:04, Maxime Ripard  wrote:
> >
> > Hi,
> >
> > On Fri, Jun 07, 2024 at 04:22:59PM GMT, Dmitry Baryshkov wrote:
> > > Turn drm_bridge_connector to using drmm_kzalloc() and
> > > drmm_connector_init() and drop the custom destroy function. The
> > > drm_connector_unregister() and fwnode_handle_put() are already handled
> > > by the drm_connector_cleanup() and so are safe to be dropped.
> > >
> > > Acked-by: Maxime Ripard 
> > > Signed-off-by: Dmitry Baryshkov 
> > > ---
> > >  drivers/gpu/drm/drm_bridge_connector.c | 23 +--
> > >  1 file changed, 5 insertions(+), 18 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/drm_bridge_connector.c 
> > > b/drivers/gpu/drm/drm_bridge_connector.c
> > > index 982552c9f92c..e093fc8928dc 100644
> > > --- a/drivers/gpu/drm/drm_bridge_connector.c
> > > +++ b/drivers/gpu/drm/drm_bridge_connector.c
> > > @@ -15,6 +15,7 @@
> > >  #include 
> > >  #include 
> > >  #include 
> > > +#include 
> > >  #include 
> > >  #include 
> > >
> > > @@ -193,19 +194,6 @@ drm_bridge_connector_detect(struct drm_connector 
> > > *connector, bool force)
> > >   return status;
> > >  }
> > >
> > > -static void drm_bridge_connector_destroy(struct drm_connector *connector)
> > > -{
> > > - struct drm_bridge_connector *bridge_connector =
> > > - to_drm_bridge_connector(connector);
> > > -
> > > - drm_connector_unregister(connector);
> > > - drm_connector_cleanup(connector);
> > > -
> > > - fwnode_handle_put(connector->fwnode);
> > > -
> > > - kfree(bridge_connector);
> > > -}
> > > -
> > >  static void drm_bridge_connector_debugfs_init(struct drm_connector 
> > > *connector,
> > > struct dentry *root)
> > >  {
> > > @@ -224,7 +212,6 @@ static const struct drm_connector_funcs 
> > > drm_bridge_connector_funcs = {
> > >   .reset = drm_atomic_helper_connector_reset,
> > >   .detect = drm_bridge_connector_detect,
> > >   .fill_modes = drm_helper_probe_single_connector_modes,
> > > - .destroy = drm_bridge_connector_destroy,
> > >   .atomic_duplicate_state = 
> > > drm_atomic_helper_connector_duplicate_state,
> > >   .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> > >   .debugfs_init = drm_bridge_connector_debugfs_init,
> > > @@ -328,7 +315,7 @@ struct drm_connector 
> > > *drm_bridge_connector_init(struct drm_device *drm,
> > >   int connector_type;
> > >   int ret;
> > >
> > > - bridge_connector = kzalloc(sizeof(*bridge_connector), GFP_KERNEL);
> > > + bridge_connector = drmm_kzalloc(drm, sizeof(*bridge_connector), 
> > > GFP_KERNEL);
> >
> > So you make destroy's kfree call unnecessary here ...
> >
> > >   if (!bridge_connector)
> > >   return ERR_PTR(-ENOMEM);
> > >
> > > @@ -383,9 +370,9 @@ struct drm_connector 
> > > *drm_bridge_connector_init(struct drm_device *drm,
> > >   return ERR_PTR(-EINVAL);
> > >   }
> > >
> > > - ret = drm_connector_init_with_ddc(drm, connector,
> > > -   _bridge_connector_funcs,
> > > -   connector_type, ddc);
> > > + ret = drmm_connector_init(drm, connector,
> > > +   _bridge_connector_funcs,
> > > +   connector_type, ddc);
> >
> > ... and here of drm_connector_cleanup.
> >
> > drm_connector_unregister wasn't needed, so can ignore it, but you leak a 
> > reference to
> > connector->fwnode since you don't call fwnode_handle_put anymore.
> >
> > We should register a drmm action right below the call to fwnode_handle_get 
> > too.
> 
> But drm_connector_cleanup() already contains
> fwnode_handle_put(connector->fwnode). Isn't that enough?

It does, but now I'm confused.

drm_bridge_connector_init takes a reference, drm_connector_init doesn't.
It will call drm_bridge_connector_destroy() that gives back its
reference (which makes sense to me), but then why do
drm_connector_cleanup() does? None of the drm_connector code even took
that reference, and we end up with a double-put.

It looks like it was introduced by commit 48c429c6d18d ("drm/connector:
Add a fwnode pointer to drm_connector and register with ACPI (v2)") from
Hans, which does call put, but never gets that reference.

It has nothing to do with this series anymore, but that's super fishy to
me, and the source of bugs as we can see here.

Maxime


signature.asc
Description: PGP signature


Re: [PATCH] drm/bridge/panel: Fix runtime warning on panel bridge release

2024-06-10 Thread Maxime Ripard
On Mon, Jun 10, 2024 at 11:27:39AM GMT, Adam Miotk wrote:
> Device managed panel bridge wrappers are created by calling to
> drm_panel_bridge_add_typed() and registering a release handler for
> clean-up when the device gets unbound.
> 
> Since the memory for this bridge is also managed and linked to the panel
> device, the release function should not try to free that memory.
> Moreover, the call to devm_kfree() inside drm_panel_bridge_remove() will
> fail in this case and emit a warning because the panel bridge resource
> is no longer on the device resources list (it has been removed from
> there before the call to release handlers).
> 
> Signed-off-by: Adam Miotk 

I've added a Fixes tag and applied to drm-misc-fixes, thanks!
Maxime


signature.asc
Description: PGP signature


Re: [PATCH] drm/komeda: check for error-valued pointer

2024-06-10 Thread Maxime Ripard
On Mon, Jun 10, 2024 at 11:20:56AM GMT, Amjad Ouled-Ameur wrote:
> komeda_pipeline_get_state() may return an error-valued pointer, thus
> check the pointer for negative or null value before dereferencing.
> 
> Signed-off-by: Amjad Ouled-Ameur 

I've added a Fixes tag and applied to drm-misc-fixes, thanks!
Maxime


signature.asc
Description: PGP signature


Re: [PATCH] drm/connector: hdmi: Fix kerneldoc warnings

2024-06-10 Thread Maxime Ripard
Hi,

On Mon, Jun 10, 2024 at 01:12:00PM GMT, Maxime Ripard wrote:
> It looks like the documentation for the HDMI-related fields recently
> added to both the drm_connector and drm_connector_state structures
> trigger some warnings because of their use of anonymous structures:
> 
>   $ scripts/kernel-doc -none include/drm/drm_connector.h
>   include/drm/drm_connector.h:1138: warning: Excess struct member 
> 'broadcast_rgb' description in 'drm_connector_state'
>   include/drm/drm_connector.h:1138: warning: Excess struct member 
> 'infoframes' description in 'drm_connector_state'
>   include/drm/drm_connector.h:1138: warning: Excess struct member 'avi' 
> description in 'drm_connector_state'
>   include/drm/drm_connector.h:1138: warning: Excess struct member 'hdr_drm' 
> description in 'drm_connector_state'
>   include/drm/drm_connector.h:1138: warning: Excess struct member 'spd' 
> description in 'drm_connector_state'
>   include/drm/drm_connector.h:1138: warning: Excess struct member 'vendor' 
> description in 'drm_connector_state'
>   include/drm/drm_connector.h:1138: warning: Excess struct member 
> 'is_limited_range' description in 'drm_connector_state'
>   include/drm/drm_connector.h:1138: warning: Excess struct member 
> 'output_bpc' description in 'drm_connector_state'
>   include/drm/drm_connector.h:1138: warning: Excess struct member 
> 'output_format' description in 'drm_connector_state'
>   include/drm/drm_connector.h:1138: warning: Excess struct member 
> 'tmds_char_rate' description in 'drm_connector_state'
>   include/drm/drm_connector.h:2112: warning: Excess struct member 'vendor' 
> description in 'drm_connector'
>   include/drm/drm_connector.h:2112: warning: Excess struct member 'product' 
> description in 'drm_connector'
>   include/drm/drm_connector.h:2112: warning: Excess struct member 
> 'supported_formats' description in 'drm_connector'
>   include/drm/drm_connector.h:2112: warning: Excess struct member 
> 'infoframes' description in 'drm_connector'
>   include/drm/drm_connector.h:2112: warning: Excess struct member 'lock' 
> description in 'drm_connector'
>   include/drm/drm_connector.h:2112: warning: Excess struct member 'audio' 
> description in 'drm_connector'
> 
> Create some intermediate structures instead of anonymous ones to silence
> the warnings.
> 
> Reported-by: Jani Nikula 
> Suggested-by: Jani Nikula 
> Fixes: 54cb39e2293b ("drm/connector: hdmi: Create an HDMI sub-state")
> Fixes: 948f01d5e559 ("drm/connector: hdmi: Add support for output format")
> Signed-off-by: Maxime Ripard 
> ---
>  include/drm/drm_connector.h | 207 +++-
>  1 file changed, 109 insertions(+), 98 deletions(-)
> 
> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> index e04a8a0d1bbd..1afee2939b71 100644
> --- a/include/drm/drm_connector.h
> +++ b/include/drm/drm_connector.h
> @@ -927,10 +927,72 @@ struct drm_connector_hdmi_infoframe {
>* @set: Is the content of @data valid?
>*/
>   bool set;
>  };
>  
> +/*
> + * struct drm_connector_hdmi_state - HDMI state container
> + */
> +struct drm_connector_hdmi_state {
> + /**
> +  * @broadcast_rgb: Connector property to pass the
> +  * Broadcast RGB selection value.
> +  */
> + enum drm_hdmi_broadcast_rgb broadcast_rgb;
> +
> + /**
> +  * @infoframes: HDMI Infoframes matching that state
> +  */
> + struct {
> + /**
> +  * @avi: AVI Infoframes structure matching our
> +  * state.
> +  */
> + struct drm_connector_hdmi_infoframe avi;
> +
> + /**
> +  * @hdr_drm: DRM (Dynamic Range and Mastering)
> +  * Infoframes structure matching our state.
> +  */
> + struct drm_connector_hdmi_infoframe hdr_drm;
> +
> + /**
> +  * @spd: SPD Infoframes structure matching our
> +  * state.
> +  */
> + struct drm_connector_hdmi_infoframe spd;
> +
> + /**
> +  * @vendor: HDMI Vendor Infoframes structure
> +  * matching our state.
> +  */
> + struct drm_connector_hdmi_infoframe hdmi;
> + } infoframes;
> +
> + /**
> +  * @is_limited_range: Is the output supposed to use a limited
> +  * RGB Quantization Range or not?
> +  */
> + bool is_limited_range;
> +
> + /**
> +  * @output_bpc: Bits per color channel to output.
> +  */
> + unsigned int output_bpc;
> +
> + /**
> +  * @output_format: Pixel format to output in.
> +  */
> + enum hdmi_colorspace output_format;
> +
> + /**
> +  * @tmds_char_rate: TMDS Character Rate, in Hz.
> +  */
> + unsigned long long tmds_char_rate;
> +
> +}

FTR, there's a missing ; here

Maxime


signature.asc
Description: PGP signature


[PATCH] drm/connector: hdmi: Fix kerneldoc warnings

2024-06-10 Thread Maxime Ripard
It looks like the documentation for the HDMI-related fields recently
added to both the drm_connector and drm_connector_state structures
trigger some warnings because of their use of anonymous structures:

  $ scripts/kernel-doc -none include/drm/drm_connector.h
  include/drm/drm_connector.h:1138: warning: Excess struct member 
'broadcast_rgb' description in 'drm_connector_state'
  include/drm/drm_connector.h:1138: warning: Excess struct member 'infoframes' 
description in 'drm_connector_state'
  include/drm/drm_connector.h:1138: warning: Excess struct member 'avi' 
description in 'drm_connector_state'
  include/drm/drm_connector.h:1138: warning: Excess struct member 'hdr_drm' 
description in 'drm_connector_state'
  include/drm/drm_connector.h:1138: warning: Excess struct member 'spd' 
description in 'drm_connector_state'
  include/drm/drm_connector.h:1138: warning: Excess struct member 'vendor' 
description in 'drm_connector_state'
  include/drm/drm_connector.h:1138: warning: Excess struct member 
'is_limited_range' description in 'drm_connector_state'
  include/drm/drm_connector.h:1138: warning: Excess struct member 'output_bpc' 
description in 'drm_connector_state'
  include/drm/drm_connector.h:1138: warning: Excess struct member 
'output_format' description in 'drm_connector_state'
  include/drm/drm_connector.h:1138: warning: Excess struct member 
'tmds_char_rate' description in 'drm_connector_state'
  include/drm/drm_connector.h:2112: warning: Excess struct member 'vendor' 
description in 'drm_connector'
  include/drm/drm_connector.h:2112: warning: Excess struct member 'product' 
description in 'drm_connector'
  include/drm/drm_connector.h:2112: warning: Excess struct member 
'supported_formats' description in 'drm_connector'
  include/drm/drm_connector.h:2112: warning: Excess struct member 'infoframes' 
description in 'drm_connector'
  include/drm/drm_connector.h:2112: warning: Excess struct member 'lock' 
description in 'drm_connector'
  include/drm/drm_connector.h:2112: warning: Excess struct member 'audio' 
description in 'drm_connector'

Create some intermediate structures instead of anonymous ones to silence
the warnings.

Reported-by: Jani Nikula 
Suggested-by: Jani Nikula 
Fixes: 54cb39e2293b ("drm/connector: hdmi: Create an HDMI sub-state")
Fixes: 948f01d5e559 ("drm/connector: hdmi: Add support for output format")
Signed-off-by: Maxime Ripard 
---
 include/drm/drm_connector.h | 207 +++-
 1 file changed, 109 insertions(+), 98 deletions(-)

diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index e04a8a0d1bbd..1afee2939b71 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -927,10 +927,72 @@ struct drm_connector_hdmi_infoframe {
 * @set: Is the content of @data valid?
 */
bool set;
 };
 
+/*
+ * struct drm_connector_hdmi_state - HDMI state container
+ */
+struct drm_connector_hdmi_state {
+   /**
+* @broadcast_rgb: Connector property to pass the
+* Broadcast RGB selection value.
+*/
+   enum drm_hdmi_broadcast_rgb broadcast_rgb;
+
+   /**
+* @infoframes: HDMI Infoframes matching that state
+*/
+   struct {
+   /**
+* @avi: AVI Infoframes structure matching our
+* state.
+*/
+   struct drm_connector_hdmi_infoframe avi;
+
+   /**
+* @hdr_drm: DRM (Dynamic Range and Mastering)
+* Infoframes structure matching our state.
+*/
+   struct drm_connector_hdmi_infoframe hdr_drm;
+
+   /**
+* @spd: SPD Infoframes structure matching our
+* state.
+*/
+   struct drm_connector_hdmi_infoframe spd;
+
+   /**
+* @vendor: HDMI Vendor Infoframes structure
+* matching our state.
+*/
+   struct drm_connector_hdmi_infoframe hdmi;
+   } infoframes;
+
+   /**
+* @is_limited_range: Is the output supposed to use a limited
+* RGB Quantization Range or not?
+*/
+   bool is_limited_range;
+
+   /**
+* @output_bpc: Bits per color channel to output.
+*/
+   unsigned int output_bpc;
+
+   /**
+* @output_format: Pixel format to output in.
+*/
+   enum hdmi_colorspace output_format;
+
+   /**
+* @tmds_char_rate: TMDS Character Rate, in Hz.
+*/
+   unsigned long long tmds_char_rate;
+
+}
+
 /**
  * struct drm_connector_state - mutable connector state
  */
 struct drm_connector_state {
/** @connector: backpointer to the connector */
@@ -1076,67 +1138,11 @@ struct drm_connector_state {
 
/**
 * @hdmi: HDMI-related variable and properties. Filled by
 * @drm_atomic_helper_connector_hdmi_check().
  

Re: [PATCH v2 0/3] Move blender setup from individual planes to crtc commit in sun4i-drm

2024-06-10 Thread Maxime Ripard
On Sat, 24 Feb 2024 16:05:57 +0100, Ondřej Jirman wrote:
> From: Ondrej Jirman 
> 
> This series refactors blender setup from individual planes to a common
> place where it can be performed at once and is easier to reason about.
> 
> In the process this fixes a few bugs that allowed blender pipes to be
> disabled while corresponding DRM planes were requested to be enabled.
> 
> [...]

Applied to misc/kernel.git (drm-misc-next).

Thanks!
Maxime



Re: (subset) [PATCH] drm: add missing MODULE_DESCRIPTION() macros

2024-06-10 Thread Maxime Ripard
On Sun, 09 Jun 2024 11:42:53 -0700, Jeff Johnson wrote:
> On x86, make allmodconfig && make W=1 C=1 reports:
> WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/gpu/drm/gud/gud.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/drm_panel_orientation_quirks.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/drm_mipi_dbi.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/gpu/drm/i915/kvmgt.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/gpu/drm/udl/udl.o
> 
> [...]

Applied to misc/kernel.git (drm-misc-next).

Thanks!
Maxime



Re: (subset) [PATCH] drm/bridge: add missing MODULE_DESCRIPTION() macros

2024-06-10 Thread Maxime Ripard
On Sun, 09 Jun 2024 10:06:17 -0700, Jeff Johnson wrote:
> make allmodconfig && make W=1 C=1 reports:
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/bridge/lontium-lt9611.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/bridge/lontium-lt9611uxc.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/bridge/sil-sii8620.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/bridge/sii9234.o
> 
> Add the missing invocations of the MODULE_DESCRIPTION() macro.
> 
> [...]

Applied to misc/kernel.git (drm-misc-next).

Thanks!
Maxime



Re: (subset) [PATCH] drm/tiny: add missing MODULE_DESCRIPTION() macros

2024-06-10 Thread Maxime Ripard
On Sun, 09 Jun 2024 10:20:27 -0700, Jeff Johnson wrote:
> make allmodconfig && make W=1 C=1 reports:
> WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/gpu/drm/tiny/bochs.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/tiny/cirrus.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/tiny/gm12u320.o
> 
> Add the missing invocations of the MODULE_DESCRIPTION() macro.
> 
> [...]

Applied to misc/kernel.git (drm-misc-next).

Thanks!
Maxime



Re: (subset) [PATCH] drm/panel: add missing MODULE_DESCRIPTION() macros

2024-06-10 Thread Maxime Ripard
On Sun, 09 Jun 2024 09:53:21 -0700, Jeff Johnson wrote:
> make allmodconfig && make W=1 C=1 reports:
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/panel/panel-abt-y030xx067a.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/panel/panel-auo-a030jtn01.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/panel/panel-innolux-ej030na.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/panel/panel-newvision-nv3052c.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/panel/panel-novatek-nt39016.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/panel/panel-orisetech-ota5601a.o
> 
> [...]

Applied to misc/kernel.git (drm-misc-next).

Thanks!
Maxime



Re: (subset) [PATCH] drm/tests: add missing MODULE_DESCRIPTION() macros

2024-06-10 Thread Maxime Ripard
On Thu, 06 Jun 2024 21:42:46 -0700, Jeff Johnson wrote:
> make allmodconfig && make W=1 C=1 reports:
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/tests/drm_kunit_helpers.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/tests/drm_buddy_test.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/tests/drm_cmdline_parser_test.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/tests/drm_connector_test.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/tests/drm_damage_helper_test.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/tests/drm_dp_mst_helper_test.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/tests/drm_exec_test.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/tests/drm_format_test.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/tests/drm_framebuffer_test.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/tests/drm_gem_shmem_test.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/tests/drm_managed_test.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/tests/drm_mm_test.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/tests/drm_modes_test.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/tests/drm_plane_helper_test.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/tests/drm_probe_helper_test.o
> WARNING: modpost: missing MODULE_DESCRIPTION() in 
> drivers/gpu/drm/tests/drm_rect_test.o
> 
> [...]

Applied to misc/kernel.git (drm-misc-next).

Thanks!
Maxime



Re: [PATCH v5 9/9] drm/msm/hdmi: also send the SPD and HDMI Vendor Specific InfoFrames

2024-06-10 Thread Maxime Ripard
On Fri, 7 Jun 2024 16:23:06 +0300, Dmitry Baryshkov wrote:
> Extend the driver to send SPD and HDMI Vendor Specific InfoFrames.
> 
> While the HDMI block has special block to send HVS InfoFrame, use
> GENERIC0 block instead. VENSPEC_INFO registers pack frame data in a way
> that requires manual repacking in the driver, while GENERIC0 doesn't
> 
> [ ... ]

Acked-by: Maxime Ripard 

Thanks!
Maxime


Re: [PATCH v5 1/9] drm/connector: hdmi: allow disabling Audio Infoframe

2024-06-10 Thread Maxime Ripard
On Fri, 7 Jun 2024 16:22:58 +0300, Dmitry Baryshkov wrote:
> Add drm_atomic_helper_connector_hdmi_disable_audio_infoframe(), an API
> to allow the driver disable sending the Audio Infoframe. This is to be
> used by the drivers if setup of the infoframes is not tightly coupled
> with the audio functionality and just disabling the audio playback
> doesn't stop the HDMI hardware from sending the Infoframe.
> 
> [ ... ]

Acked-by: Maxime Ripard 

Thanks!
Maxime


Re: [PATCH v5 2/9] drm/bridge-connector: switch to using drmm allocations

2024-06-10 Thread Maxime Ripard
Hi,

On Fri, Jun 07, 2024 at 04:22:59PM GMT, Dmitry Baryshkov wrote:
> Turn drm_bridge_connector to using drmm_kzalloc() and
> drmm_connector_init() and drop the custom destroy function. The
> drm_connector_unregister() and fwnode_handle_put() are already handled
> by the drm_connector_cleanup() and so are safe to be dropped.
> 
> Acked-by: Maxime Ripard 
> Signed-off-by: Dmitry Baryshkov 
> ---
>  drivers/gpu/drm/drm_bridge_connector.c | 23 +--
>  1 file changed, 5 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_bridge_connector.c 
> b/drivers/gpu/drm/drm_bridge_connector.c
> index 982552c9f92c..e093fc8928dc 100644
> --- a/drivers/gpu/drm/drm_bridge_connector.c
> +++ b/drivers/gpu/drm/drm_bridge_connector.c
> @@ -15,6 +15,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  
> @@ -193,19 +194,6 @@ drm_bridge_connector_detect(struct drm_connector 
> *connector, bool force)
>   return status;
>  }
>  
> -static void drm_bridge_connector_destroy(struct drm_connector *connector)
> -{
> - struct drm_bridge_connector *bridge_connector =
> - to_drm_bridge_connector(connector);
> -
> - drm_connector_unregister(connector);
> - drm_connector_cleanup(connector);
> -
> - fwnode_handle_put(connector->fwnode);
> -
> - kfree(bridge_connector);
> -}
> -
>  static void drm_bridge_connector_debugfs_init(struct drm_connector 
> *connector,
> struct dentry *root)
>  {
> @@ -224,7 +212,6 @@ static const struct drm_connector_funcs 
> drm_bridge_connector_funcs = {
>   .reset = drm_atomic_helper_connector_reset,
>   .detect = drm_bridge_connector_detect,
>   .fill_modes = drm_helper_probe_single_connector_modes,
> - .destroy = drm_bridge_connector_destroy,
>   .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
>   .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
>   .debugfs_init = drm_bridge_connector_debugfs_init,
> @@ -328,7 +315,7 @@ struct drm_connector *drm_bridge_connector_init(struct 
> drm_device *drm,
>   int connector_type;
>   int ret;
>  
> - bridge_connector = kzalloc(sizeof(*bridge_connector), GFP_KERNEL);
> + bridge_connector = drmm_kzalloc(drm, sizeof(*bridge_connector), 
> GFP_KERNEL);

So you make destroy's kfree call unnecessary here ...

>   if (!bridge_connector)
>   return ERR_PTR(-ENOMEM);
>  
> @@ -383,9 +370,9 @@ struct drm_connector *drm_bridge_connector_init(struct 
> drm_device *drm,
>   return ERR_PTR(-EINVAL);
>   }
>  
> - ret = drm_connector_init_with_ddc(drm, connector,
> -   _bridge_connector_funcs,
> -   connector_type, ddc);
> + ret = drmm_connector_init(drm, connector,
> +   _bridge_connector_funcs,
> +   connector_type, ddc);

... and here of drm_connector_cleanup.

drm_connector_unregister wasn't needed, so can ignore it, but you leak a 
reference to
connector->fwnode since you don't call fwnode_handle_put anymore.

We should register a drmm action right below the call to fwnode_handle_get too.

Maxime


signature.asc
Description: PGP signature


Re: [RFC PATCH 2/3] drm/tidss: Add support for display sharing

2024-06-06 Thread Maxime Ripard
On Wed, May 29, 2024 at 08:16:46PM GMT, Devarsh Thakkar wrote:
> Hi Javier, Maxime, Daniel,
> 
> Sorry for the delay. Please find response inline.
> 
> On 16/05/24 18:21, Daniel Vetter wrote:
> > On Wed, May 15, 2024 at 04:45:09PM +0200, Javier Martinez Canillas wrote:
> >> Devarsh Thakkar  writes:
> 
> [..]
> 
> >>
> >> If I understand you correctly, for now the only real use case is when the
> >> the RTOS owns / manages the complete display pipeline and Linux can only
> >> own video planes.
> >>
> 
> Not exactly, What I mean is that this is the default configuration/example we
> intend to provide to customer as an out-of-box demo . But flexibility is
> provided to customer to modify the display sharing configuration per their
> use-case, for e.g at RTOS side in place of device-tree, we have a sysconfig
> menu [1] using which they can select the desired configuration, furthermore
> they can go ahead and edit the code too, so Linux driver is expected to be
> flexible to support different configurations as supported by the HW.

Everything you stated above can be achieved with the solutions we've
been suggesting too.

> I have a limited view of all possible use-cases which customer may try out
> with different configurations

I think that's a problem in itself. In order to properly reflect and
discuss a solution, we first need to have a problem. "Flexible
solutions" in practice never really work because you always end up not
flexible enough and still have to rework the whole thing. Except it's
now harder to do since you created something complicated first.

> few examples are shared below part from the one discussed earlier :
> 
> [Examples]:
> 1) Customer is running Linux as main OS but using RTOS to control some
> external peripherals like temperature sensor, motion sensor e.t.c. In that
> case if they want to display the sensor data too on the same monitor, then
> they can use the configuration where RTOS use single plane and Linux as the
> DSS master.

How would that work in real-world? If Linux is in charge of the display,
it can shut down the output whenever it wants too, including shutting
down the clocks or power domains, which then would probably make the
firmware crash?

A much more robust solution here would be to have either the firmware in
charge of the display and delegate a few planes, or provide some way for
Linux to access those sensors while being fully in charge of the
display.

> 2) Another configuration could be where RTOS want to control one full
> end-to-end pipeline going to one connector and Linux want to control full
> end-to-end pipeline going to another connector, that can be supported too
> using this scheme (as shared in this series).

That one is easy: you make the firmware adjust the DT when it boots
Linux and thus restrict the part of the display controller it can use.

It's mostly a DT binding issue.

> 3) Also I think, this device-tree based scheme could be leveraged in
> virtualization too with static partitioning based scheme using Xen for e.g. we
> split the DSS resources between host (DOM0) and the guest (DOMU).

I'm not sure you can leverage virtio at the firmware level, but
otherwise, it's pretty much what we've been suggesting the whole time:
make a generic interface between the firmware and Linux, and then write
a KMS driver for that interface.

Then the firmware can delegate planes to Linux, just like the hypervisor
would to a guest VM.

> >> The opposite is supported by the DSS hardware (thanks to its feature that
> >> allows partitioning the register space and having multiple per-host IRQs) 
> >> but it's not a real use case yet. The reason why this case is added to the
> >> DT binding is as you said for flexiblity and make the design future-proof.
>
> Not really, as explained above we are documenting all possible configurations
> which hardware supports as supported in software in the SDK and that's what we
> are aiming for upstream too.

Generally speaking, not all hardware configurations make sense to run
with in Linux, and there's tons of drivers were we support only a
limited set of capabilities precisely because some simply don't work
well with Linux. I'm glad you're (and your organization) is that
committed to Linux, but I don't think having that as an absolute goal is
reasonable.

Let's work on usecases, and make the most of it instead. In your
examples, 2 and 3 make total sense to be supported in Linux. I'm not
sure 1) does.

> [..] I'm probably missing something then here, but if the Linux side of
>  things is expected to keep the current configuration and keep it active
>  for it to work, what use-case would it be useful for?
> 
> >>>
> >>> It's just one of the partitioning possibilities that I mentioned here, 
> >>> that
> >>> Linux is in control of DSS as a whole and the user want the other host 
> >>> (be it
> >>> RTOS or any other core) to control a single plane. For e.g it could be 
> >>> Linux
> >>> (with GPU rendering) 

Re: [PATCH v13 5/9] drm/dp: Add refresh rate divider to struct representing AS SDP

2024-06-06 Thread Maxime Ripard
On Thu, Jun 06, 2024 at 02:38:45PM GMT, Jani Nikula wrote:
> On Wed, 05 Jun 2024, Mitul Golani  
> wrote:
> > Add target_rr_divider to structure representing AS SDP.
> > It is valid only in FAVT mode, sink device ignores the bit in AVT
> > mode.
> >
> > --v2:
> > - Update commit header and send patch to dri-devel.
> >
> > Signed-off-by: Mitul Golani 
> > Reviewed-by: Arun R Murthy 
> 
> Maxime, Maarten, Thomas, ack for merging this via drm-intel-next?

Acked-by: Maxime Ripard 

Maxime


signature.asc
Description: PGP signature


Re: [PATCH v3 1/2] dt-bindings: display: panel: Add WL-355608-A8 panel

2024-06-06 Thread Maxime Ripard
On Thu, Jun 06, 2024 at 09:48:54PM GMT, Ryan Walklin wrote:
> On Thu, 6 Jun 2024, at 9:32 PM, Maxime Ripard wrote:
> Hi Maxime, thanks for reviewing.
> 
> > Where has this consensus been found?
> 
> As Neil notes Conor suggested it [1], and we did consider Hironori's
> suggestion [2] of using anbernic as the vendor prefix, although my
> (not strong) feeling at the time was because Anbernic is not the panel
> vendor, just integrating an unknown OEM's panel into their devices, so
> at the time I fit was not quite accurate to say Anbernic was the
> vendor.
> 
> Some discussion was also had on IRC at #linux-sunxi [3]. Admittedly
> not a *broad* consensus, but all offered opinions were taken and the
> patch was accepted subsequently.

Respectfully, #linux-sunxi isn't the persons you should be discussing
this with.

Maxime


signature.asc
Description: PGP signature


Re: [PATCH v3 1/2] dt-bindings: display: panel: Add WL-355608-A8 panel

2024-06-06 Thread Maxime Ripard
On Thu, Jun 06, 2024 at 11:37:31AM GMT, Neil Armstrong wrote:
> On 06/06/2024 11:32, Maxime Ripard wrote:
> > On Fri, May 31, 2024 at 09:12:14AM GMT, Ryan Walklin wrote:
> > > The WL-355608-A8 is a 3.5" 640x480@60Hz RGB LCD display used in a
> > > number of handheld gaming devices made by Anbernic. By consensus a
> > > vendor prefix is not provided as the panel OEM is unknown.
> > 
> > Where has this consensus been found?
> > 
> > I had a look at the previous discussions, and I can't find any consensus
> > being reached there. And for that kind of thing, having the ack or
> > review of any of the DT maintainers would have been great.
> 
> There was a consensus with Conor, this is why he acked v2, see
> https://lore.kernel.org/all/20240525-velvet-citable-a45dd06847a7@spud/

It's probably a matter of semantics here, but if it's with only one
person, it's not a consensus but an agreement.

> ```
> I think if we genuinely do not know what the vendor is then we just
> don't have a prefix.
> ```

And even then, I don't interpret Conor's statement as a formal agreement
but rather an acknowledgment of the issue.

> I agree with Conor so I applied the patchset after Connor reviewed it and the 
> comment was fixed in v3:
> https://lore.kernel.org/all/20240530-satchel-playgroup-e8aa6937b8b9@spud/

Yeah, I know. Still, it's a major deviation to what we've always been
doing, getting the DT maintainers voice on that would have been a good
idea.

Maxime


signature.asc
Description: PGP signature


[PULL] drm-misc-next

2024-06-06 Thread Maxime Ripard
pport for XLCDC using IP specific driver ops
  drm: atmel-hlcdc: add DPI mode support for XLCDC
  drm: atmel-hlcdc: add vertical and horizontal scaling support for XLCDC
  drm: atmel-hlcdc: add support for DSI output formats
  drm: atmel-hlcdc: add LCD controller layer definition for sam9x75

Marek Vasut (1):
  drm/bridge: tc358767: Enable FRMSYNC timing generator

MarileneGarcia (1):
  drm/dp: Fix documentation warning

Maxime Ripard (32):
  Merge drm/drm-next into drm-misc-next
  drm/connector: Introduce an HDMI connector initialization function
  drm/tests: connector: Add tests for drmm_connector_hdmi_init
  drm/connector: hdmi: Create an HDMI sub-state
  drm/connector: hdmi: Add output BPC to the connector state
  drm/mode_object: Export drm_mode_obj_find_prop_id for tests
  drm/tests: Add output bpc tests
  drm/connector: hdmi: Add support for output format
  drm/tests: Add output formats tests
  drm/display: hdmi: Add HDMI compute clock helper
  drm/tests: Add HDMI TDMS character rate tests
  drm/connector: hdmi: Calculate TMDS character rate
  drm/tests: Add TDMS character rate connector state tests
  drm/connector: hdmi: Add custom hook to filter TMDS character rate
  drm/tests: Add HDMI connector rate filter hook tests
  drm/connector: hdmi: Compute bpc and format automatically
  drm/tests: Add HDMI connector bpc and format tests
  drm/doc: Remove unused Broadcast RGB Property
  drm/connector: hdmi: Add Broadcast RGB property
  drm/tests: Add tests for Broadcast RGB property
  drm/connector: hdmi: Add RGB Quantization Range to the connector state
  drm/tests: Add RGB Quantization tests
  drm/connector: hdmi: Add Infoframes generation
  drm/tests: Add infoframes test
  drm/connector: hdmi: Create Infoframe DebugFS entries
  drm/vc4: hdmi: Switch to HDMI connector
  drm/vc4: tests: Remove vc4_dummy_plane structure
  drm/vc4: tests: Convert to plane creation helper
  drm/rockchip: inno_hdmi: Switch to HDMI connector
  drm/sun4i: hdmi: Switch to HDMI connector
  drm/sun4i: Fix compilation error
  drm/display: Fix HDMI state helper dependency

Maíra Canal (6):
  drm/v3d: Add Performance Counters descriptions for V3D 4.2 and 7.1
  drm/v3d: Different V3D versions can have different number of perfcnt
  drm/v3d: Create a new V3D parameter for the maximum number of perfcnt
  drm/v3d: Create new IOCTL to expose performance counters information
  drm/v3d: Use V3D_MAX_COUNTERS instead of V3D_PERFCNT_NUM
  drm/v3d: Deprecate the use of the Performance Counters enum

Pin-yen Lin (2):
  drm/panel-edp: Add support for several panels
  drm/panel-edp: Add more panels with conservative timings

Ryan Walklin (2):
  dt-bindings: display: panel: Add WL-355608-A8 panel
  drm: panel: nv3052c: Add WL-355608-A8 panel

Sam Ravnborg (1):
  MAINTAINERS: drm: Drop sam as panel reviewer

Sean Anderson (5):
  drm: xlnx: Store base pointers in zynqmp_disp directly
  drm: xlnx: Fix kerneldoc
  drm: zynqmp_dp: Downgrade log level for aux retries message
  drm: zynqmp_dp: Adjust training values per-lane
  drm: zynqmp_dpsub: Always register bridge

Sui Jingfeng (15):
  drm/debugfs: Drop conditionals around of_node pointers
  drm/panel: ili9341: Remove a superfluous else after return
  drm/drm-bridge: Drop conditionals around of_node pointers
  drm/bridge: simple-bridge: Remove a redundant check on existence of 
bridge->encoder
  drm/bridge: tfp410: Remove a redundant check on existence of 
bridge->encoder
  drm/bridge: nxp-ptn3460: Remove a redundant check on existence of 
bridge->encoder
  drm/bridge: panel: Remove a redundant check on existence of 
bridge->encoder
  drm/bridge: it6505: Remove a redundant check on existence of 
bridge->encoder
  drm/bridge: adv7511: Remove a redundant check on existence of 
bridge->encoder
  drm/bridge: cdns-mhdp8546: Remove a redundant check on existence of 
bridge->encoder
  drm/bridge: megachips-stdp-ge-b850v3-fw: Remove a redundant check on 
existence of bridge->encoder
  drm/bridge: synopsys: dw-mipi-dsi: Remove a redundant check on existence 
of bridge->encoder
  drm/bridge: lt9611uxc: Remove a redundant check on existence of 
bridge->encoder
  drm/bridge: imx: Remove redundant checks on existence of bridge->encoder
  drm/bridge: analogix: Remove redundant checks on existence of 
bridge->encoder

Thomas Zimmermann (61):
  Merge drm/drm-next into drm-misc-next
  drm/fbdev-generic: Do not set physical framebuffer address
  fbdev/deferred-io: Move pageref setup into separate helper
  fbdev/deferred-io: Clean up pageref on lastclose
  fbdev/deferred-io: Test screen_buffer for vmalloc'ed memory
  fbdev/deferred-io: Test smem_start for I/O memory
  fbdev/deferred-io

Re: [PATCH v3 1/2] dt-bindings: display: panel: Add WL-355608-A8 panel

2024-06-06 Thread Maxime Ripard
On Fri, May 31, 2024 at 09:12:14AM GMT, Ryan Walklin wrote:
> The WL-355608-A8 is a 3.5" 640x480@60Hz RGB LCD display used in a
> number of handheld gaming devices made by Anbernic. By consensus a
> vendor prefix is not provided as the panel OEM is unknown.

Where has this consensus been found?

I had a look at the previous discussions, and I can't find any consensus
being reached there. And for that kind of thing, having the ack or
review of any of the DT maintainers would have been great.

For this kind of cases, we usually use the device it's attached to as
the vendor, so anbernic in this case. Can you send a followup patch?

Maxime


signature.asc
Description: PGP signature


Re: [PATCH 00/14] Add initial support for the Rockchip RK3588 HDMI TX Controller

2024-06-05 Thread Maxime Ripard
On Wed, Jun 05, 2024 at 11:28:41AM GMT, neil.armstr...@linaro.org wrote:
> Hi,
> 
> On 05/06/2024 11:25, Andy Yan wrote:
> > 
> > Hi,
> > 
> > At 2024-06-05 04:33:57, "Cristian Ciocaltea" 
> >  wrote:
> > > On 6/3/24 4:08 PM, neil.armstr...@linaro.org wrote:
> > > > Hi,
> > > > 
> > > > On 03/06/2024 15:03, Heiko Stuebner wrote:
> > > > > Am Montag, 3. Juni 2024, 14:14:17 CEST schrieb Andy Yan:
> > > > > > Hi Neil:
> > > > > > 
> > > > > > On 6/3/24 16:55, Neil Armstrong wrote:
> > > > > > > Hi Christian,
> > > > > > > 
> > > > > > > On 01/06/2024 15:12, Cristian Ciocaltea wrote:
> > > > > > > > The RK3588 SoC family integrates a Quad-Pixel (QP) variant of 
> > > > > > > > the
> > > > > > > > Synopsys DesignWare HDMI TX controller used in the previous 
> > > > > > > > SoCs.
> > > > > > > > 
> > > > > > > > It is HDMI 2.1 compliant and supports the following features, 
> > > > > > > > among
> > > > > > > > others:
> > > > > > > > 
> > > > > > > .
> > > > > > > 
> > > > > > > ..
> > > > > > > 
> > > > > > > > * SCDC I2C DDC access
> > > > > > > > * TMDS Scrambler enabling 2160p@60Hz with RGB/YCbCr4:4:4
> > > > > > > > * YCbCr4:2:0 enabling 2160p@60Hz at lower HDMI link speeds
> > > > > > > > * Multi-stream audio
> > > > > > > > * Enhanced Audio Return Channel (EARC)
> > > > > > > -> Those features were already supported by the HDMI 2.0a 
> > > > > > > compliant
> > > > > > > HW, just
> > > > > > > list the _new_ features for HDMI 2.1
> > > > > > > 
> > > > > > > I did a quick review of your patchset and I don't understand why 
> > > > > > > you
> > > > > > > need
> > > > > > > to add a separate dw-hdmi-qp.c since you only need simple variants
> > > > > > > of the I2C
> > > > > > > bus, infoframe and bridge setup.
> > > > > > > 
> > > > > > > Can you elaborate further ? isn't this Quad-Pixel (QP) TX 
> > > > > > > controller
> > > > > > > version
> > > > > > > detectable at runtime ?
> > > > > > > 
> > > > > > > I would prefer to keep a single dw-hdmi driver if possible.
> > > > > > 
> > > > > > 
> > > > > > 
> > > > > > The QP HDMI controller is a completely different variant with 
> > > > > > totally
> > > > > > different
> > > > > > registers layout, see PATCH 13/14.
> > > > > > I think make it a separate driver will be easier for development and
> > > > > > maintenance.
> > > > > 
> > > > > I'm with Andy here. Trying to navigate a driver for two IP blocks 
> > > > > really
> > > > > sounds taxing especially when both are so different.
> > > 
> > > Thank you all for the valuable feedback!
> > > 
> > > > I agree, I just wanted more details than "variant of the
> > > > Synopsys DesignWare HDMI TX controller", if the register mapping is 100%
> > > > different, and does not match at all with the old IP, then it's indeed 
> > > > time
> > > > to make a brand new driver, but instead of doing a mix up, it's time to
> > > > extract
> > > > the dw-hdmi code that could be common helpers into a dw-hdmi-common 
> > > > module
> > > > and use them.
> > > 
> > > Sounds good, will handle this in v2.
> > > 
> > > > As I see, no "driver" code can be shared, only DRM plumbings, so perhaps
> > > > those
> > > > plumbing code should go into the DRM core ?
> > > > 
> > > > In any case, please add more details on the cover letter, including the
> > > > detailed
> > > > HW differrence and the design you chose so support this new IP.
> > > 
> > > Andy, could you please help with a summary of the HW changes?
> > > The information I could provide is rather limited, since I don't have
> > > access to any DW IP datasheets and I'm also not familiar enough with the
> > > old variant.
> > > 
> >   Accurately, we should refer to it as an entirely new IP,it has nothing in 
> > common with
> > the current mainline dw-hdmi。 The only  commonality is that they both come 
> > from
> > Synopsys DesignWare:
> > (1)It has a 100% different register mapping
> > (2)It supports FRL and DSC
> > (3)different configuration flow in many places。
> > 
> > So I have the same feeling with Heiko and Maxime:
> > The DW_HDMI_QP should have a  separate driver and with it's  own CONFIG  
> > such as DRM_DW_HDMI_QP  in Kconfig.
> > and the rockchip part should also be split from dw_hdmi-rockchip.c.
> > I am sorry we mixed them in dw_hdmi-rockchip.c when we develop the bsp 
> > driver,but we really regretted this decision
> > when  we repeatedly broke compatibility with dw-hdmi on other socs。
> 
> Yes please, and as I say, if there's code common with the old dw-hdmi, please 
> add a common
> module if this code can't be moved in core bridge helpers.

And chances are that the common code is actually there to deal with HDMI
spec itself and not really the hardware, which is solved by moving both
drivers to the HDMI helpers that just got merged.

Maxime


signature.asc
Description: PGP signature


Re: (subset) [PATCH] drm/v3d: Fix perfmon build error/warning

2024-06-05 Thread Maxime Ripard
On Tue, 04 Jun 2024 17:02:10 +0100, Tvrtko Ursulin wrote:
> Move static const array into the source file to fix the "defined but not
> used" errors.
> 
> The fix is perhaps not the prettiest due hand crafting the array sizes
> in v3d_performance_counters.h, but I did add some build time asserts to
> validate the counts look sensible, so hopefully it is good enough for a
> quick fix.
> 
> [...]

Applied to misc/kernel.git (drm-misc-next).

Thanks!
Maxime



Re: [PATCH] drm/v3d: Fix perfmon build error/warning

2024-06-05 Thread Maxime Ripard
Hi,

On Wed, Jun 05, 2024 at 08:19:34AM GMT, Iago Toral wrote:
> Thanks for looking at ixing this Tvrtko.
> 
> El mar, 04-06-2024 a las 17:02 +0100, Tvrtko Ursulin escribió:
> > From: Tvrtko Ursulin 
> > 
> > Move static const array into the source file to fix the "defined but
> > not
> > used" errors.
> > 
> > The fix is perhaps not the prettiest due hand crafting the array
> > sizes
> > in v3d_performance_counters.h, but I did add some build time asserts
> > to
> > validate the counts look sensible, so hopefully it is good enough for
> > a
> > quick fix.
> > 
> 
> If we need this to go in ASAP I am fine with this patch as-is, so:
> 
> Reviewed-by: Iago Toral Quiroga 
> 
> With that said, if we are still in time for a bit of iteration may I
> suggest that instead of hard-coding the counters we instead add helper
> functions in drivers/gpu/drm/v3d/v3d_perfmon.c that call ARRAY_SIZE on
> the corresponding array based on v3d->ver? It is fine if we prefer to
> merge this as-is and do this change later as a follow-up patch.

This is blocking the merge from drm-misc-next into drm/next at the
moment, so I'm going to merge this patch as is so I can send the PR
tomorrow.

Your comment looks fine to me too, so feel free to send a follow-up
patch to refine what's done here :)

Thanks!
Maxime


signature.asc
Description: PGP signature


Re: [PATCH] drm/mm: Remove unused drm_mm_replace_node

2024-06-05 Thread Maxime Ripard
On Tue, 4 Jun 2024 13:54:38 -0400, Rodrigo Vivi wrote:
> Last caller was removed with commit 078a5b498d6a ("drm/tests:
> Remove slow tests").
> 
> Cc: Maxime Ripard 
> Signed-off-by: Rodrigo Vivi 
> 
> [ ... ]

Acked-by: Maxime Ripard 

Thanks!
Maxime


Re: [PATCH 00/14] Add initial support for the Rockchip RK3588 HDMI TX Controller

2024-06-03 Thread Maxime Ripard
On Mon, Jun 03, 2024 at 03:03:12PM GMT, Heiko Stuebner wrote:
> Am Montag, 3. Juni 2024, 14:14:17 CEST schrieb Andy Yan:
> > Hi Neil:
> > 
> > On 6/3/24 16:55, Neil Armstrong wrote:
> > > Hi Christian,
> > > 
> > > On 01/06/2024 15:12, Cristian Ciocaltea wrote:
> > >> The RK3588 SoC family integrates a Quad-Pixel (QP) variant of the
> > >> Synopsys DesignWare HDMI TX controller used in the previous SoCs.
> > >>
> > >> It is HDMI 2.1 compliant and supports the following features, among
> > >> others:
> > >>
> > > .
> > > 
> > > ..
> > > 
> > >> * SCDC I2C DDC access
> > >> * TMDS Scrambler enabling 2160p@60Hz with RGB/YCbCr4:4:4
> > >> * YCbCr4:2:0 enabling 2160p@60Hz at lower HDMI link speeds
> > >> * Multi-stream audio
> > >> * Enhanced Audio Return Channel (EARC)
> > > -> Those features were already supported by the HDMI 2.0a compliant HW, 
> > > just
> > > list the _new_ features for HDMI 2.1
> > > 
> > > I did a quick review of your patchset and I don't understand why you need
> > > to add a separate dw-hdmi-qp.c since you only need simple variants of the 
> > > I2C
> > > bus, infoframe and bridge setup.
> > > 
> > > Can you elaborate further ? isn't this Quad-Pixel (QP) TX controller 
> > > version
> > > detectable at runtime ?
> > > 
> > > I would prefer to keep a single dw-hdmi driver if possible.
> >
> > The QP HDMI controller is a completely different variant with totally 
> > different
> > registers layout, see PATCH 13/14.
> > I think make it a separate driver will be easier for development and 
> > maintenance.
> 
> I'm with Andy here. Trying to navigate a driver for two IP blocks really
> sounds taxing especially when both are so different.

If it's a completely new controller, I agree that it needs a new driver,
but then why do we need to share code between the two?

Maxime


signature.asc
Description: PGP signature


Re: [PATCH v15 00/29] drm/connector: Create HDMI Connector infrastructure

2024-06-03 Thread Maxime Ripard
Hi Jani,

On Fri, May 31, 2024 at 09:43:16PM GMT, Jani Nikula wrote:
> On Mon, 27 May 2024, Maxime Ripard  wrote:
> > Let me know what you think,
> 
> Sorry to report that this series generates a bunch of kernel-doc
> warnings in include/drm/drm_connector.h. Documenting nested struct
> members doesn't work as smoothly as you'd expect:
>
> ../include/drm/drm_connector.h:1138: warning: Excess struct member 
> 'broadcast_rgb' description in 'drm_connector_state'
> ../include/drm/drm_connector.h:1138: warning: Excess struct member 
> 'infoframes' description in 'drm_connector_state'
> ../include/drm/drm_connector.h:1138: warning: Excess struct member 'avi' 
> description in 'drm_connector_state'
> ../include/drm/drm_connector.h:1138: warning: Excess struct member 'hdr_drm' 
> description in 'drm_connector_state'
> ../include/drm/drm_connector.h:1138: warning: Excess struct member 'spd' 
> description in 'drm_connector_state'
> ../include/drm/drm_connector.h:1138: warning: Excess struct member 'vendor' 
> description in 'drm_connector_state'
> ../include/drm/drm_connector.h:1138: warning: Excess struct member 
> 'is_limited_range' description in 'drm_connector_state'
> ../include/drm/drm_connector.h:1138: warning: Excess struct member 
> 'output_bpc' description in 'drm_connector_state'
> ../include/drm/drm_connector.h:1138: warning: Excess struct member 
> 'output_format' description in 'drm_connector_state'
> ../include/drm/drm_connector.h:1138: warning: Excess struct member 
> 'tmds_char_rate' description in 'drm_connector_state'
> ../include/drm/drm_connector.h:2112: warning: Excess struct member 'vendor' 
> description in 'drm_connector'
> ../include/drm/drm_connector.h:2112: warning: Excess struct member 'product' 
> description in 'drm_connector'
> ../include/drm/drm_connector.h:2112: warning: Excess struct member 
> 'supported_formats' description in 'drm_connector'
> ../include/drm/drm_connector.h:2112: warning: Excess struct member 
> 'infoframes' description in 'drm_connector'
> ../include/drm/drm_connector.h:2112: warning: Excess struct member 'lock' 
> description in 'drm_connector'
> ../include/drm/drm_connector.h:2112: warning: Excess struct member 'audio' 
> description in 'drm_connector'
> 
> Noticed this when I was rebasing [1]. Having that merged would find
> issues in headers at build time instead of 'make htmldocs'.
> 
> In the mean time, this is the quick reproducer:
> 
> $ scripts/kernel-doc -none include/drm/drm_connector.h

Thanks for the report and the reproducer. I have to admit I have no idea
how to fix it, do you have a suggestion?

Maxime


signature.asc
Description: PGP signature


Re: [PATCH v4 6/9] drm/msm/hdmi: make use of the drm_connector_hdmi framework

2024-06-03 Thread Maxime Ripard
On Fri, 31 May 2024 23:07:29 +0300, Dmitry Baryshkov wrote:
> Setup the HDMI connector on the MSM HDMI outputs. Make use of
> atomic_check hook and of the provided Infoframe infrastructure.
> 
> Signed-off-by: Dmitry Baryshkov 

Acked-by: Maxime Ripard 

Thanks!
Maxime


Re: [PATCH v4 3/9] drm/bridge-connector: implement glue code for HDMI connector

2024-06-03 Thread Maxime Ripard
Hi,

On Fri, May 31, 2024 at 11:07:26PM GMT, Dmitry Baryshkov wrote:
> +static int drm_bridge_connector_clear_infoframe(struct drm_connector 
> *connector,
> + enum hdmi_infoframe_type type)
> +{
> + struct drm_bridge_connector *bridge_connector =
> + to_drm_bridge_connector(connector);
> + struct drm_bridge *bridge;
> +
> + bridge = bridge_connector->bridge_hdmi;
> + if (!bridge)
> + return -EINVAL;
> +
> + if (bridge->funcs->hdmi_clear_infoframe)
> + return bridge->funcs->hdmi_clear_infoframe(bridge, type);
> + else
> + return 0;
> +}
> +
> +static int drm_bridge_connector_write_infoframe(struct drm_connector 
> *connector,
> + enum hdmi_infoframe_type type,
> + const u8 *buffer, size_t len)
> +{
> + struct drm_bridge_connector *bridge_connector =
> + to_drm_bridge_connector(connector);
> + struct drm_bridge *bridge;
> +
> + bridge = bridge_connector->bridge_hdmi;
> + if (!bridge)
> + return -EINVAL;
> +
> + return bridge->funcs->hdmi_write_infoframe(bridge, type, buffer, len);
> +}


Sorry, I didn't notice it before, but I think it would be good to try to
make clear_infoframe mandatory just like write_infoframe. It wasn't
possible for the main helpers because we didn't have enough info for
some drivers, but I think we should try to make it mandatory, and be
prepared to relax it if needs be.

With that fixed:
Acked-by: Maxime Ripard 

Maxime


signature.asc
Description: PGP signature


Re: [PATCH v4 1/9] drm/connector: hdmi: accept NULL for Audio Infoframe

2024-06-03 Thread Maxime Ripard
Hi,

Sorry for not answering your mail on the previous version sooner.

On Fri, May 31, 2024 at 11:07:24PM GMT, Dmitry Baryshkov wrote:
> Allow passing NULL as audio infoframe as a way to disable Audio
> Infoframe generation.
> 
> Signed-off-by: Dmitry Baryshkov 
> ---
>  drivers/gpu/drm/display/drm_hdmi_state_helper.c | 14 ++
>  1 file changed, 10 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c 
> b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> index ce96837eea65..5356723d21f5 100644
> --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> @@ -681,7 +681,7 @@ 
> EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_update_infoframes);
>  /**
>   * drm_atomic_helper_connector_hdmi_update_audio_infoframe - Update the 
> Audio Infoframe
>   * @connector: A pointer to the HDMI connector
> - * @frame: A pointer to the audio infoframe to write
> + * @frame: A pointer to the audio infoframe to write or NULL to disable 
> sending the frame

I'm still two-minded about this. I think I would like a separate helper
better, to also make things consistent with the HDMI helpers.

Most importantly, it looks like you're not using it at all in your series?

>   * This function is meant for HDMI connector drivers to update their
>   * audio infoframe. It will typically be used in one of the ALSA hooks
> @@ -704,10 +704,16 @@ 
> drm_atomic_helper_connector_hdmi_update_audio_infoframe(struct drm_connector 
> *co
>  
>   mutex_lock(>hdmi.infoframes.lock);
>  
> - memcpy(>data, frame, sizeof(infoframe->data));
> - infoframe->set = true;
> + if (frame) {
> + memcpy(>data, frame, sizeof(infoframe->data));
> + infoframe->set = true;
> +
> + ret = write_infoframe(connector, infoframe);
> + } else {
> + infoframe->set = false;
>  
> - ret = write_infoframe(connector, infoframe);
> + ret = clear_infoframe(connector, infoframe);
> + }

We should probably clear infoframe->data here too

Maxime


signature.asc
Description: PGP signature


Re: [PATCH v4 7/9] drm/msm/hdmi: get rid of hdmi_mode

2024-06-03 Thread Maxime Ripard
On Fri, 31 May 2024 23:07:30 +0300, Dmitry Baryshkov wrote:
> Use connector->display_info.is_hdmi instead of manually using
> drm_detect_hdmi_monitor().
> 
> Signed-off-by: Dmitry Baryshkov 

Acked-by: Maxime Ripard 

Thanks!
Maxime


Re: [PATCH v4 5/9] drm/msm/hdmi: turn mode_set into atomic_enable

2024-06-03 Thread Maxime Ripard
On Fri, 31 May 2024 23:07:28 +0300, Dmitry Baryshkov wrote:
> The mode_set callback is deprecated, it doesn't get the
> drm_bridge_state, just mode-related argumetns. Turn it into the
> atomic_enable callback as suggested by the documentation.
> 
> Signed-off-by: Dmitry Baryshkov 
> 
> [ ... ]

Acked-by: Maxime Ripard 

Thanks!
Maxime


Re: [PATCH v1] drm/bridge: simple-bridge: Add support for TI TDP158

2024-05-30 Thread Maxime Ripard
On Tue, May 28, 2024 at 01:39:52PM GMT, Arnaud Vrac wrote:
> On 28/05/2024 11:17, Maxime Ripard wrote:
> > On Tue, May 28, 2024 at 10:05:50AM GMT, Arnaud Vrac wrote:
> > > On 28/05/2024 09:43, Maxime Ripard wrote:
> > > > Hi,
> > > > 
> > > > On Mon, May 27, 2024 at 06:03:56PM GMT, Marc Gonzalez wrote:
> > > > > From: Arnaud Vrac 
> > > > > 
> > > > > The TI TDP158 is an AC-Coupled HDMI signal to TMDS Redriver supporting
> > > > > DVI 1.0 and HDMI 1.4b and 2.0b output signals.
> > > > > 
> > > > > Since it's an I2C-programmable bridge, it could have a proper driver,
> > > > > but the default settings work fine, thus simple bridge is sufficient.
> > > > 
> > > > No it doesn't. That bridge supports HDMI 2.0 which means you'll need to
> > > > change the TMDS clock ratio when programming a TMDS character rate
> > > > higher than 340MHz. And you'll need hotplug support to deal with it
> > > > properly too.
> > > > 
> > > > So sorry, you need a real driver there.
> > > 
> > > Hello, this is an HDMI redriver, which simply cleans up the HDMI
> > > signal, so no programming is needed to support HDMI 2.0.
> > 
> > I mean, if I'm to trust the datasheet, it is more complicated than that.
> > It snoops the DDC bus so it can update the TMDS clock ratio bit if it's
> > sent on its input side, but that wouldn't happen with DP for example.
> > 
> 
> That's a use case we can't test and will never use as a device
> integrator, unfortunately.
>
> To support our simple HDMI redriver use case, would it be ok to write
> a driver just handling power up with documented bindings with the chip
> default settings ? Someone with an actual need for more specific
> setups could then implement the additional code needed to support
> that. The bindings could be extended without breaking compatibility.

Sure, that's what I meant. We need to make sure the binding is
extensible enough / take all the possibilities into account, but the
driver can definitely be minimal.

Maxime


signature.asc
Description: PGP signature


[PULL] drm-misc-next

2024-05-30 Thread Maxime Ripard
gson/7a2000: convert to struct drm_edid
  drm/imx/tve: convert to struct drm_edid
  drm/imx/ldb: convert to struct drm_edid

Jiapeng Chong (1):
  drm/vmwgfx: Remove duplicate vmwgfx_vkms.h header

Jocelyn Falempe (4):
  drm/fb_dma: Add checks in drm_fb_dma_get_scanout_buffer()
  lib/fonts: Allow to select fonts for drm_panic
  Revert "drm/mgag200: Add a workaround for low-latency"
  drm/mgag200: Add an option to disable Write-Combine

Krzysztof Kozlowski (4):
  drm/tiny: ili9225: drop driver owner assignment
  drm/tiny: mi0283qt: drop driver owner assignment
  drm/tiny: panel-mipi-dbi: drop driver owner assignment
  drm/tiny: st7586: drop driver owner assignment

Kuro Chung (1):
  drm/bridge: it6505: fix hibernate to resume no display issue

Luca Ceresoli (1):
  Revert "drm/bridge: ti-sn65dsi83: Fix enable error path"

Marek Vasut (1):
  drm/bridge: tc358767: Enable FRMSYNC timing generator

MarileneGarcia (1):
  drm/dp: Fix documentation warning

Maxime Ripard (32):
  Merge drm/drm-next into drm-misc-next
  drm/connector: Introduce an HDMI connector initialization function
  drm/tests: connector: Add tests for drmm_connector_hdmi_init
  drm/connector: hdmi: Create an HDMI sub-state
  drm/connector: hdmi: Add output BPC to the connector state
  drm/mode_object: Export drm_mode_obj_find_prop_id for tests
  drm/tests: Add output bpc tests
  drm/connector: hdmi: Add support for output format
  drm/tests: Add output formats tests
  drm/display: hdmi: Add HDMI compute clock helper
  drm/tests: Add HDMI TDMS character rate tests
  drm/connector: hdmi: Calculate TMDS character rate
  drm/tests: Add TDMS character rate connector state tests
  drm/connector: hdmi: Add custom hook to filter TMDS character rate
  drm/tests: Add HDMI connector rate filter hook tests
  drm/connector: hdmi: Compute bpc and format automatically
  drm/tests: Add HDMI connector bpc and format tests
  drm/doc: Remove unused Broadcast RGB Property
  drm/connector: hdmi: Add Broadcast RGB property
  drm/tests: Add tests for Broadcast RGB property
  drm/connector: hdmi: Add RGB Quantization Range to the connector state
  drm/tests: Add RGB Quantization tests
  drm/connector: hdmi: Add Infoframes generation
  drm/tests: Add infoframes test
  drm/connector: hdmi: Create Infoframe DebugFS entries
  drm/vc4: hdmi: Switch to HDMI connector
  drm/vc4: tests: Remove vc4_dummy_plane structure
  drm/vc4: tests: Convert to plane creation helper
  drm/rockchip: inno_hdmi: Switch to HDMI connector
  drm/sun4i: hdmi: Switch to HDMI connector
  drm/sun4i: Fix compilation error
  drm/display: Fix HDMI state helper dependency

Maíra Canal (6):
  drm/v3d: Add Performance Counters descriptions for V3D 4.2 and 7.1
  drm/v3d: Different V3D versions can have different number of perfcnt
  drm/v3d: Create a new V3D parameter for the maximum number of perfcnt
  drm/v3d: Create new IOCTL to expose performance counters information
  drm/v3d: Use V3D_MAX_COUNTERS instead of V3D_PERFCNT_NUM
  drm/v3d: Deprecate the use of the Performance Counters enum

Pin-yen Lin (2):
  drm/panel-edp: Add support for several panels
  drm/panel-edp: Add more panels with conservative timings

Sean Anderson (5):
  drm: xlnx: Store base pointers in zynqmp_disp directly
  drm: xlnx: Fix kerneldoc
  drm: zynqmp_dp: Downgrade log level for aux retries message
  drm: zynqmp_dp: Adjust training values per-lane
  drm: zynqmp_dpsub: Always register bridge

Sui Jingfeng (15):
  drm/debugfs: Drop conditionals around of_node pointers
  drm/panel: ili9341: Remove a superfluous else after return
  drm/drm-bridge: Drop conditionals around of_node pointers
  drm/bridge: simple-bridge: Remove a redundant check on existence of 
bridge->encoder
  drm/bridge: tfp410: Remove a redundant check on existence of 
bridge->encoder
  drm/bridge: nxp-ptn3460: Remove a redundant check on existence of 
bridge->encoder
  drm/bridge: panel: Remove a redundant check on existence of 
bridge->encoder
  drm/bridge: it6505: Remove a redundant check on existence of 
bridge->encoder
  drm/bridge: adv7511: Remove a redundant check on existence of 
bridge->encoder
  drm/bridge: cdns-mhdp8546: Remove a redundant check on existence of 
bridge->encoder
  drm/bridge: megachips-stdp-ge-b850v3-fw: Remove a redundant check on 
existence of bridge->encoder
  drm/bridge: synopsys: dw-mipi-dsi: Remove a redundant check on existence 
of bridge->encoder
  drm/bridge: lt9611uxc: Remove a redundant check on existence of 
bridge->encoder
  drm/bridge: imx: Remove redundant checks on existence of bridge->encoder
  drm/bridge: analogix: Remove redundant checks on existence of 
bridge->enc

Re: [PATCH v4 2/2] drm/bridge: Add pixel clock check in atomic_check

2024-05-30 Thread Maxime Ripard
Hi,

On Thu, May 30, 2024 at 02:59:30PM GMT, Jayesh Choudhary wrote:
> Check the pixel clock for the mode in atomic_check and ensure that
> it is within the range supported by the bridge.
> 
> Signed-off-by: Jayesh Choudhary 
> ---
>  drivers/gpu/drm/bridge/sii902x.c | 6 ++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/drivers/gpu/drm/bridge/sii902x.c 
> b/drivers/gpu/drm/bridge/sii902x.c
> index 6a6055a4ccf9..1bf2f14a772d 100644
> --- a/drivers/gpu/drm/bridge/sii902x.c
> +++ b/drivers/gpu/drm/bridge/sii902x.c
> @@ -494,6 +494,12 @@ static int sii902x_bridge_atomic_check(struct drm_bridge 
> *bridge,
>  struct drm_crtc_state *crtc_state,
>  struct drm_connector_state *conn_state)
>  {
> + if (crtc_state->mode.clock < SII902X_MIN_PIXEL_CLOCK_KHZ)
> + return MODE_CLOCK_LOW;
> +
> + if (crtc_state->mode.clock > SII902X_MAX_PIXEL_CLOCK_KHZ)
> + return MODE_CLOCK_HIGH;
> +

atomic_check doesn't return drm_mode_status but regular error codes (0
on success, negative error code on failure)

Maxime


signature.asc
Description: PGP signature


Re: [PATCH v2] drm: bridge: cdns-mhdp8546: Move mode_valid hook to drm_bridge_funcs

2024-05-30 Thread Maxime Ripard
On Thu, 30 May 2024 14:47:57 +0530, Jayesh Choudhary wrote:
> With the support for the 'DRM_BRIDGE_ATTACH_NO_CONNECTOR' case,
> the connector_helper funcs are not initialized if the encoder has this
> flag in its bridge_attach call. Till now we had mode_valid hook only in
> the drm_connector_helper_funcs. Move this hook to drm_bridge_funcs to
> validate the modes.
> 
> [ ... ]

Acked-by: Maxime Ripard 

Thanks!
Maxime


Re: [PATCH v3 5/7] drm/msm/hdmi: make use of the drm_connector_hdmi framework

2024-05-30 Thread Maxime Ripard
Hi,

On Thu, May 30, 2024 at 02:12:28AM GMT, Dmitry Baryshkov wrote:
> Setup the HDMI connector on the MSM HDMI outputs. Make use of
> atomic_check hook and of the provided Infoframe infrastructure.
> 
> Signed-off-by: Dmitry Baryshkov 

As a general comment: I really like it, it looks super tidy. Thanks!

There's a couple of minor issues below

> -int msm_hdmi_audio_update(struct hdmi *hdmi)
> +static int msm_hdmi_audio_update(struct hdmi *hdmi)
>  {
>   struct hdmi_audio *audio = >audio;
> - struct hdmi_audio_infoframe *info = >infoframe;
>   const struct hdmi_msm_audio_arcs *arcs = NULL;
>   bool enabled = audio->enabled;
>   uint32_t acr_pkt_ctrl, vbi_pkt_ctrl, aud_pkt_ctrl;
> - uint32_t infofrm_ctrl, audio_config;
> + uint32_t audio_config;
> +
> + if (!hdmi->hdmi_mode)
> + return -EINVAL;
> +
> + DBG("audio: enabled=%d, channels=%d, rate=%d",
> + audio->enabled, audio->channels, audio->rate);
>  
> - DBG("audio: enabled=%d, channels=%d, channel_allocation=0x%x, "
> - "level_shift_value=%d, downmix_inhibit=%d, rate=%d",
> - audio->enabled, info->channels,  info->channel_allocation,
> - info->level_shift_value, info->downmix_inhibit, audio->rate);
>   DBG("video: power_on=%d, pixclock=%lu", hdmi->power_on, hdmi->pixclock);

pixclock should come from the connector state too. It's still calculated
by the driver in msm_hdmi_bridge_mode_set

> @@ -341,8 +425,11 @@ int msm_hdmi_bridge_init(struct hdmi *hdmi)
>   bridge->funcs = _hdmi_bridge_funcs;
>   bridge->ddc = hdmi->i2c;
>   bridge->type = DRM_MODE_CONNECTOR_HDMIA;
> + bridge->vendor = "Qualcomm";
> + bridge->product = "Snapdragon";
>   bridge->ops = DRM_BRIDGE_OP_HPD |
>   DRM_BRIDGE_OP_DETECT |
> + DRM_BRIDGE_OP_HDMI |
>   DRM_BRIDGE_OP_EDID;
>  
>   ret = devm_drm_bridge_add(hdmi->dev->dev, bridge);

It looks like you're not setting either the supported formats or bpc?

Maxime


signature.asc
Description: PGP signature


Re: [PATCH v3 4/7] drm/msm/hdmi: switch to atomic bridge callbacks

2024-05-30 Thread Maxime Ripard
On Thu, 30 May 2024 02:12:27 +0300, Dmitry Baryshkov wrote:
> Change MSM HDMI bridge to use atomic_* callbacks in preparation to
> enablign the HDMI connector support.
> 
> Signed-off-by: Dmitry Baryshkov 

Acked-by: Maxime Ripard 

Thanks!
Maxime


Re: [PATCH v3 3/7] drm/bridge-connector: implement glue code for HDMI connector

2024-05-30 Thread Maxime Ripard
Hi,

On Thu, May 30, 2024 at 02:12:26AM GMT, Dmitry Baryshkov wrote:
> In order to let bridge chains implement HDMI connector infrastructure,
> add necessary glue code to the drm_bridge_connector. In case there is a
> bridge that sets DRM_BRIDGE_OP_HDMI, drm_bridge_connector will register
> itself as a HDMI connector and provide proxy drm_connector_hdmi_funcs
> implementation.
> 
> Note, to simplify implementation, there can be only one bridge in a
> chain that sets DRM_BRIDGE_OP_HDMI. Setting more than one is considered
> an error. This limitation can be lifted later, if the need arises.
> 
> Signed-off-by: Dmitry Baryshkov 
> ---
>  drivers/gpu/drm/drm_bridge_connector.c | 101 
> -
>  drivers/gpu/drm/drm_debugfs.c  |   2 +
>  include/drm/drm_bridge.h   |  82 ++
>  3 files changed, 182 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_bridge_connector.c 
> b/drivers/gpu/drm/drm_bridge_connector.c
> index e093fc8928dc..8dca3eda5381 100644
> --- a/drivers/gpu/drm/drm_bridge_connector.c
> +++ b/drivers/gpu/drm/drm_bridge_connector.c
> @@ -18,6 +18,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  /**
>   * DOC: overview
> @@ -87,6 +88,13 @@ struct drm_bridge_connector {
>* connector modes detection, if any (see _BRIDGE_OP_MODES).
>*/
>   struct drm_bridge *bridge_modes;
> + /**
> +  * @bridge_hdmi:
> +  *
> +  * The bridge in the chain that implements necessary support for the
> +  * HDMI connector infrastructure, if any (see _BRIDGE_OP_HDMI).
> +  */
> + struct drm_bridge *bridge_hdmi;
>  };
>  
>  #define to_drm_bridge_connector(x) \
> @@ -287,6 +295,61 @@ static const struct drm_connector_helper_funcs 
> drm_bridge_connector_helper_funcs
>   .disable_hpd = drm_bridge_connector_disable_hpd,
>  };
>  
> +static enum drm_mode_status
> +drm_bridge_connector_tmds_char_rate_valid(const struct drm_connector 
> *connector,
> +   const struct drm_display_mode *mode,
> +   unsigned long long tmds_rate)
> +{
> + struct drm_bridge_connector *bridge_connector =
> + to_drm_bridge_connector(connector);
> + struct drm_bridge *bridge;
> +
> + bridge = bridge_connector->bridge_hdmi;
> + if (bridge)
> + return bridge->funcs->tmds_char_rate_valid ?
> + bridge->funcs->tmds_char_rate_valid(bridge, mode, 
> tmds_rate) :
> + MODE_OK;
> +
> + return MODE_ERROR;
> +}

It's kind of a nitpick, but I think the following syntax is clearer:

if (bridge)
if (bridge->funcs->tmds_char_rate_valid)
return bridge->funcs->tmds_char_rate_valid(bridge, mode, 
tmds_rate);
else
return MODE_OK;

return MODE_ERROR;

> +static int drm_bridge_connector_clear_infoframe(struct drm_connector 
> *connector,
> + enum hdmi_infoframe_type type)
> +{
> + struct drm_bridge_connector *bridge_connector =
> + to_drm_bridge_connector(connector);
> + struct drm_bridge *bridge;
> +
> + bridge = bridge_connector->bridge_hdmi;
> + if (bridge)
> + return bridge->funcs->clear_infoframe ?
> + bridge->funcs->clear_infoframe(bridge, type) :
> + 0;
> +
> + return -EINVAL;
> +}
> +
> +static int drm_bridge_connector_write_infoframe(struct drm_connector 
> *connector,
> + enum hdmi_infoframe_type type,
> + const u8 *buffer, size_t len)
> +{
> + struct drm_bridge_connector *bridge_connector =
> + to_drm_bridge_connector(connector);
> + struct drm_bridge *bridge;
> +
> + bridge = bridge_connector->bridge_hdmi;
> + if (bridge)
> + return bridge->funcs->write_infoframe(bridge, type, buffer, 
> len);
> +
> + return -EINVAL;
> +}
> +
> +static const struct drm_connector_hdmi_funcs drm_bridge_connector_hdmi_funcs 
> = {
> + .tmds_char_rate_valid = drm_bridge_connector_tmds_char_rate_valid,
> + .clear_infoframe = drm_bridge_connector_clear_infoframe,
> + .write_infoframe = drm_bridge_connector_write_infoframe,
> +};
> +
>  /* 
> -
>   * Bridge Connector Initialisation
>   */
> @@ -312,6 +375,10 @@ struct drm_connector *drm_bridge_connector_init(struct 
> drm_device *drm,
>   struct drm_connector *connector;
>   struct i2c_adapter *ddc = NULL;
>   struct drm_bridge *bridge, *panel_bridge = NULL;
> + const char *vendor = "Unknown";
> + const char *product = "Unknown";
> + unsigned int supported_formats = BIT(HDMI_COLORSPACE_RGB);
> + unsigned int max_bpc = 8;
>   int connector_type;
>   int ret;
>  
> @@ -348,6 +415,25 @@ struct drm_connector 

Re: [PATCH v3 2/7] drm/bridge-connector: switch to using drmm allocations

2024-05-30 Thread Maxime Ripard
On Thu, 30 May 2024 02:12:25 +0300, Dmitry Baryshkov wrote:
> Turn drm_bridge_connector to using drmm_kzalloc() and
> drmm_connector_init() and drop the custom destroy function. The
> drm_connector_unregister() and fwnode_handle_put() are already handled
> by the drm_connector_cleanup() and so are safe to be dropped.
> 
> 
> [ ... ]

Acked-by: Maxime Ripard 

Thanks!
Maxime


Re: [PATCH v3 1/7] drm/connector: hdmi: accept NULL for Audio Infoframe

2024-05-30 Thread Maxime Ripard
Hi,

On Thu, May 30, 2024 at 02:12:24AM GMT, Dmitry Baryshkov wrote:
> Allow passing NULL as audio infoframe as a way to disable Audio
> Infoframe generation.
> 
> Signed-off-by: Dmitry Baryshkov 
> ---
>  drivers/gpu/drm/display/drm_hdmi_state_helper.c | 14 ++
>  1 file changed, 10 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c 
> b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> index ce96837eea65..5356723d21f5 100644
> --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> @@ -681,7 +681,7 @@ 
> EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_update_infoframes);
>  /**
>   * drm_atomic_helper_connector_hdmi_update_audio_infoframe - Update the 
> Audio Infoframe
>   * @connector: A pointer to the HDMI connector
> - * @frame: A pointer to the audio infoframe to write
> + * @frame: A pointer to the audio infoframe to write or NULL to disable 
> sending the frame
>   *
>   * This function is meant for HDMI connector drivers to update their
>   * audio infoframe. It will typically be used in one of the ALSA hooks
> @@ -704,10 +704,16 @@ 
> drm_atomic_helper_connector_hdmi_update_audio_infoframe(struct drm_connector 
> *co
>  
>   mutex_lock(>hdmi.infoframes.lock);
>  
> - memcpy(>data, frame, sizeof(infoframe->data));
> - infoframe->set = true;
> + if (frame) {
> + memcpy(>data, frame, sizeof(infoframe->data));
> + infoframe->set = true;
> +
> + ret = write_infoframe(connector, infoframe);
> + } else {
> + infoframe->set = false;
>  
> - ret = write_infoframe(connector, infoframe);
> + ret = clear_infoframe(connector, infoframe);
> + }

I'm not entirely sure your commit matches your commit log? It looks like
you follow the same pattern than the other infoframes and call
write_infoframe if there's one, or clear_infoframe if there isn't.

So we're never passing NULL to disable? clear_infoframe is called.

Maxime


signature.asc
Description: PGP signature


Re: [PATCH] drm/tests: Add a missing Kconfig select

2024-05-29 Thread Maxime Ripard
Hi,

Thanks for sending that patch

On Wed, May 29, 2024 at 11:19:55AM GMT, Thomas Hellström wrote:
> Fix the following warning:
> 
> WARNING: unmet direct dependencies detected for DRM_DISPLAY_HDMI_STATE_HELPER
>   Depends on [n]: HAS_IOMEM [=y] && DRM [=y] && DRM_DISPLAY_HELPER [=y] && 
> DRM_DISPLAY_HDMI_HELPER [=n]
>   Selected by [y]:
>   - DRM_KUNIT_TEST [=y] && HAS_IOMEM [=y] && DRM [=y] && KUNIT [=y] && MMU 
> [=y]
> 
> Signed-off-by: Thomas Hellström 
> Fixes: 54cb39e2293b ("drm/connector: hdmi: Create an HDMI sub-state")
> Cc: Maxime Ripard 
> Cc: dri-devel@lists.freedesktop.org

I already sent a fix for that one, and just merged it:
https://lore.kernel.org/r/20240529080013.2325748-1-mrip...@kernel.org

Let me know if it doesn't fix it for you

Maxime


signature.asc
Description: PGP signature


Re: [PATCH] drm/display: Fix HDMI state helper dependency

2024-05-29 Thread Maxime Ripard
On Wed, 29 May 2024 10:00:13 +0200, Maxime Ripard wrote:
> During the life of the series that introduced the
> DRM_DISPLAY_HDMI_STATE_HELPER option, we reworked the Kconfig option
> dependency setup to rely on depends on with commit f6d2dc03fa85 ("drm:
> Switch DRM_DISPLAY_HDMI_HELPER to depends on") which got reverted later
> on because it was creating too many issues by commit d7c128cb775e
> ("Revert "drm: Switch DRM_DISPLAY_HDMI_HELPER to depends on"").
> 
> [...]

Applied to misc/kernel.git (drm-misc-next).

Thanks!
Maxime



Re: [PATCH] drm/sun4i: Fix compilation error

2024-05-29 Thread Maxime Ripard
On Wed, May 29, 2024 at 11:33:43AM GMT, Dmitry Baryshkov wrote:
> On Wed, May 29, 2024 at 10:14:55AM +0200, Maxime Ripard wrote:
> > On Tue, 28 May 2024 17:10:56 +0200, Maxime Ripard wrote:
> > > Commit ea64761a54a2 ("drm/sun4i: hdmi: Switch to HDMI connector")
> > > introduced a dependency that got renamed in a previous version, but
> > > wasn't properly updated in that driver. Fix the name of the function.
> > > 
> > > 
> > 
> > Applied to misc/kernel.git (drm-misc-next).
> 
> Just to note, I don't see this commit in drm-misc-next.

Thanks for the notice, I forgot to push it indeed.

It's now fixed

Maxime


signature.asc
Description: PGP signature


Re: linux-next: build failure after merge of the drm-misc tree

2024-05-29 Thread Maxime Ripard
Hi,

On Wed, May 29, 2024 at 12:35:31PM GMT, Stephen Rothwell wrote:
> Hi all,
> 
> After merging the drm-misc tree, today's linux-next build (arm
> multi_v7_defconfig) failed like this:
> 
> drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c: In function 
> 'sun4i_hdmi_connector_mode_valid':
> drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c:213:17: error: implicit declaration of 
> function 'drm_connector_hdmi_compute_mode_clock'; did you mean 
> 'drm_hdmi_compute_mode_clock'? [-Werror=implicit-function-declaration]
>   213 | drm_connector_hdmi_compute_mode_clock(mode, 8,
>   | ^
>   | drm_hdmi_compute_mode_clock
> cc1: some warnings being treated as errors
> 
> Caused by commit
> 
>   ea64761a54a2 ("drm/sun4i: hdmi: Switch to HDMI connector")
> 
> I have used the drm-misc tree from next-20240528 for today.

Thanks for the report. A fix is now merged into drm-misc-next
https://lore.kernel.org/dri-devel/20240528151056.2104153-1-mrip...@kernel.org/

Maxime


signature.asc
Description: PGP signature


Re: [PATCH] drm/sun4i: Fix compilation error

2024-05-29 Thread Maxime Ripard
On Tue, 28 May 2024 17:10:56 +0200, Maxime Ripard wrote:
> Commit ea64761a54a2 ("drm/sun4i: hdmi: Switch to HDMI connector")
> introduced a dependency that got renamed in a previous version, but
> wasn't properly updated in that driver. Fix the name of the function.
> 
> 

Applied to misc/kernel.git (drm-misc-next).

Thanks!
Maxime



[PATCH] drm/display: Fix HDMI state helper dependency

2024-05-29 Thread Maxime Ripard
During the life of the series that introduced the
DRM_DISPLAY_HDMI_STATE_HELPER option, we reworked the Kconfig option
dependency setup to rely on depends on with commit f6d2dc03fa85 ("drm:
Switch DRM_DISPLAY_HDMI_HELPER to depends on") which got reverted later
on because it was creating too many issues by commit d7c128cb775e
("Revert "drm: Switch DRM_DISPLAY_HDMI_HELPER to depends on"").

However, since the series was out of tree at that time,
DRM_DISPLAY_HDMI_STATE_HELPER wasn't properly updated to take the revert
into account and is now creating build issues.

Let's switch the depends on to a select to fix this.

Reported-by: kernel test robot 
Closes: 
https://lore.kernel.org/oe-kbuild-all/202405290332.sqtt0ix0-...@intel.com/
Closes: 
https://lore.kernel.org/oe-kbuild-all/202405290438.toyhxmin-...@intel.com/
Closes: 
https://lore.kernel.org/oe-kbuild-all/202405290803.c3178dyt-...@intel.com/
Closes: 
https://lore.kernel.org/oe-kbuild-all/202405291109.pqdqc46g-...@intel.com/
Closes: 
https://lore.kernel.org/oe-kbuild-all/202405291221.a0nstxhe-...@intel.com/
Fixes: 54cb39e2293b ("drm/connector: hdmi: Create an HDMI sub-state")
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/display/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/display/Kconfig b/drivers/gpu/drm/display/Kconfig
index 14114b597ef4..479e62690d75 100644
--- a/drivers/gpu/drm/display/Kconfig
+++ b/drivers/gpu/drm/display/Kconfig
@@ -72,8 +72,8 @@ config DRM_DISPLAY_HDMI_HELPER
  DRM display helpers for HDMI.
 
 config DRM_DISPLAY_HDMI_STATE_HELPER
bool
depends on DRM_DISPLAY_HELPER
-   depends on DRM_DISPLAY_HDMI_HELPER
+   select DRM_DISPLAY_HDMI_HELPER
help
  DRM KMS state helpers for HDMI.
-- 
2.45.0



[PATCH] drm/sun4i: Fix compilation error

2024-05-28 Thread Maxime Ripard
Commit ea64761a54a2 ("drm/sun4i: hdmi: Switch to HDMI connector")
introduced a dependency that got renamed in a previous version, but
wasn't properly updated in that driver. Fix the name of the function.

Reported-by: kernel test robot 
Closes: 
https://lore.kernel.org/oe-kbuild-all/202405282205.eu7nuoeq-...@intel.com/
Closes: 
https://lore.kernel.org/oe-kbuild-all/202405282248.u2lhpvck-...@intel.com/
Fixes: ea64761a54a2 ("drm/sun4i: hdmi: Switch to HDMI connector")
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c 
b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
index 0e652dd480c9..b3649449de30 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
@@ -207,13 +207,12 @@ static int sun4i_hdmi_connector_atomic_check(struct 
drm_connector *connector,
 
 static enum drm_mode_status
 sun4i_hdmi_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
 {
-   unsigned long long rate =
-   drm_connector_hdmi_compute_mode_clock(mode, 8,
- HDMI_COLORSPACE_RGB);
+   unsigned long long rate = drm_hdmi_compute_mode_clock(mode, 8,
+ 
HDMI_COLORSPACE_RGB);
 
return sun4i_hdmi_connector_clock_valid(connector, mode, rate);
 }
 
 static int sun4i_hdmi_get_modes(struct drm_connector *connector)
-- 
2.45.0



Re: [PATCH v1] drm/bridge: simple-bridge: Add support for TI TDP158

2024-05-28 Thread Maxime Ripard
On Tue, May 28, 2024 at 04:50:10PM GMT, Dmitry Baryshkov wrote:
> On Tue, May 28, 2024 at 11:17:56AM +0200, Maxime Ripard wrote:
> > On Tue, May 28, 2024 at 10:05:50AM GMT, Arnaud Vrac wrote:
> > > On 28/05/2024 09:43, Maxime Ripard wrote:
> > > > Hi,
> > > > 
> > > > On Mon, May 27, 2024 at 06:03:56PM GMT, Marc Gonzalez wrote:
> > > > > From: Arnaud Vrac 
> > > > > 
> > > > > The TI TDP158 is an AC-Coupled HDMI signal to TMDS Redriver supporting
> > > > > DVI 1.0 and HDMI 1.4b and 2.0b output signals.
> > > > > 
> > > > > Since it's an I2C-programmable bridge, it could have a proper driver,
> > > > > but the default settings work fine, thus simple bridge is sufficient.
> > > > 
> > > > No it doesn't. That bridge supports HDMI 2.0 which means you'll need to
> > > > change the TMDS clock ratio when programming a TMDS character rate
> > > > higher than 340MHz. And you'll need hotplug support to deal with it
> > > > properly too.
> > > > 
> > > > So sorry, you need a real driver there.
> > > 
> > > Hello, this is an HDMI redriver, which simply cleans up the HDMI
> > > signal, so no programming is needed to support HDMI 2.0.
> > 
> > I mean, if I'm to trust the datasheet, it is more complicated than that.
> > It snoops the DDC bus so it can update the TMDS clock ratio bit if it's
> > sent on its input side, but that wouldn't happen with DP for example.
> 
> If I understand correctly, this chip can work in two modes: dummy and
> I2C-programmed. In the former case it is fully transparent, including
> HPD passthrough, it doesn't require any additional programming, just
> Vcc, Vdd and pin straps, etc.  And the second mode is a 'brainy' one,
> when the chip is fully controlled over I2C.

Right, and like I said, the situation is more complicated than "it just
does passthrough" like simple-bridge does.

> From the Linux standpoint these two modes will use single compat string,
> but two distinct drivers: for the former mode is is enough to use
> simple-bridge (fixed to support two supplies), while the latter one
> needs a proper I2C driver.
> 
> Does that solve your concern?

We need to be careful here: if there's two drivers with the same
compatible and bus, both will be probed. So we need to take it into
account when designing the binding.

Maxime


signature.asc
Description: PGP signature


Re: [PATCH 6/7] drm/bridge: Introduce early_enable and late disable

2024-05-28 Thread Maxime Ripard
On Fri, May 24, 2024 at 04:38:13PM GMT, Aradhya Bhatia wrote:
> Hi Maxime,
> 
> On 21/05/24 18:45, Maxime Ripard wrote:
> > Hi,
> > 
> > On Thu, May 16, 2024 at 03:10:15PM GMT, Aradhya Bhatia wrote:
> >>>>  /**
> >>>>   * @pre_enable:
> >>>>   *
> >>>> @@ -285,6 +319,26 @@ struct drm_bridge_funcs {
> >>>>   */
> >>>>  void (*enable)(struct drm_bridge *bridge);
> >>>>  
> >>>> +/**
> >>>> + * @atomic_early_enable:
> >>>> + *
> >>>> + * This callback should enable the bridge. It is called right 
> >>>> before
> >>>> + * the preceding element in the display pipe is enabled. If the
> >>>> + * preceding element is a bridge this means it's called before 
> >>>> that
> >>>> + * bridge's @atomic_early_enable. If the preceding element is a
> >>>> + * _crtc it's called right before the crtc's
> >>>> + * _crtc_helper_funcs.atomic_enable hook.
> >>>> + *
> >>>> + * The display pipe (i.e. clocks and timing signals) feeding 
> >>>> this bridge
> >>>> + * will not yet be running when this callback is called. The 
> >>>> bridge can
> >>>> + * enable the display link feeding the next bridge in the chain 
> >>>> (if
> >>>> + * there is one) when this callback is called.
> >>>> + *
> >>>> + * The @early_enable callback is optional.
> >>>> + */
> >>>> +void (*atomic_early_enable)(struct drm_bridge *bridge,
> >>>> +struct drm_bridge_state 
> >>>> *old_bridge_state);
> >>>> +
> >>>>  /**
> >>>>   * @atomic_pre_enable:
> >>>>   *
> >>>> @@ -361,6 +415,21 @@ struct drm_bridge_funcs {
> >>>>  void (*atomic_post_disable)(struct drm_bridge *bridge,
> >>>>  struct drm_bridge_state 
> >>>> *old_bridge_state);
> >>>>  
> >>>> +/**
> >>>> + * @atomic_late_disable:
> >>>> + *
> >>>> + * This callback should disable the bridge. It is called right 
> >>>> after the
> >>>> + * preceding element in the display pipe is disabled. If the 
> >>>> preceding
> >>>> + * element is a bridge this means it's called after that 
> >>>> bridge's
> >>>> + * @atomic_late_disable. If the preceding element is a 
> >>>> _crtc it's
> >>>> + * called right after the crtc's 
> >>>> _crtc_helper_funcs.atomic_disable
> >>>> + * hook.
> >>>> + *
> >>>> + * The @atomic_late_disable callback is optional.
> >>>> + */
> >>>> +void (*atomic_late_disable)(struct drm_bridge *bridge,
> >>>> +struct drm_bridge_state 
> >>>> *old_bridge_state);
> >>>> +
> >>>
> >>> But more importantly, I don't quite get the use case you're trying to
> >>> solve here.
> >>>
> >>> If I got the rest of your series, the Cadence DSI bridge needs to be
> >>> powered up before its source is started. You can't use atomic_enable or
> >>> atomic_pre_enable because it would start the source before the DSI
> >>> bridge. Is that correct?
> >>>
> >>
> >> That's right. I cannot use bridge_atomic_pre_enable /
> >> bridge_atomic_enable here. But that's because my source is CRTC, which
> >> gets enabled via crtc_atomic_enable.
> >>
> >>
> >>> If it is, then how is it different from what
> >>> drm_atomic_bridge_chain_pre_enable is doing? The assumption there is
> >>> that it starts enabling bridges last to first, to it should be enabled
> >>> before anything starts.
> >>>
> >>> The whole bridge enabling order code starts to be a bit of a mess, so it
> >>> would be great if you could list all the order variations we have
> >>> currently, and why none work for cdns-dsi.
> >>>
> >

Re: [PATCH v1] drm/bridge: simple-bridge: Add support for TI TDP158

2024-05-28 Thread Maxime Ripard
On Tue, May 28, 2024 at 10:05:50AM GMT, Arnaud Vrac wrote:
> On 28/05/2024 09:43, Maxime Ripard wrote:
> > Hi,
> > 
> > On Mon, May 27, 2024 at 06:03:56PM GMT, Marc Gonzalez wrote:
> > > From: Arnaud Vrac 
> > > 
> > > The TI TDP158 is an AC-Coupled HDMI signal to TMDS Redriver supporting
> > > DVI 1.0 and HDMI 1.4b and 2.0b output signals.
> > > 
> > > Since it's an I2C-programmable bridge, it could have a proper driver,
> > > but the default settings work fine, thus simple bridge is sufficient.
> > 
> > No it doesn't. That bridge supports HDMI 2.0 which means you'll need to
> > change the TMDS clock ratio when programming a TMDS character rate
> > higher than 340MHz. And you'll need hotplug support to deal with it
> > properly too.
> > 
> > So sorry, you need a real driver there.
> 
> Hello, this is an HDMI redriver, which simply cleans up the HDMI
> signal, so no programming is needed to support HDMI 2.0.

I mean, if I'm to trust the datasheet, it is more complicated than that.
It snoops the DDC bus so it can update the TMDS clock ratio bit if it's
sent on its input side, but that wouldn't happen with DP for example.

Maxime


signature.asc
Description: PGP signature


Re: [PATCH v15 00/29] drm/connector: Create HDMI Connector infrastructure

2024-05-28 Thread Maxime Ripard
On Mon, 27 May 2024 15:57:49 +0200, Maxime Ripard wrote:
> Here's a series that creates some extra infrastructure specifically
> targeted at HDMI controllers.
> 
> The idea behind this series came from a recent discussion on IRC during
> which we discussed infoframes generation of i915 vs everything else.
> 
> Infoframes generation code still requires some decent boilerplate, with
> each driver doing some variation of it.
> 
> [...]

Applied to misc/kernel.git (drm-misc-next).

Thanks!
Maxime


Re: [PATCH v1] drm/bridge: simple-bridge: Add support for TI TDP158

2024-05-28 Thread Maxime Ripard
Hi,

On Mon, May 27, 2024 at 06:03:56PM GMT, Marc Gonzalez wrote:
> From: Arnaud Vrac 
> 
> The TI TDP158 is an AC-Coupled HDMI signal to TMDS Redriver supporting
> DVI 1.0 and HDMI 1.4b and 2.0b output signals.
> 
> Since it's an I2C-programmable bridge, it could have a proper driver,
> but the default settings work fine, thus simple bridge is sufficient.

No it doesn't. That bridge supports HDMI 2.0 which means you'll need to
change the TMDS clock ratio when programming a TMDS character rate
higher than 340MHz. And you'll need hotplug support to deal with it
properly too.

So sorry, you need a real driver there.

> Signed-off-by: Arnaud Vrac 
> Signed-off-by: Marc Gonzalez 
> ---
>  drivers/gpu/drm/bridge/simple-bridge.c | 5 +
>  1 file changed, 5 insertions(+)
> 
> diff --git a/drivers/gpu/drm/bridge/simple-bridge.c 
> b/drivers/gpu/drm/bridge/simple-bridge.c
> index 5813a2c4fc5ee..b138279864750 100644
> --- a/drivers/gpu/drm/bridge/simple-bridge.c
> +++ b/drivers/gpu/drm/bridge/simple-bridge.c
> @@ -292,6 +292,11 @@ static const struct of_device_id simple_bridge_match[] = 
> {
>   .timings = _ths8134_bridge_timings,
>   .connector_type = DRM_MODE_CONNECTOR_VGA,
>   },
> + }, {
> + .compatible = "ti,tdp158",
> + .data = &(const struct simple_bridge_info) {
> + .connector_type = DRM_MODE_CONNECTOR_HDMIA,
> + },

You'll need a DT binding for that too.

Maxime


signature.asc
Description: PGP signature


Re: [PATCH v6 0/7] Add mediate-drm secure flow for SVP

2024-05-27 Thread Maxime Ripard
Hi,

On Sun, May 26, 2024 at 07:29:21AM GMT, Jason-JH.Lin wrote:
> From: Jason-jh Lin 
> 
> Memory Definitions:
> secure memory - Memory allocated in the TEE (Trusted Execution
> Environment) which is inaccessible in the REE (Rich Execution
> Environment, i.e. linux kernel/userspace).
> secure handle - Integer value which acts as reference to 'secure
> memory'. Used in communication between TEE and REE to reference
> 'secure memory'.
> secure buffer - 'secure memory' that is used to store decrypted,
> compressed video or for other general purposes in the TEE.
> secure surface - 'secure memory' that is used to store graphic buffers.
> 
> Memory Usage in SVP:
> The overall flow of SVP starts with encrypted video coming in from an
> outside source into the REE. The REE will then allocate a 'secure
> buffer' and send the corresponding 'secure handle' along with the
> encrypted, compressed video data to the TEE. The TEE will then decrypt
> the video and store the result in the 'secure buffer'. The REE will
> then allocate a 'secure surface'. The REE will pass the 'secure
> handles' for both the 'secure buffer' and 'secure surface' into the
> TEE for video decoding. The video decoder HW will then decode the
> contents of the 'secure buffer' and place the result in the 'secure
> surface'. The REE will then attach the 'secure surface' to the overlay
> plane for rendering of the video.
> 
> Everything relating to ensuring security of the actual contents of the
> 'secure buffer' and 'secure surface' is out of scope for the REE and
> is the responsibility of the TEE.
> 
> DRM driver handles allocation of gem objects that are backed by a 'secure
> surface' and for displaying a 'secure surface' on the overlay plane.
> This introduces a new flag for object creation called
> DRM_MTK_GEM_CREATE_RESTRICTED which indicates it should be a 'secure
> surface'. All changes here are in MediaTek specific code.
> ---
> TODO:
> 1) Drop MTK_DRM_IOCTL_GEM_CREATE and use DMA_HEAP_IOCTL_ALLOC in userspace
> 2) DRM driver use secure mailbox channel to handle normal and secure flow
> 3) Implement setting mmsys routing table in the secure world series

I'm not sure what you mean here. Why are you trying to upstream
something that still needs to be removed from your patch series?

Also, I made some comments on the previous version that have been
entirely ignored and still apply on this version:
https://lore.kernel.org/dri-devel/20240415-guppy-of-perpetual-current-3a7974@houat/

Maxime


signature.asc
Description: PGP signature


[PATCH v15 23/29] drm/tests: Add infoframes test

2024-05-27 Thread Maxime Ripard
The previous patch added the generation of the infoframes matching an
HDMI connector state. Let's add a few tests to make sure it works as
expected.

Reviewed-by: Dmitry Baryshkov 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/tests/drm_connector_test.c | 219 +
 1 file changed, 219 insertions(+)

diff --git a/drivers/gpu/drm/tests/drm_connector_test.c 
b/drivers/gpu/drm/tests/drm_connector_test.c
index 2e631617c391..eda2e5d08cd9 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -219,10 +219,221 @@ static void drm_test_connector_hdmi_init_null_ddc(struct 
kunit *test)
   BIT(HDMI_COLORSPACE_RGB),
   8);
KUNIT_EXPECT_EQ(test, ret, 0);
 }
 
+/*
+ * Test that the registration of an HDMI connector with a NULL vendor
+ * fails.
+ */
+static void drm_test_connector_hdmi_init_null_vendor(struct kunit *test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   int ret;
+
+   ret = drmm_connector_hdmi_init(>drm, >connector,
+  NULL, "Product",
+  _funcs,
+  _hdmi_funcs,
+  DRM_MODE_CONNECTOR_HDMIA,
+  >ddc,
+  BIT(HDMI_COLORSPACE_RGB),
+  8);
+   KUNIT_EXPECT_LT(test, ret, 0);
+}
+
+/*
+ * Test that the registration of an HDMI connector with a NULL product
+ * fails.
+ */
+static void drm_test_connector_hdmi_init_null_product(struct kunit *test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   int ret;
+
+   ret = drmm_connector_hdmi_init(>drm, >connector,
+  "Vendor", NULL,
+  _funcs,
+  _hdmi_funcs,
+  DRM_MODE_CONNECTOR_HDMIA,
+  >ddc,
+  BIT(HDMI_COLORSPACE_RGB),
+  8);
+   KUNIT_EXPECT_LT(test, ret, 0);
+}
+
+/*
+ * Test that the registration of a connector with a valid, shorter than
+ * the max length, product name succeeds, and is stored padded with 0.
+ */
+static void drm_test_connector_hdmi_init_product_valid(struct kunit *test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   const unsigned char expected_product[DRM_CONNECTOR_HDMI_PRODUCT_LEN] = {
+   'P', 'r', 'o', 'd',
+   };
+   const char *product_name = "Prod";
+   int ret;
+
+   KUNIT_ASSERT_LT(test, strlen(product_name), 
DRM_CONNECTOR_HDMI_PRODUCT_LEN);
+
+   ret = drmm_connector_hdmi_init(>drm, >connector,
+  "Vendor", product_name,
+  _funcs,
+  _hdmi_funcs,
+  DRM_MODE_CONNECTOR_HDMIA,
+  >ddc,
+  BIT(HDMI_COLORSPACE_RGB),
+  8);
+   KUNIT_EXPECT_EQ(test, ret, 0);
+   KUNIT_EXPECT_MEMEQ(test,
+  priv->connector.hdmi.product,
+  expected_product,
+  sizeof(priv->connector.hdmi.product));
+}
+
+/*
+ * Test that the registration of a connector with a valid, at max
+ * length, product name succeeds, and is stored padded without any
+ * trailing \0.
+ */
+static void drm_test_connector_hdmi_init_product_length_exact(struct kunit 
*test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   const unsigned char expected_product[DRM_CONNECTOR_HDMI_PRODUCT_LEN] = {
+   'P', 'r', 'o', 'd', 'u', 'c', 't',
+   'P', 'r', 'o', 'd', 'u', 'c', 't',
+   'P', 'r',
+   };
+   const char *product_name = "ProductProductPr";
+   int ret;
+
+   KUNIT_ASSERT_EQ(test, strlen(product_name), 
DRM_CONNECTOR_HDMI_PRODUCT_LEN);
+
+   ret = drmm_connector_hdmi_init(>drm, >connector,
+  "Vendor", product_name,
+  _funcs,
+  _hdmi_funcs,
+  DRM_MODE_CONNECTOR_HDMIA,
+  >ddc,
+  BIT(HDMI_COLORSPACE_RGB),
+  8);
+   KUNIT_EXPECT_EQ(test, ret, 0);
+   KUNIT_EXPECT_MEMEQ(test,
+  priv->connector.hdmi.product,
+  expected_product,
+  sizeof(priv->connector.hdmi.produc

[PATCH v15 25/29] drm/vc4: hdmi: Switch to HDMI connector

2024-05-27 Thread Maxime Ripard
The new HDMI connector infrastructure allows us to remove a lot of
boilerplate, so let's switch to it.

Acked-by: Sui Jingfeng 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/vc4/Kconfig|   1 +
 drivers/gpu/drm/vc4/vc4_hdmi.c | 644 +
 drivers/gpu/drm/vc4/vc4_hdmi.h |  44 +--
 drivers/gpu/drm/vc4/vc4_hdmi_phy.c |   6 +-
 4 files changed, 92 insertions(+), 603 deletions(-)

diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig
index 91dcf8d174d6..269b5f26b2ea 100644
--- a/drivers/gpu/drm/vc4/Kconfig
+++ b/drivers/gpu/drm/vc4/Kconfig
@@ -8,10 +8,11 @@ config DRM_VC4
depends on DRM
depends on SND && SND_SOC
depends on COMMON_CLK
depends on PM
select DRM_DISPLAY_HDMI_HELPER
+   select DRM_DISPLAY_HDMI_STATE_HELPER
select DRM_DISPLAY_HELPER
select DRM_KMS_HELPER
select DRM_GEM_DMA_HELPER
select DRM_PANEL_BRIDGE
select SND_PCM
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index d30f8e8e8967..d57c4a5948c8 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -30,10 +30,11 @@
  * The driver does not yet support CEC control, though the HDMI
  * encoder block has CEC support.
  */
 
 #include 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
@@ -108,29 +109,10 @@
 #define HSM_MIN_CLOCK_FREQ 12000
 #define CEC_CLOCK_FREQ 4
 
 #define HDMI_14_MAX_TMDS_CLK   (340 * 1000 * 1000)
 
-static const char * const output_format_str[] = {
-   [VC4_HDMI_OUTPUT_RGB]   = "RGB",
-   [VC4_HDMI_OUTPUT_YUV420]= "YUV 4:2:0",
-   [VC4_HDMI_OUTPUT_YUV422]= "YUV 4:2:2",
-   [VC4_HDMI_OUTPUT_YUV444]= "YUV 4:4:4",
-};
-
-static const char *vc4_hdmi_output_fmt_str(enum vc4_hdmi_output_format fmt)
-{
-   if (fmt >= ARRAY_SIZE(output_format_str))
-   return "invalid";
-
-   return output_format_str[fmt];
-}
-
-static unsigned long long
-vc4_hdmi_encoder_compute_mode_clock(const struct drm_display_mode *mode,
-   unsigned int bpc, enum 
vc4_hdmi_output_format fmt);
-
 static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi *vc4_hdmi)
 {
struct drm_display_info *display = _hdmi->connector.display_info;
 
lockdep_assert_held(_hdmi->mutex);
@@ -145,32 +127,17 @@ static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi 
*vc4_hdmi)
return true;
 }
 
 static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode,
   unsigned int bpc,
-  enum vc4_hdmi_output_format fmt)
+  enum hdmi_colorspace fmt)
 {
-   unsigned long long clock = vc4_hdmi_encoder_compute_mode_clock(mode, 
bpc, fmt);
+   unsigned long long clock = drm_hdmi_compute_mode_clock(mode, bpc, fmt);
 
return clock > HDMI_14_MAX_TMDS_CLK;
 }
 
-static bool vc4_hdmi_is_full_range(struct vc4_hdmi *vc4_hdmi,
-  struct vc4_hdmi_connector_state *vc4_state)
-{
-   const struct drm_display_mode *mode = _hdmi->saved_adjusted_mode;
-   struct drm_display_info *display = _hdmi->connector.display_info;
-
-   if (vc4_state->broadcast_rgb == VC4_HDMI_BROADCAST_RGB_LIMITED)
-   return false;
-   else if (vc4_state->broadcast_rgb == VC4_HDMI_BROADCAST_RGB_FULL)
-   return true;
-
-   return !display->is_hdmi ||
-   drm_default_rgb_quant_range(mode) == 
HDMI_QUANTIZATION_RANGE_FULL;
-}
-
 static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
 {
struct drm_debugfs_entry *entry = m->private;
struct vc4_hdmi *vc4_hdmi = entry->file.data;
struct drm_device *drm = vc4_hdmi->connector.dev;
@@ -522,11 +489,11 @@ static int vc4_hdmi_connector_get_modes(struct 
drm_connector *connector)
if (!vc4->hvs->vc5_hdmi_enable_hdmi_20) {
struct drm_device *drm = connector->dev;
const struct drm_display_mode *mode;
 
list_for_each_entry(mode, >probed_modes, head) {
-   if (vc4_hdmi_mode_needs_scrambling(mode, 8, 
VC4_HDMI_OUTPUT_RGB)) {
+   if (vc4_hdmi_mode_needs_scrambling(mode, 8, 
HDMI_COLORSPACE_RGB)) {
drm_warn_once(drm, "The core clock cannot reach 
frequencies high enough to support 4k @ 60Hz.");
drm_warn_once(drm, "Please change your 
config.txt file to add hdmi_enable_4kp60.");
}
}
}
@@ -537,16 +504,12 @@ static int vc4_hdmi_connector_get_modes(struct 
drm_connector *connector)
 static int vc4_hdmi_connector_atomic_check(struct drm_connector *connecto

[PATCH v15 26/29] drm/vc4: tests: Remove vc4_dummy_plane structure

2024-05-27 Thread Maxime Ripard
The vc4_dummy_plane structure was introduced as a mean to add
mock-specific fields.

However, we never really used it and it's still strictly equivalent to
vc4_plane (which is in the same situation vs drm_plane), so we can
simply remove the vc4_dummy_plane structure and make the mock code
cleaner.

Reviewed-by: Maíra Canal 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/vc4/tests/vc4_mock.c   |  6 ++
 drivers/gpu/drm/vc4/tests/vc4_mock.h   |  9 ++---
 drivers/gpu/drm/vc4/tests/vc4_mock_plane.c | 14 +-
 3 files changed, 9 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.c 
b/drivers/gpu/drm/vc4/tests/vc4_mock.c
index becb3dbaa548..0731a7d85d7a 100644
--- a/drivers/gpu/drm/vc4/tests/vc4_mock.c
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock.c
@@ -107,20 +107,18 @@ static const struct vc4_mock_desc vc5_mock =
 );
 
 static int __build_one_pipe(struct kunit *test, struct drm_device *drm,
const struct vc4_mock_pipe_desc *pipe)
 {
-   struct vc4_dummy_plane *dummy_plane;
struct drm_plane *plane;
struct vc4_dummy_crtc *dummy_crtc;
struct drm_crtc *crtc;
unsigned int i;
 
-   dummy_plane = vc4_dummy_plane(test, drm, DRM_PLANE_TYPE_PRIMARY);
-   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_plane);
+   plane = vc4_dummy_plane(test, drm, DRM_PLANE_TYPE_PRIMARY);
+   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane);
 
-   plane = _plane->plane.base;
dummy_crtc = vc4_mock_pv(test, drm, plane, pipe->data);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_crtc);
 
crtc = _crtc->crtc.base;
for (i = 0; i < pipe->noutputs; i++) {
diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.h 
b/drivers/gpu/drm/vc4/tests/vc4_mock.h
index 2d0b339bd9f3..002b6218960c 100644
--- a/drivers/gpu/drm/vc4/tests/vc4_mock.h
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock.h
@@ -19,17 +19,12 @@ struct drm_crtc *vc4_find_crtc_for_encoder(struct kunit 
*test,
return crtc;
 
return NULL;
 }
 
-struct vc4_dummy_plane {
-   struct vc4_plane plane;
-};
-
-struct vc4_dummy_plane *vc4_dummy_plane(struct kunit *test,
-   struct drm_device *drm,
-   enum drm_plane_type type);
+struct drm_plane *vc4_dummy_plane(struct kunit *test, struct drm_device *drm,
+ enum drm_plane_type type);
 
 struct vc4_dummy_crtc {
struct vc4_crtc crtc;
 };
 
diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c 
b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c
index 62b18f5f41db..973f5f929097 100644
--- a/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c
@@ -20,28 +20,24 @@ static const struct drm_plane_funcs vc4_dummy_plane_funcs = 
{
 
 static const uint32_t vc4_dummy_plane_formats[] = {
DRM_FORMAT_XRGB,
 };
 
-struct vc4_dummy_plane *vc4_dummy_plane(struct kunit *test,
-   struct drm_device *drm,
-   enum drm_plane_type type)
+struct drm_plane *vc4_dummy_plane(struct kunit *test, struct drm_device *drm,
+ enum drm_plane_type type)
 {
-   struct vc4_dummy_plane *dummy_plane;
struct drm_plane *plane;
 
-   dummy_plane = drmm_universal_plane_alloc(drm,
-struct vc4_dummy_plane, 
plane.base,
+   plane = __drmm_universal_plane_alloc(drm, sizeof(struct drm_plane), 0,
 0,
 _dummy_plane_funcs,
 vc4_dummy_plane_formats,
 
ARRAY_SIZE(vc4_dummy_plane_formats),
 NULL,
 DRM_PLANE_TYPE_PRIMARY,
 NULL);
-   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_plane);
+   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane);
 
-   plane = _plane->plane.base;
drm_plane_helper_add(plane, _dummy_plane_helper_funcs);
 
-   return dummy_plane;
+   return plane;
 }

-- 
2.45.0



[PATCH v15 29/29] drm/sun4i: hdmi: Switch to HDMI connector

2024-05-27 Thread Maxime Ripard
The new HDMI connector infrastructure allows to remove some boilerplate,
especially to generate infoframes. Let's switch to it.

Reviewed-by: Jernej Skrabec 
Acked-by: Sui Jingfeng 
Reviewed-by: Andy Yan 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/sun4i/Kconfig  |  3 ++
 drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 84 ++
 2 files changed, 57 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
index 4741d9f6544c..4037e085430e 100644
--- a/drivers/gpu/drm/sun4i/Kconfig
+++ b/drivers/gpu/drm/sun4i/Kconfig
@@ -16,10 +16,13 @@ config DRM_SUN4I
 if DRM_SUN4I
 
 config DRM_SUN4I_HDMI
tristate "Allwinner A10/A10s/A20/A31 HDMI Controller Support"
depends on ARM || COMPILE_TEST
+   select DRM_DISPLAY_HDMI_HELPER
+   select DRM_DISPLAY_HDMI_STATE_HELPER
+   select DRM_DISPLAY_HELPER
default DRM_SUN4I
help
  Choose this option if you have an Allwinner A10/A10s/A20/A31
  SoC with an HDMI controller.
 
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c 
b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
index 245b34adca5a..0e652dd480c9 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
@@ -24,10 +24,13 @@
 #include 
 #include 
 #include 
 #include 
 
+#include 
+#include 
+
 #include "sun4i_backend.h"
 #include "sun4i_crtc.h"
 #include "sun4i_drv.h"
 #include "sun4i_hdmi.h"
 
@@ -35,34 +38,28 @@
container_of_const(e, struct sun4i_hdmi, encoder)
 
 #define drm_connector_to_sun4i_hdmi(c) \
container_of_const(c, struct sun4i_hdmi, connector)
 
-static int sun4i_hdmi_setup_avi_infoframes(struct sun4i_hdmi *hdmi,
-  struct drm_display_mode *mode)
+static int sun4i_hdmi_write_infoframe(struct drm_connector *connector,
+ enum hdmi_infoframe_type type,
+ const u8 *buffer, size_t len)
 {
-   struct hdmi_avi_infoframe frame;
-   u8 buffer[17];
-   int i, ret;
+   struct sun4i_hdmi *hdmi = drm_connector_to_sun4i_hdmi(connector);
+   int i;
 
-   ret = drm_hdmi_avi_infoframe_from_display_mode(,
-  >connector, mode);
-   if (ret < 0) {
-   DRM_ERROR("Failed to get infoframes from mode\n");
-   return ret;
+   if (type != HDMI_INFOFRAME_TYPE_AVI) {
+   drm_err(connector->dev,
+   "Unsupported infoframe type: %u\n", type);
+   return 0;
}
 
-   ret = hdmi_avi_infoframe_pack(, buffer, sizeof(buffer));
-   if (ret < 0) {
-   DRM_ERROR("Failed to pack infoframes\n");
-   return ret;
-   }
-
-   for (i = 0; i < sizeof(buffer); i++)
+   for (i = 0; i < len; i++)
writeb(buffer[i], hdmi->base + SUN4I_HDMI_AVI_INFOFRAME_REG(i));
 
return 0;
+
 }
 
 static void sun4i_hdmi_disable(struct drm_encoder *encoder,
   struct drm_atomic_state *state)
 {
@@ -81,18 +78,22 @@ static void sun4i_hdmi_disable(struct drm_encoder *encoder,
 static void sun4i_hdmi_enable(struct drm_encoder *encoder,
  struct drm_atomic_state *state)
 {
struct drm_display_mode *mode = >crtc->state->adjusted_mode;
struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder);
-   struct drm_display_info *display = >connector.display_info;
+   struct drm_connector *connector = >connector;
+   struct drm_display_info *display = >display_info;
+   struct drm_connector_state *conn_state =
+   drm_atomic_get_new_connector_state(state, connector);
+   unsigned long long tmds_rate = conn_state->hdmi.tmds_char_rate;
unsigned int x, y;
u32 val = 0;
 
DRM_DEBUG_DRIVER("Enabling the HDMI Output\n");
 
-   clk_set_rate(hdmi->mod_clk, mode->crtc_clock * 1000);
-   clk_set_rate(hdmi->tmds_clk, mode->crtc_clock * 1000);
+   clk_set_rate(hdmi->mod_clk, tmds_rate);
+   clk_set_rate(hdmi->tmds_clk, tmds_rate);
 
/* Set input sync enable */
writel(SUN4I_HDMI_UNKNOWN_INPUT_SYNC,
   hdmi->base + SUN4I_HDMI_UNKNOWN_REG);
 
@@ -141,11 +142,12 @@ static void sun4i_hdmi_enable(struct drm_encoder *encoder,
 
writel(val, hdmi->base + SUN4I_HDMI_VID_TIMING_POL_REG);
 
clk_prepare_enable(hdmi->tmds_clk);
 
-   sun4i_hdmi_setup_avi_infoframes(hdmi, mode);
+   drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
+
val |= SUN4I_HDMI_PKT_CTRL_TYPE(0, SUN4I_HDMI_PKT_AVI);
val |= SUN4I_HDMI_PKT_CTRL_TYPE(1, SUN4I_HDMI_PKT_END);
writel(val, hdmi->base + SUN4I_HDMI

[PATCH v15 22/29] drm/connector: hdmi: Add Infoframes generation

2024-05-27 Thread Maxime Ripard
Infoframes in KMS is usually handled by a bunch of low-level helpers
that require quite some boilerplate for drivers. This leads to
discrepancies with how drivers generate them, and which are actually
sent.

Now that we have everything needed to generate them in the HDMI
connector state, we can generate them in our common logic so that
drivers can simply reuse what we precomputed.

Cc: Ville Syrjälä 
Reviewed-by: Dmitry Baryshkov 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/display/drm_hdmi_state_helper.c| 336 +
 drivers/gpu/drm/drm_connector.c|  14 +
 drivers/gpu/drm/tests/drm_connector_test.c |  12 +
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c |   1 +
 include/drm/display/drm_hdmi_state_helper.h|   7 +
 include/drm/drm_connector.h| 111 ++-
 6 files changed, 480 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c 
b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index f18020cfe4ea..ce96837eea65 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -331,10 +331,148 @@ hdmi_compute_config(const struct drm_connector 
*connector,
}
 
return -EINVAL;
 }
 
+static int hdmi_generate_avi_infoframe(const struct drm_connector *connector,
+  struct drm_connector_state *conn_state)
+{
+   const struct drm_display_mode *mode =
+   connector_state_get_mode(conn_state);
+   struct drm_connector_hdmi_infoframe *infoframe =
+   _state->hdmi.infoframes.avi;
+   struct hdmi_avi_infoframe *frame =
+   >data.avi;
+   bool is_limited_range = conn_state->hdmi.is_limited_range;
+   enum hdmi_quantization_range rgb_quant_range =
+   is_limited_range ? HDMI_QUANTIZATION_RANGE_LIMITED : 
HDMI_QUANTIZATION_RANGE_FULL;
+   int ret;
+
+   ret = drm_hdmi_avi_infoframe_from_display_mode(frame, connector, mode);
+   if (ret)
+   return ret;
+
+   frame->colorspace = conn_state->hdmi.output_format;
+
+   /*
+* FIXME: drm_hdmi_avi_infoframe_quant_range() doesn't handle
+* YUV formats at all at the moment, so if we ever support YUV
+* formats this needs to be revised.
+*/
+   drm_hdmi_avi_infoframe_quant_range(frame, connector, mode, 
rgb_quant_range);
+   drm_hdmi_avi_infoframe_colorimetry(frame, conn_state);
+   drm_hdmi_avi_infoframe_bars(frame, conn_state);
+
+   infoframe->set = true;
+
+   return 0;
+}
+
+static int hdmi_generate_spd_infoframe(const struct drm_connector *connector,
+  struct drm_connector_state *conn_state)
+{
+   struct drm_connector_hdmi_infoframe *infoframe =
+   _state->hdmi.infoframes.spd;
+   struct hdmi_spd_infoframe *frame =
+   >data.spd;
+   int ret;
+
+   ret = hdmi_spd_infoframe_init(frame,
+ connector->hdmi.vendor,
+ connector->hdmi.product);
+   if (ret)
+   return ret;
+
+   frame->sdi = HDMI_SPD_SDI_PC;
+
+   infoframe->set = true;
+
+   return 0;
+}
+
+static int hdmi_generate_hdr_infoframe(const struct drm_connector *connector,
+  struct drm_connector_state *conn_state)
+{
+   struct drm_connector_hdmi_infoframe *infoframe =
+   _state->hdmi.infoframes.hdr_drm;
+   struct hdmi_drm_infoframe *frame =
+   >data.drm;
+   int ret;
+
+   if (connector->max_bpc < 10)
+   return 0;
+
+   if (!conn_state->hdr_output_metadata)
+   return 0;
+
+   ret = drm_hdmi_infoframe_set_hdr_metadata(frame, conn_state);
+   if (ret)
+   return ret;
+
+   infoframe->set = true;
+
+   return 0;
+}
+
+static int hdmi_generate_hdmi_vendor_infoframe(const struct drm_connector 
*connector,
+  struct drm_connector_state 
*conn_state)
+{
+   const struct drm_display_info *info = >display_info;
+   const struct drm_display_mode *mode =
+   connector_state_get_mode(conn_state);
+   struct drm_connector_hdmi_infoframe *infoframe =
+   _state->hdmi.infoframes.hdmi;
+   struct hdmi_vendor_infoframe *frame =
+   >data.vendor.hdmi;
+   int ret;
+
+   if (!info->has_hdmi_infoframe)
+   return 0;
+
+   ret = drm_hdmi_vendor_infoframe_from_display_mode(frame, connector, 
mode);
+   if (ret)
+   return ret;
+
+   infoframe->set = true;
+
+   return 0;
+}
+
+static int
+hdmi_generate_infoframes(const struct drm_connector *connector,
+struct drm_connector_state *conn_state)
+{
+  

[PATCH v15 21/29] drm/tests: Add RGB Quantization tests

2024-05-27 Thread Maxime Ripard
The previous commit added the infrastructure to the connector state to
track what RGB Quantization should be used in a given state for an HDMI
connector.

Let's add some kunit tests to make sure it works as expected.

Reviewed-by: Dave Stevenson 
Reviewed-by: Dmitry Baryshkov 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 355 +
 1 file changed, 355 insertions(+)

diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c 
b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
index ff9a882201eb..da5c3d9a80bb 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -353,10 +353,354 @@ static void 
drm_test_check_broadcast_rgb_crtc_mode_not_changed(struct kunit *tes
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
KUNIT_EXPECT_FALSE(test, crtc_state->mode_changed);
 }
 
+/*
+ * Test that for an HDMI connector, with an HDMI monitor, if the
+ * Broadcast RGB property is set to auto with a mode that isn't the
+ * VIC-1 mode, we will get a limited RGB Quantization Range.
+ */
+static void drm_test_check_broadcast_rgb_auto_cea_mode(struct kunit *test)
+{
+   struct drm_atomic_helper_connector_hdmi_priv *priv;
+   struct drm_modeset_acquire_ctx *ctx;
+   struct drm_connector_state *conn_state;
+   struct drm_atomic_state *state;
+   struct drm_display_mode *preferred;
+   struct drm_connector *conn;
+   struct drm_device *drm;
+   struct drm_crtc *crtc;
+   int ret;
+
+   priv = drm_atomic_helper_connector_hdmi_init(test,
+BIT(HDMI_COLORSPACE_RGB),
+8);
+   KUNIT_ASSERT_NOT_NULL(test, priv);
+
+   conn = >connector;
+   KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi);
+
+   ctx = drm_kunit_helper_acquire_ctx_alloc(test);
+   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+
+   preferred = find_preferred_mode(conn);
+   KUNIT_ASSERT_NOT_NULL(test, preferred);
+   KUNIT_ASSERT_NE(test, drm_match_cea_mode(preferred), 1);
+
+   drm = >drm;
+   crtc = priv->crtc;
+   ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
+   KUNIT_ASSERT_EQ(test, ret, 0);
+
+   state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
+   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+   conn_state = drm_atomic_get_connector_state(state, conn);
+   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+   KUNIT_ASSERT_EQ(test,
+   conn_state->hdmi.broadcast_rgb,
+   DRM_HDMI_BROADCAST_RGB_AUTO);
+
+   ret = drm_atomic_check_only(state);
+   KUNIT_ASSERT_EQ(test, ret, 0);
+
+   conn_state = drm_atomic_get_connector_state(state, conn);
+   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+   KUNIT_EXPECT_TRUE(test, conn_state->hdmi.is_limited_range);
+}
+
+/*
+ * Test that for an HDMI connector, with an HDMI monitor, if the
+ * Broadcast RGB property is set to auto with a VIC-1 mode, we will get
+ * a full RGB Quantization Range.
+ */
+static void drm_test_check_broadcast_rgb_auto_cea_mode_vic_1(struct kunit 
*test)
+{
+   struct drm_atomic_helper_connector_hdmi_priv *priv;
+   struct drm_modeset_acquire_ctx *ctx;
+   struct drm_connector_state *conn_state;
+   struct drm_atomic_state *state;
+   struct drm_display_mode *mode;
+   struct drm_connector *conn;
+   struct drm_device *drm;
+   struct drm_crtc *crtc;
+   int ret;
+
+   priv = drm_atomic_helper_connector_hdmi_init(test,
+BIT(HDMI_COLORSPACE_RGB),
+8);
+   KUNIT_ASSERT_NOT_NULL(test, priv);
+
+   drm = >drm;
+   conn = >connector;
+   KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi);
+
+   ctx = drm_kunit_helper_acquire_ctx_alloc(test);
+   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+
+   mode = drm_display_mode_from_cea_vic(drm, 1);
+   KUNIT_ASSERT_NOT_NULL(test, mode);
+
+   drm = >drm;
+   crtc = priv->crtc;
+   ret = light_up_connector(test, drm, crtc, conn, mode, ctx);
+   KUNIT_ASSERT_EQ(test, ret, 0);
+
+   state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
+   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+   conn_state = drm_atomic_get_connector_state(state, conn);
+   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+   KUNIT_ASSERT_EQ(test,
+   conn_state->hdmi.broadcast_rgb,
+   DRM_HDMI_BROADCAST_RGB_AUTO);
+
+   ret = drm_atomic_check_only(state);
+   KUNIT_ASSERT_EQ(test, ret, 0);
+
+   conn_state = drm_atomic_get_connector_state(state, conn);
+   KUNIT_

[PATCH v15 28/29] drm/rockchip: inno_hdmi: Switch to HDMI connector

2024-05-27 Thread Maxime Ripard
The new HDMI connector infrastructure allows to remove some boilerplate,
especially to generate infoframes. Let's switch to it.

Reviewed-by: Heiko Stuebner 
Acked-by: Heiko Stuebner 
Acked-by: Andy Yan 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/rockchip/Kconfig |   3 +
 drivers/gpu/drm/rockchip/inno_hdmi.c | 172 +--
 2 files changed, 66 insertions(+), 109 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 1bf3e2829cd0..7df875e38517 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -72,10 +72,13 @@ config ROCKCHIP_DW_MIPI_DSI
  enable MIPI DSI on RK3288 or RK3399 based SoC, you should
  select this option.
 
 config ROCKCHIP_INNO_HDMI
bool "Rockchip specific extensions for Innosilicon HDMI"
+   select DRM_DISPLAY_HDMI_HELPER
+   select DRM_DISPLAY_HDMI_STATE_HELPER
+   select DRM_DISPLAY_HELPER
help
  This selects support for Rockchip SoC specific extensions
  for the Innosilicon HDMI driver. If you want to enable
  HDMI on RK3036 based SoC, you should select this option.
 
diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c 
b/drivers/gpu/drm/rockchip/inno_hdmi.c
index 3df2cfcf9998..2241e53a2946 100644
--- a/drivers/gpu/drm/rockchip/inno_hdmi.c
+++ b/drivers/gpu/drm/rockchip/inno_hdmi.c
@@ -20,10 +20,13 @@
 #include 
 #include 
 #include 
 #include 
 
+#include 
+#include 
+
 #include "rockchip_drm_drv.h"
 
 #include "inno_hdmi.h"
 
 #define INNO_HDMI_MIN_TMDS_CLOCK  2500U
@@ -65,13 +68,11 @@ struct inno_hdmi {
const struct inno_hdmi_variant *variant;
 };
 
 struct inno_hdmi_connector_state {
struct drm_connector_state  base;
-   unsigned intenc_out_format;
unsigned intcolorimetry;
-   boolrgb_limited_range;
 };
 
 static struct inno_hdmi *encoder_to_inno_hdmi(struct drm_encoder *encoder)
 {
struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
@@ -255,90 +256,53 @@ static void inno_hdmi_reset(struct inno_hdmi *hdmi)
hdmi_modb(hdmi, HDMI_SYS_CTRL, msk, val);
 
inno_hdmi_standby(hdmi);
 }
 
-static void inno_hdmi_disable_frame(struct inno_hdmi *hdmi,
-   enum hdmi_infoframe_type type)
+static int inno_hdmi_disable_frame(struct drm_connector *connector,
+  enum hdmi_infoframe_type type)
 {
-   struct drm_connector *connector = >connector;
-
-   if (type != HDMI_INFOFRAME_TYPE_AVI) {
-   drm_err(connector->dev,
-   "Unsupported infoframe type: %u\n", type);
-   return;
-   }
-
-   hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI);
-}
-
-static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi,
- union hdmi_infoframe *frame, enum 
hdmi_infoframe_type type)
-{
-   struct drm_connector *connector = >connector;
-   u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE];
-   ssize_t rc, i;
+   struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector);
 
if (type != HDMI_INFOFRAME_TYPE_AVI) {
drm_err(connector->dev,
"Unsupported infoframe type: %u\n", type);
return 0;
}
 
-   inno_hdmi_disable_frame(hdmi, type);
+   hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI);
 
-   rc = hdmi_infoframe_pack(frame, packed_frame,
-sizeof(packed_frame));
-   if (rc < 0)
-   return rc;
+   return 0;
+}
 
-   for (i = 0; i < rc; i++)
+static int inno_hdmi_upload_frame(struct drm_connector *connector,
+ enum hdmi_infoframe_type type,
+ const u8 *buffer, size_t len)
+{
+   struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector);
+   u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE];
+   ssize_t i;
+
+   if (type != HDMI_INFOFRAME_TYPE_AVI) {
+   drm_err(connector->dev,
+   "Unsupported infoframe type: %u\n", type);
+   return 0;
+   }
+
+   inno_hdmi_disable_frame(connector, type);
+
+   for (i = 0; i < len; i++)
hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_ADDR + i,
packed_frame[i]);
 
return 0;
 }
 
-static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi,
- struct drm_display_mode *mode)
-{
-   struct drm_connector *connector = >connector;
-   struct drm_connector_state *conn_state = connector->state;
-   struct inno_hdmi_connector_state *inno_conn_state =
-   to_inno_hdm

[PATCH v15 27/29] drm/vc4: tests: Convert to plane creation helper

2024-05-27 Thread Maxime Ripard
Now that we have a plane create helper for kunit mocked drivers, let's
convert to it in vc4.

Reviewed-by: Maíra Canal 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/vc4/tests/vc4_mock_plane.c | 34 +++---
 1 file changed, 8 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c 
b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c
index 973f5f929097..14357db82238 100644
--- a/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c
@@ -1,43 +1,25 @@
 // SPDX-License-Identifier: GPL-2.0
 
-#include 
-#include 
-#include 
+#include 
 #include 
 
 #include 
 
 #include "vc4_mock.h"
 
-static const struct drm_plane_helper_funcs vc4_dummy_plane_helper_funcs = {
-};
-
-static const struct drm_plane_funcs vc4_dummy_plane_funcs = {
-   .atomic_destroy_state   = drm_atomic_helper_plane_destroy_state,
-   .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
-   .reset  = drm_atomic_helper_plane_reset,
-};
-
-static const uint32_t vc4_dummy_plane_formats[] = {
-   DRM_FORMAT_XRGB,
-};
-
 struct drm_plane *vc4_dummy_plane(struct kunit *test, struct drm_device *drm,
  enum drm_plane_type type)
 {
struct drm_plane *plane;
 
-   plane = __drmm_universal_plane_alloc(drm, sizeof(struct drm_plane), 0,
-0,
-_dummy_plane_funcs,
-vc4_dummy_plane_formats,
-
ARRAY_SIZE(vc4_dummy_plane_formats),
-NULL,
-DRM_PLANE_TYPE_PRIMARY,
-NULL);
-   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane);
+   KUNIT_ASSERT_EQ(test, type, DRM_PLANE_TYPE_PRIMARY);
 
-   drm_plane_helper_add(plane, _dummy_plane_helper_funcs);
+   plane = drm_kunit_helper_create_primary_plane(test, drm,
+ NULL,
+ NULL,
+ NULL, 0,
+ NULL);
+   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane);
 
return plane;
 }

-- 
2.45.0



[PATCH v15 24/29] drm/connector: hdmi: Create Infoframe DebugFS entries

2024-05-27 Thread Maxime Ripard
There has been some discussions recently about the infoframes sent by
drivers and if they were properly generated.

In parallel, there's been some interest in creating an infoframe-decode
tool similar to edid-decode.

Both would be much easier if we were to expose the infoframes programmed
in the hardware. It won't be perfect since we have no guarantee that
it's actually what goes through the wire, but it's the best we can do.

Reviewed-by: Dmitry Baryshkov 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/drm_debugfs.c | 152 ++
 1 file changed, 152 insertions(+)

diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c
index 08fcefd804bc..dd39a5b7a711 100644
--- a/drivers/gpu/drm/drm_debugfs.c
+++ b/drivers/gpu/drm/drm_debugfs.c
@@ -518,10 +518,160 @@ static const struct file_operations drm_connector_fops = 
{
.llseek = seq_lseek,
.release = single_release,
.write = connector_write
 };
 
+#define HDMI_MAX_INFOFRAME_SIZE29
+
+static ssize_t
+audio_infoframe_read(struct file *filp, char __user *ubuf, size_t count, 
loff_t *ppos)
+{
+   struct drm_connector_hdmi_infoframe *infoframe;
+   struct drm_connector *connector;
+   union hdmi_infoframe *frame;
+   u8 buf[HDMI_INFOFRAME_SIZE(AUDIO)];
+   ssize_t len = 0;
+
+   connector = filp->private_data;
+   mutex_lock(>hdmi.infoframes.lock);
+
+   infoframe = >hdmi.infoframes.audio;
+   if (!infoframe->set)
+   goto out;
+
+   frame = >data;
+   len = hdmi_infoframe_pack(frame, buf, sizeof(buf));
+   if (len < 0)
+   goto out;
+
+   len = simple_read_from_buffer(ubuf, count, ppos, buf, len);
+
+out:
+   mutex_unlock(>hdmi.infoframes.lock);
+   return len;
+}
+
+static const struct file_operations audio_infoframe_fops = {
+   .owner   = THIS_MODULE,
+   .open= simple_open,
+   .read= audio_infoframe_read,
+};
+
+static int create_hdmi_audio_infoframe_file(struct drm_connector *connector,
+   struct dentry *parent)
+{
+   struct dentry *file;
+
+   file = debugfs_create_file("audio", 0400, parent, connector, 
_infoframe_fops);
+   if (IS_ERR(file))
+   return PTR_ERR(file);
+
+   return 0;
+}
+
+#define DEFINE_INFOFRAME_FILE(_f) \
+static ssize_t _f##_read_infoframe(struct file *filp, \
+  char __user *ubuf, \
+  size_t count,  \
+  loff_t *ppos)  \
+{ \
+   struct drm_connector_hdmi_infoframe *infoframe; \
+   struct drm_connector_state *conn_state; \
+   struct drm_connector *connector; \
+   union hdmi_infoframe *frame; \
+   struct drm_device *dev; \
+   u8 buf[HDMI_MAX_INFOFRAME_SIZE]; \
+   ssize_t len = 0; \
+   \
+   connector = filp->private_data; \
+   dev = connector->dev; \
+   \
+   drm_modeset_lock(>mode_config.connection_mutex, NULL); \
+   \
+   conn_state = connector->state; \
+   infoframe = _state->hdmi.infoframes._f; \
+   if (!infoframe->set) \
+   goto out; \
+   \
+   frame = >data; \
+   len = hdmi_infoframe_pack(frame, buf, sizeof(buf)); \
+   if (len < 0) \
+   goto out; \
+   \
+   len = simple_read_from_buffer(ubuf, count, ppos, buf, len); \
+   \
+out: \
+   drm_modeset_unlock(>mode_config.connection_mutex); \
+   return len; \
+} \
+\
+static const struct file_operations _f##_infoframe_fops = { \
+   .owner = THIS_MODULE, \
+   .open = simple_open, \
+   .read = _f##_read_infoframe, \
+}; \
+\
+static int create_hdmi_## _f ## _infoframe_file (struct drm_connector 
*connector, \
+struct dentry *parent) \
+{ \
+   struct dentry *file; \
+   \
+   file = debugfs_create_file(#_f, 0400, parent, connector, & _f ## 
_infoframe_fops); \
+   if (IS_ERR(file)) \
+   return PTR_ERR(file); \
+   \
+   return 0; \
+}
+
+DEFINE_INFOFRAME_FILE(avi);
+DEFINE_INFOFRAME_FILE(hdmi);
+DEFINE_INFOFRAME_FILE(hdr_drm);
+DEFINE_INFOFRAME_FILE(spd);
+
+static int create_hdmi_infoframe_files(struct drm_connector *connector,
+  struct dentry *parent)
+{
+   int ret;
+
+   ret = create_hdmi_audio_infoframe_file(connector, parent);
+   if (ret)
+   return ret;
+
+   ret = create_hdmi_avi_infoframe_file(connector, parent);
+   if (ret)
+   return ret;
+
+   ret = create_hdmi_hdmi_infoframe_file(connector, parent);
+   if (ret)
+   return ret;
+
+   ret = create_hdmi_hdr_drm_infoframe_file(connector, parent);
+   if (ret)
+   return ret;
+
+   ret = create_hdmi_spd_infoframe_file(c

[PATCH v15 20/29] drm/connector: hdmi: Add RGB Quantization Range to the connector state

2024-05-27 Thread Maxime Ripard
HDMI controller drivers will need to figure out the RGB range they need
to configure based on a mode and property values. Let's expose that in
the HDMI connector state so drivers can just use that value.

Reviewed-by: Dave Stevenson 
Reviewed-by: Dmitry Baryshkov 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/display/drm_hdmi_state_helper.c | 29 +
 drivers/gpu/drm/drm_atomic.c|  1 +
 include/drm/drm_connector.h |  6 +
 3 files changed, 36 insertions(+)

diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c 
b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 57c66beec5bc..f18020cfe4ea 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -49,10 +49,37 @@ connector_state_get_mode(const struct drm_connector_state 
*conn_state)
return NULL;
 
return _state->mode;
 }
 
+static bool hdmi_is_limited_range(const struct drm_connector *connector,
+ const struct drm_connector_state *conn_state)
+{
+   const struct drm_display_info *info = >display_info;
+   const struct drm_display_mode *mode =
+   connector_state_get_mode(conn_state);
+
+   /*
+* The Broadcast RGB property only applies to RGB format, and
+* i915 just assumes limited range for YCbCr output, so let's
+* just do the same.
+*/
+   if (conn_state->hdmi.output_format != HDMI_COLORSPACE_RGB)
+   return true;
+
+   if (conn_state->hdmi.broadcast_rgb == DRM_HDMI_BROADCAST_RGB_FULL)
+   return false;
+
+   if (conn_state->hdmi.broadcast_rgb == DRM_HDMI_BROADCAST_RGB_LIMITED)
+   return true;
+
+   if (!info->is_hdmi)
+   return false;
+
+   return drm_default_rgb_quant_range(mode) == 
HDMI_QUANTIZATION_RANGE_LIMITED;
+}
+
 static bool
 sink_supports_format_bpc(const struct drm_connector *connector,
 const struct drm_display_info *info,
 const struct drm_display_mode *mode,
 unsigned int format, unsigned int bpc)
@@ -327,10 +354,12 @@ int drm_atomic_helper_connector_hdmi_check(struct 
drm_connector *connector,
drm_atomic_get_new_connector_state(state, connector);
const struct drm_display_mode *mode =
connector_state_get_mode(new_conn_state);
int ret;
 
+   new_conn_state->hdmi.is_limited_range = 
hdmi_is_limited_range(connector, new_conn_state);
+
ret = hdmi_compute_config(connector, new_conn_state, mode);
if (ret)
return ret;
 
if (old_conn_state->hdmi.broadcast_rgb != 
new_conn_state->hdmi.broadcast_rgb ||
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 3e57d98d8418..07b4b394e3bf 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1145,10 +1145,11 @@ static void drm_atomic_connector_print_state(struct 
drm_printer *p,
 
if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) {
drm_printf(p, "\tbroadcast_rgb=%s\n",
   
drm_hdmi_connector_get_broadcast_rgb_name(state->hdmi.broadcast_rgb));
+   drm_printf(p, "\tis_limited_range=%c\n", 
state->hdmi.is_limited_range ? 'y' : 'n');
drm_printf(p, "\toutput_bpc=%u\n", state->hdmi.output_bpc);
drm_printf(p, "\toutput_format=%s\n",
   
drm_hdmi_connector_get_output_format_name(state->hdmi.output_format));
drm_printf(p, "\ttmds_char_rate=%llu\n", 
state->hdmi.tmds_char_rate);
}
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index a40eaf3a8ce4..1fca26d51218 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1068,10 +1068,16 @@ struct drm_connector_state {
 * @broadcast_rgb: Connector property to pass the
 * Broadcast RGB selection value.
 */
enum drm_hdmi_broadcast_rgb broadcast_rgb;
 
+   /**
+* @is_full_range: Is the output supposed to use a full
+* RGB Quantization Range or not?
+*/
+   bool is_limited_range;
+
/**
 * @output_bpc: Bits per color channel to output.
 */
unsigned int output_bpc;
 

-- 
2.45.0



[PATCH v15 18/29] drm/connector: hdmi: Add Broadcast RGB property

2024-05-27 Thread Maxime Ripard
The i915 driver has a property to force the RGB range of an HDMI output.
The vc4 driver then implemented the same property with the same
semantics. KWin has support for it, and a PR for mutter is also there to
support it.

Both drivers implementing the same property with the same semantics,
plus the userspace having support for it, is proof enough that it's
pretty much a de-facto standard now and we can provide helpers for it.

Let's plumb it into the newly created HDMI connector.

Reviewed-by: Dave Stevenson 
Acked-by: Pekka Paalanen 
Reviewed-by: Sebastian Wick 
Signed-off-by: Maxime Ripard 
---
 Documentation/gpu/kms-properties.csv|  1 -
 drivers/gpu/drm/display/drm_hdmi_state_helper.c |  4 +-
 drivers/gpu/drm/drm_atomic.c|  2 +
 drivers/gpu/drm/drm_atomic_uapi.c   |  4 ++
 drivers/gpu/drm/drm_connector.c | 88 +
 include/drm/drm_connector.h | 36 ++
 6 files changed, 133 insertions(+), 2 deletions(-)

diff --git a/Documentation/gpu/kms-properties.csv 
b/Documentation/gpu/kms-properties.csv
index c3c50a277cc9..bfbfbf4f102d 100644
--- a/Documentation/gpu/kms-properties.csv
+++ b/Documentation/gpu/kms-properties.csv
@@ -15,11 +15,10 @@ Owner Module/Drivers,Group,Property Name,Type,Property 
Values,Object attached,De
 ,,“saturation”,RANGE,"Min=0, Max=100",Connector,TBD
 ,,“hue”,RANGE,"Min=0, Max=100",Connector,TBD
 ,Virtual GPU,“suggested X”,RANGE,"Min=0, Max=0x",Connector,property to 
suggest an X offset for a connector
 ,,“suggested Y”,RANGE,"Min=0, Max=0x",Connector,property to suggest an 
Y offset for a connector
 ,Optional,"""aspect ratio""",ENUM,"{ ""None"", ""4:3"", ""16:9"" 
}",Connector,TDB
-i915,Generic,"""Broadcast RGB""",ENUM,"{ ""Automatic"", ""Full"", ""Limited 
16:235"" }",Connector,"When this property is set to Limited 16:235 and CTM is 
set, the hardware will be programmed with the result of the multiplication of 
CTM by the limited range matrix to ensure the pixels normally in the range 
0..1.0 are remapped to the range 16/255..235/255."
 ,,“audio”,ENUM,"{ ""force-dvi"", ""off"", ""auto"", ""on"" }",Connector,TBD
 ,SDVO-TV,“mode”,ENUM,"{ ""NTSC_M"", ""NTSC_J"", ""NTSC_443"", ""PAL_B"" } 
etc.",Connector,TBD
 ,,"""left_margin""",RANGE,"Min=0, Max= SDVO dependent",Connector,TBD
 ,,"""right_margin""",RANGE,"Min=0, Max= SDVO dependent",Connector,TBD
 ,,"""top_margin""",RANGE,"Min=0, Max= SDVO dependent",Connector,TBD
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c 
b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 1623b96cd97c..57c66beec5bc 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -23,10 +23,11 @@ void __drm_atomic_helper_connector_hdmi_reset(struct 
drm_connector *connector,
 {
unsigned int max_bpc = connector->max_bpc;
 
new_conn_state->max_bpc = max_bpc;
new_conn_state->max_requested_bpc = max_bpc;
+   new_conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_AUTO;
 }
 EXPORT_SYMBOL(__drm_atomic_helper_connector_hdmi_reset);
 
 static const struct drm_display_mode *
 connector_state_get_mode(const struct drm_connector_state *conn_state)
@@ -330,11 +331,12 @@ int drm_atomic_helper_connector_hdmi_check(struct 
drm_connector *connector,
 
ret = hdmi_compute_config(connector, new_conn_state, mode);
if (ret)
return ret;
 
-   if (old_conn_state->hdmi.output_bpc != new_conn_state->hdmi.output_bpc 
||
+   if (old_conn_state->hdmi.broadcast_rgb != 
new_conn_state->hdmi.broadcast_rgb ||
+   old_conn_state->hdmi.output_bpc != new_conn_state->hdmi.output_bpc 
||
old_conn_state->hdmi.output_format != 
new_conn_state->hdmi.output_format) {
struct drm_crtc *crtc = new_conn_state->crtc;
struct drm_crtc_state *crtc_state;
 
crtc_state = drm_atomic_get_crtc_state(state, crtc);
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 26f9e525c0a0..3e57d98d8418 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1143,10 +1143,12 @@ static void drm_atomic_connector_print_state(struct 
drm_printer *p,
drm_printf(p, "\tmax_requested_bpc=%d\n", state->max_requested_bpc);
drm_printf(p, "\tcolorsp

[PATCH v15 19/29] drm/tests: Add tests for Broadcast RGB property

2024-05-27 Thread Maxime Ripard
This had a bunch of kunit tests to make sure our code to handle the
Broadcast RGB property behaves properly.

This requires bringing a bit of infrastructure to create mock HDMI
connectors, with custom EDIDs.

Reviewed-by: Dave Stevenson 
Reviewed-by: Dmitry Baryshkov 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/tests/drm_connector_test.c | 116 
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 151 +
 2 files changed, 267 insertions(+)

diff --git a/drivers/gpu/drm/tests/drm_connector_test.c 
b/drivers/gpu/drm/tests/drm_connector_test.c
index e44dfe2e9455..a4ea170a2575 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -579,10 +579,67 @@ static struct kunit_case 
drm_get_tv_mode_from_name_tests[] = {
 static struct kunit_suite drm_get_tv_mode_from_name_test_suite = {
.name = "drm_get_tv_mode_from_name",
.test_cases = drm_get_tv_mode_from_name_tests,
 };
 
+struct drm_hdmi_connector_get_broadcast_rgb_name_test {
+   unsigned int kind;
+   const char *expected_name;
+};
+
+#define BROADCAST_RGB_TEST(_kind, _name)   \
+   {   \
+   .kind = _kind,  \
+   .expected_name = _name, \
+   }
+
+static void drm_test_drm_hdmi_connector_get_broadcast_rgb_name(struct kunit 
*test)
+{
+   const struct drm_hdmi_connector_get_broadcast_rgb_name_test *params =
+   test->param_value;
+
+   KUNIT_EXPECT_STREQ(test,
+  
drm_hdmi_connector_get_broadcast_rgb_name(params->kind),
+  params->expected_name);
+}
+
+static const
+struct drm_hdmi_connector_get_broadcast_rgb_name_test
+drm_hdmi_connector_get_broadcast_rgb_name_valid_tests[] = {
+   BROADCAST_RGB_TEST(DRM_HDMI_BROADCAST_RGB_AUTO, "Automatic"),
+   BROADCAST_RGB_TEST(DRM_HDMI_BROADCAST_RGB_FULL, "Full"),
+   BROADCAST_RGB_TEST(DRM_HDMI_BROADCAST_RGB_LIMITED, "Limited 16:235"),
+};
+
+static void
+drm_hdmi_connector_get_broadcast_rgb_name_valid_desc(const struct 
drm_hdmi_connector_get_broadcast_rgb_name_test *t,
+char *desc)
+{
+   sprintf(desc, "%s", t->expected_name);
+}
+
+KUNIT_ARRAY_PARAM(drm_hdmi_connector_get_broadcast_rgb_name_valid,
+ drm_hdmi_connector_get_broadcast_rgb_name_valid_tests,
+ drm_hdmi_connector_get_broadcast_rgb_name_valid_desc);
+
+static void drm_test_drm_hdmi_connector_get_broadcast_rgb_name_invalid(struct 
kunit *test)
+{
+   KUNIT_EXPECT_NULL(test, drm_hdmi_connector_get_broadcast_rgb_name(3));
+};
+
+static struct kunit_case drm_hdmi_connector_get_broadcast_rgb_name_tests[] = {
+   KUNIT_CASE_PARAM(drm_test_drm_hdmi_connector_get_broadcast_rgb_name,
+
drm_hdmi_connector_get_broadcast_rgb_name_valid_gen_params),
+   KUNIT_CASE(drm_test_drm_hdmi_connector_get_broadcast_rgb_name_invalid),
+   { }
+};
+
+static struct kunit_suite drm_hdmi_connector_get_broadcast_rgb_name_test_suite 
= {
+   .name = "drm_hdmi_connector_get_broadcast_rgb_name",
+   .test_cases = drm_hdmi_connector_get_broadcast_rgb_name_tests,
+};
+
 struct drm_hdmi_connector_get_output_format_name_test {
unsigned int kind;
const char *expected_name;
 };
 
@@ -637,10 +694,67 @@ static struct kunit_case 
drm_hdmi_connector_get_output_format_name_tests[] = {
 static struct kunit_suite drm_hdmi_connector_get_output_format_name_test_suite 
= {
.name = "drm_hdmi_connector_get_output_format_name",
.test_cases = drm_hdmi_connector_get_output_format_name_tests,
 };
 
+static void drm_test_drm_connector_attach_broadcast_rgb_property(struct kunit 
*test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   struct drm_connector *connector = >connector;
+   struct drm_property *prop;
+   int ret;
+
+   ret = drmm_connector_init(>drm, connector,
+ _funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ >ddc);
+   KUNIT_ASSERT_EQ(test, ret, 0);
+
+   ret = drm_connector_attach_broadcast_rgb_property(connector);
+   KUNIT_ASSERT_EQ(test, ret, 0);
+
+   prop = connector->broadcast_rgb_property;
+   KUNIT_ASSERT_NOT_NULL(test, prop);
+   KUNIT_EXPECT_NOT_NULL(test, drm_mode_obj_find_prop_id(>base, 
prop->base.id));
+}
+
+static void 
drm_test_drm_connector_attach_broadcast_rgb_property_hdmi_connector(struct 
kunit *test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   struct drm_connector *connector = >connector;
+   struct drm_property *prop;
+   int ret;
+
+   ret = drmm_connector_hdmi_init(>d

[PATCH v15 10/29] drm/tests: Add HDMI TDMS character rate tests

2024-05-27 Thread Maxime Ripard
The previous patch added an helper to compute the TMDS character rate on
an HDMI connector. Let's add a few tests to make sure it works as
expected.

Reviewed-by: Dave Stevenson 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/tests/drm_connector_test.c | 300 +
 1 file changed, 300 insertions(+)

diff --git a/drivers/gpu/drm/tests/drm_connector_test.c 
b/drivers/gpu/drm/tests/drm_connector_test.c
index 250348ddfa70..8557f722080c 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -6,11 +6,15 @@
 #include 
 
 #include 
 #include 
 #include 
+#include 
 #include 
+#include 
+
+#include 
 
 #include 
 
 #include "../drm_crtc_internal.h"
 
@@ -619,14 +623,310 @@ static struct kunit_case 
drm_hdmi_connector_get_output_format_name_tests[] = {
 static struct kunit_suite drm_hdmi_connector_get_output_format_name_test_suite 
= {
.name = "drm_hdmi_connector_get_output_format_name",
.test_cases = drm_hdmi_connector_get_output_format_name_tests,
 };
 
+/*
+ * Test that for a given mode, with 8bpc and an RGB output the TMDS
+ * character rate is equal to the mode pixel clock.
+ */
+static void drm_test_drm_hdmi_compute_mode_clock_rgb(struct kunit *test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   const struct drm_display_mode *mode;
+   unsigned long long rate;
+   struct drm_device *drm = >drm;
+
+   mode = drm_display_mode_from_cea_vic(drm, 16);
+   KUNIT_ASSERT_NOT_NULL(test, mode);
+
+   KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);
+
+   rate = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB);
+   KUNIT_ASSERT_GT(test, rate, 0);
+   KUNIT_EXPECT_EQ(test, mode->clock * 1000ULL, rate);
+}
+
+/*
+ * Test that for a given mode, with 10bpc and an RGB output the TMDS
+ * character rate is equal to 1.25 times the mode pixel clock.
+ */
+static void drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc(struct kunit *test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   const struct drm_display_mode *mode;
+   unsigned long long rate;
+   struct drm_device *drm = >drm;
+
+   mode = drm_display_mode_from_cea_vic(drm, 16);
+   KUNIT_ASSERT_NOT_NULL(test, mode);
+
+   KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);
+
+   rate = drm_hdmi_compute_mode_clock(mode, 10, HDMI_COLORSPACE_RGB);
+   KUNIT_ASSERT_GT(test, rate, 0);
+   KUNIT_EXPECT_EQ(test, mode->clock * 1250, rate);
+}
+
+/*
+ * Test that for the VIC-1 mode, with 10bpc and an RGB output the TMDS
+ * character rate computation fails.
+ */
+static void drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc_vic_1(struct kunit 
*test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   const struct drm_display_mode *mode;
+   unsigned long long rate;
+   struct drm_device *drm = >drm;
+
+   mode = drm_display_mode_from_cea_vic(drm, 1);
+   KUNIT_ASSERT_NOT_NULL(test, mode);
+
+   rate = drm_hdmi_compute_mode_clock(mode, 10, HDMI_COLORSPACE_RGB);
+   KUNIT_EXPECT_EQ(test, rate, 0);
+}
+
+/*
+ * Test that for a given mode, with 12bpc and an RGB output the TMDS
+ * character rate is equal to 1.5 times the mode pixel clock.
+ */
+static void drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc(struct kunit *test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   const struct drm_display_mode *mode;
+   unsigned long long rate;
+   struct drm_device *drm = >drm;
+
+   mode = drm_display_mode_from_cea_vic(drm, 16);
+   KUNIT_ASSERT_NOT_NULL(test, mode);
+
+   KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);
+
+   rate = drm_hdmi_compute_mode_clock(mode, 12, HDMI_COLORSPACE_RGB);
+   KUNIT_ASSERT_GT(test, rate, 0);
+   KUNIT_EXPECT_EQ(test, mode->clock * 1500, rate);
+}
+
+/*
+ * Test that for the VIC-1 mode, with 12bpc and an RGB output the TMDS
+ * character rate computation fails.
+ */
+static void drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc_vic_1(struct kunit 
*test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   const struct drm_display_mode *mode;
+   unsigned long long rate;
+   struct drm_device *drm = >drm;
+
+   mode = drm_display_mode_from_cea_vic(drm, 1);
+   KUNIT_ASSERT_NOT_NULL(test, mode);
+
+   rate = drm_hdmi_compute_mode_clock(mode, 12, HDMI_COLORSPACE_RGB);
+   KUNIT_EXPECT_EQ(test, rate, 0);
+}
+
+/*
+ * Test that for a mode with the pixel repetition flag, the TMDS
+ * character rate is indeed double the mode pixel clock.
+ */
+static void drm_test_drm_hdmi_compute_mode_clock_rgb_double(struct kunit *test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   const struct drm_display_mode *mode;
+   unsigned long long rate;
+   struct drm_device *drm = >drm;
+
+ 

[PATCH v15 17/29] drm/doc: Remove unused Broadcast RGB Property

2024-05-27 Thread Maxime Ripard
The Broadcast RGB property has been documented as three separate entries
so far, each with a different set of values.

The first one is pretty much the generic one: it's used by i915 and vc4,
and is the one used by all the compositors.

The second one is used by the gma500 driver, and is a subset of the
first one: it can have the values "Full" or "Limited 16:235", but lack
the "Automatic" value.

The third one however isn't used by any driver and documents the values
"off", "auto" and "on".

It's unclear where the last one comes from. It was first documented in
commit 6c6a3996f2c5 ("Documentation: drm: describing drm properties
exposed by various drivers") which adds a number of properties used by
drivers, but without mentioning which driver was using what property.

Grepping at the 6c6a3996f2c5 commit however, it looks like no driver is
actually using it, and a quick look at the entire kernel history doesn't
show any match either.

At the time though, gma500 had an "audio" property used right next to
Broadcast RGB that did have the "off", "auto" and "on" values in the
same order.

As such, it was probably a copy/paste or scripting error back then, and
there's never been such property used in the kernel.

Either way, it certainly hasn't been used in a decade or two so we can
just get rid of it.

Suggested-by: Dmitry Baryshkov 
Signed-off-by: Maxime Ripard 
---
 Documentation/gpu/kms-properties.csv | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Documentation/gpu/kms-properties.csv 
b/Documentation/gpu/kms-properties.csv
index 0f9590834829..c3c50a277cc9 100644
--- a/Documentation/gpu/kms-properties.csv
+++ b/Documentation/gpu/kms-properties.csv
@@ -36,11 +36,10 @@ i915,Generic,"""Broadcast RGB""",ENUM,"{ ""Automatic"", 
""Full"", ""Limited 16:2
 ,,“tv_chroma_filter”,RANGE,"Min=0, Max= SDVO dependent",Connector,TBD
 ,,“tv_luma_filter”,RANGE,"Min=0, Max= SDVO dependent",Connector,TBD
 ,,“dot_crawl”,RANGE,"Min=0, Max=1",Connector,TBD
 ,SDVO-TV/LVDS,“brightness”,RANGE,"Min=0, Max= SDVO dependent",Connector,TBD
 CDV gma-500,Generic,"""Broadcast RGB""",ENUM,"{ “Full”, “Limited 16:235” 
}",Connector,TBD
-,,"""Broadcast RGB""",ENUM,"{ “off”, “auto”, “on” }",Connector,TBD
 Poulsbo,Generic,“backlight”,RANGE,"Min=0, Max=100",Connector,TBD
 ,SDVO-TV,“mode”,ENUM,"{ ""NTSC_M"", ""NTSC_J"", ""NTSC_443"", ""PAL_B"" } 
etc.",Connector,TBD
 ,,"""left_margin""",RANGE,"Min=0, Max= SDVO dependent",Connector,TBD
 ,,"""right_margin""",RANGE,"Min=0, Max= SDVO dependent",Connector,TBD
 ,,"""top_margin""",RANGE,"Min=0, Max= SDVO dependent",Connector,TBD

-- 
2.45.0



[PATCH v15 13/29] drm/connector: hdmi: Add custom hook to filter TMDS character rate

2024-05-27 Thread Maxime Ripard
Most of the HDMI controllers have an upper TMDS character rate limit
they can't exceed. On "embedded"-grade display controllers, it will
typically be lower than what high-grade monitors can provide these days,
so drivers will filter the TMDS character rate based on the controller
capabilities.

To make that easier to handle for drivers, let's provide an optional
hook to be implemented by drivers so they can tell the HDMI controller
helpers if a given TMDS character rate is reachable for them or not.

This will then be useful to figure out the best format and bpc count for
a given mode.

Reviewed-by: Dave Stevenson 
Reviewed-by: Dmitry Baryshkov 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/display/drm_hdmi_state_helper.c|  9 +++
 drivers/gpu/drm/drm_connector.c|  4 +++
 drivers/gpu/drm/tests/drm_connector_test.c | 14 ++
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c |  4 +++
 include/drm/drm_connector.h| 31 ++
 5 files changed, 62 insertions(+)

diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c 
b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 08630561d864..063421835dba 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -51,15 +51,24 @@ connector_state_get_mode(const struct drm_connector_state 
*conn_state)
 static enum drm_mode_status
 hdmi_clock_valid(const struct drm_connector *connector,
 const struct drm_display_mode *mode,
 unsigned long long clock)
 {
+   const struct drm_connector_hdmi_funcs *funcs = connector->hdmi.funcs;
const struct drm_display_info *info = >display_info;
 
if (info->max_tmds_clock && clock > info->max_tmds_clock * 1000)
return MODE_CLOCK_HIGH;
 
+   if (funcs && funcs->tmds_char_rate_valid) {
+   enum drm_mode_status status;
+
+   status = funcs->tmds_char_rate_valid(connector, mode, clock);
+   if (status != MODE_OK)
+   return status;
+   }
+
return MODE_OK;
 }
 
 static int
 hdmi_compute_clock(const struct drm_connector *connector,
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index b629c8e990f4..555eac20e5a4 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -455,10 +455,11 @@ EXPORT_SYMBOL(drmm_connector_init);
 /**
  * drmm_connector_hdmi_init - Init a preallocated HDMI connector
  * @dev: DRM device
  * @connector: A pointer to the HDMI connector to init
  * @funcs: callbacks for this connector
+ * @hdmi_funcs: HDMI-related callbacks for this connector
  * @connector_type: user visible type of the connector
  * @ddc: optional pointer to the associated ddc adapter
  * @supported_formats: Bitmask of @hdmi_colorspace listing supported output 
formats
  * @max_bpc: Maximum bits per char the HDMI connector supports
  *
@@ -474,10 +475,11 @@ EXPORT_SYMBOL(drmm_connector_init);
  * Zero on success, error code on failure.
  */
 int drmm_connector_hdmi_init(struct drm_device *dev,
 struct drm_connector *connector,
 const struct drm_connector_funcs *funcs,
+const struct drm_connector_hdmi_funcs *hdmi_funcs,
 int connector_type,
 struct i2c_adapter *ddc,
 unsigned long supported_formats,
 unsigned int max_bpc)
 {
@@ -510,10 +512,12 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
connector->max_bpc = max_bpc;
 
if (max_bpc > 8)
drm_connector_attach_hdr_output_metadata_property(connector);
 
+   connector->hdmi.funcs = hdmi_funcs;
+
return 0;
 }
 EXPORT_SYMBOL(drmm_connector_hdmi_init);
 
 /**
diff --git a/drivers/gpu/drm/tests/drm_connector_test.c 
b/drivers/gpu/drm/tests/drm_connector_test.c
index 8557f722080c..e44dfe2e9455 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -22,10 +22,13 @@ struct drm_connector_init_priv {
struct drm_device drm;
struct drm_connector connector;
struct i2c_adapter ddc;
 };
 
+static const struct drm_connector_hdmi_funcs dummy_hdmi_funcs = {
+};
+
 static const struct drm_connector_funcs dummy_funcs = {
.atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.reset  = drm_atomic_helper_connector_reset,
 };
@@ -187,10 +190,11 @@ static void drm_test_connector_hdmi_init_valid(struct 
kunit *test)
struct drm_connector_init_priv *priv = test->priv;
int ret;
 
ret = drmm_connector_hdmi_init(>

[PATCH v15 16/29] drm/tests: Add HDMI connector bpc and format tests

2024-05-27 Thread Maxime Ripard
The previous patch added the bpc and format an HDMI connector needs to
be set up with for a given connector state.

Let's add a few tests to make sure it works as expected.

Reviewed-by: Dmitry Baryshkov 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 509 +
 drivers/gpu/drm/tests/drm_kunit_edid.h | 160 +++
 2 files changed, 669 insertions(+)

diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c 
b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
index a49a544d7b49..968204781928 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -15,10 +15,11 @@
 #include 
 #include 
 #include 
 #include 
 
+#include 
 #include 
 
 #include "../drm_crtc_internal.h"
 
 #include 
@@ -370,10 +371,60 @@ static void 
drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit *test)
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
KUNIT_EXPECT_FALSE(test, crtc_state->mode_changed);
 }
 
+/*
+ * Test that if we have an HDMI connector but a !HDMI display, we always
+ * output RGB with 8 bpc.
+ */
+static void drm_test_check_output_bpc_dvi(struct kunit *test)
+{
+   struct drm_atomic_helper_connector_hdmi_priv *priv;
+   struct drm_modeset_acquire_ctx *ctx;
+   struct drm_connector_state *conn_state;
+   struct drm_display_info *info;
+   struct drm_display_mode *preferred;
+   struct drm_connector *conn;
+   struct drm_device *drm;
+   struct drm_crtc *crtc;
+   int ret;
+
+   priv = drm_atomic_helper_connector_hdmi_init(test,
+BIT(HDMI_COLORSPACE_RGB) |
+
BIT(HDMI_COLORSPACE_YUV422) |
+
BIT(HDMI_COLORSPACE_YUV444),
+12);
+   KUNIT_ASSERT_NOT_NULL(test, priv);
+
+   conn = >connector;
+   ret = set_connector_edid(test, conn,
+test_edid_dvi_1080p,
+ARRAY_SIZE(test_edid_dvi_1080p));
+   KUNIT_ASSERT_EQ(test, ret, 0);
+
+   info = >display_info;
+   KUNIT_ASSERT_FALSE(test, info->is_hdmi);
+
+   ctx = drm_kunit_helper_acquire_ctx_alloc(test);
+   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+
+   preferred = find_preferred_mode(conn);
+   KUNIT_ASSERT_NOT_NULL(test, preferred);
+
+   drm = >drm;
+   crtc = priv->crtc;
+   ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
+   KUNIT_ASSERT_EQ(test, ret, 0);
+
+   conn_state = conn->state;
+   KUNIT_ASSERT_NOT_NULL(test, conn_state);
+
+   KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8);
+   KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, 
HDMI_COLORSPACE_RGB);
+}
+
 /*
  * Test that when doing a commit which would use RGB 8bpc, the TMDS
  * clock rate stored in the connector state is equal to the mode clock
  */
 static void drm_test_check_tmds_char_rate_rgb_8bpc(struct kunit *test)
@@ -562,14 +613,472 @@ static void drm_test_check_hdmi_funcs_reject_rate(struct 
kunit *test)
 
ret = drm_atomic_check_only(state);
KUNIT_EXPECT_LT(test, ret, 0);
 }
 
+/*
+ * Test that if:
+ * - We have an HDMI connector supporting RGB only
+ * - The chosen mode has a TMDS character rate higher than the display
+ *   supports in RGB/12bpc
+ * - The chosen mode has a TMDS character rate lower than the display
+ *   supports in RGB/10bpc.
+ *
+ * Then we will pick the latter, and the computed TMDS character rate
+ * will be equal to 1.25 times the mode pixel clock.
+ */
+static void drm_test_check_max_tmds_rate_bpc_fallback(struct kunit *test)
+{
+   struct drm_atomic_helper_connector_hdmi_priv *priv;
+   struct drm_modeset_acquire_ctx *ctx;
+   struct drm_connector_state *conn_state;
+   struct drm_display_info *info;
+   struct drm_display_mode *preferred;
+   unsigned long long rate;
+   struct drm_connector *conn;
+   struct drm_device *drm;
+   struct drm_crtc *crtc;
+   int ret;
+
+   priv = drm_atomic_helper_connector_hdmi_init(test,
+BIT(HDMI_COLORSPACE_RGB),
+12);
+   KUNIT_ASSERT_NOT_NULL(test, priv);
+
+   conn = >connector;
+   ret = set_connector_edid(test, conn,
+test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz,
+
ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz));
+   KUNIT_ASSERT_EQ(test, ret, 0);
+
+   info = >display_info;
+   KUNIT_ASSERT_TRUE(test, info->is_hdmi);
+   KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
+
+   

[PATCH v15 07/29] drm/connector: hdmi: Add support for output format

2024-05-27 Thread Maxime Ripard
Just like BPC, we'll add support for automatic selection of the output
format for HDMI connectors.

Let's add the needed defaults and fields for now.

Reviewed-by: Dave Stevenson 
Reviewed-by: Dmitry Baryshkov 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/display/drm_hdmi_state_helper.c|  3 ++-
 drivers/gpu/drm/drm_atomic.c   |  2 ++
 drivers/gpu/drm/drm_connector.c| 31 ++
 drivers/gpu/drm/tests/drm_connector_test.c |  9 +++
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 22 +++
 include/drm/drm_connector.h| 20 ++
 6 files changed, 81 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c 
b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 82293d93b5f8..f6cd0612ea2c 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -43,11 +43,12 @@ int drm_atomic_helper_connector_hdmi_check(struct 
drm_connector *connector,
struct drm_connector_state *old_conn_state =
drm_atomic_get_old_connector_state(state, connector);
struct drm_connector_state *new_conn_state =
drm_atomic_get_new_connector_state(state, connector);
 
-   if (old_conn_state->hdmi.output_bpc != new_conn_state->hdmi.output_bpc) 
{
+   if (old_conn_state->hdmi.output_bpc != new_conn_state->hdmi.output_bpc 
||
+   old_conn_state->hdmi.output_format != 
new_conn_state->hdmi.output_format) {
struct drm_crtc *crtc = new_conn_state->crtc;
struct drm_crtc_state *crtc_state;
 
crtc_state = drm_atomic_get_crtc_state(state, crtc);
if (IS_ERR(crtc_state))
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 4e11cfb4518b..8730137baa86 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1144,10 +1144,12 @@ static void drm_atomic_connector_print_state(struct 
drm_printer *p,
drm_printf(p, "\tcolorspace=%s\n", 
drm_get_colorspace_name(state->colorspace));
 
if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) {
drm_printf(p, "\toutput_bpc=%u\n", state->hdmi.output_bpc);
+   drm_printf(p, "\toutput_format=%s\n",
+  
drm_hdmi_connector_get_output_format_name(state->hdmi.output_format));
}
 
if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
if (state->writeback_job && state->writeback_job->fb)
drm_printf(p, "\tfb=%d\n", 
state->writeback_job->fb->base.id);
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index da51a2bcb978..b629c8e990f4 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -457,10 +457,11 @@ EXPORT_SYMBOL(drmm_connector_init);
  * @dev: DRM device
  * @connector: A pointer to the HDMI connector to init
  * @funcs: callbacks for this connector
  * @connector_type: user visible type of the connector
  * @ddc: optional pointer to the associated ddc adapter
+ * @supported_formats: Bitmask of @hdmi_colorspace listing supported output 
formats
  * @max_bpc: Maximum bits per char the HDMI connector supports
  *
  * Initialises a preallocated HDMI connector. Connectors can be
  * subclassed as part of driver connector objects.
  *
@@ -475,25 +476,31 @@ EXPORT_SYMBOL(drmm_connector_init);
 int drmm_connector_hdmi_init(struct drm_device *dev,
 struct drm_connector *connector,
 const struct drm_connector_funcs *funcs,
 int connector_type,
 struct i2c_adapter *ddc,
+unsigned long supported_formats,
 unsigned int max_bpc)
 {
int ret;
 
if (!(connector_type == DRM_MODE_CONNECTOR_HDMIA ||
  connector_type == DRM_MODE_CONNECTOR_HDMIB))
return -EINVAL;
 
+   if (!supported_formats || !(supported_formats & 
BIT(HDMI_COLORSPACE_RGB)))
+   return -EINVAL;
+
if (!(max_bpc == 8 || max_bpc == 10 || max_bpc == 12))
return -EINVAL;
 
ret = drmm_connector_init(dev, connector, funcs, connector_type, ddc);
if (ret)
return ret;
 
+   connector->hdmi.supported_formats = supported_formats;
+
/*
 * drm_connector_attach_max_bpc_property() requires the
 * connector to have a state.
 */
if (connector->funcs->reset)
@@ -1199,10 +1206,34 @@ static const u32 dp_colorspaces =
BIT(DRM_MODE_COLORIMETRY_SYCC_601) |
BIT(DRM_MODE_COLORIMETRY_OPYCC_601

[PATCH v15 14/29] drm/tests: Add HDMI connector rate filter hook tests

2024-05-27 Thread Maxime Ripard
The previous patch adds a new hook for HDMI connectors to filter out
configurations based on the TMDS character rate. Let's add some tests to
make sure it works as expected.

Reviewed-by: Dave Stevenson 
Reviewed-by: Dmitry Baryshkov 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 65 ++
 1 file changed, 65 insertions(+)

diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c 
b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
index 7f9a48902db4..ead998a691e7 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -113,10 +113,22 @@ static int set_connector_edid(struct kunit *test, struct 
drm_connector *connecto
 }
 
 static const struct drm_connector_hdmi_funcs dummy_connector_hdmi_funcs = {
 };
 
+static enum drm_mode_status
+reject_connector_tmds_char_rate_valid(const struct drm_connector *connector,
+  const struct drm_display_mode *mode,
+  unsigned long long tmds_rate)
+{
+   return MODE_BAD;
+}
+
+static const struct drm_connector_hdmi_funcs reject_connector_hdmi_funcs = {
+   .tmds_char_rate_valid   = reject_connector_tmds_char_rate_valid,
+};
+
 static int dummy_connector_get_modes(struct drm_connector *connector)
 {
struct drm_atomic_helper_connector_hdmi_priv *priv =
connector_to_priv(connector);
const struct drm_edid *edid;
@@ -491,11 +503,64 @@ static void 
drm_test_check_tmds_char_rate_rgb_12bpc(struct kunit *test)
KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_bpc, 12);
KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, 
HDMI_COLORSPACE_RGB);
KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock 
* 1500);
 }
 
+/*
+ * Test that if we filter a rate through our hook, it's indeed rejected
+ * by the whole atomic_check logic.
+ *
+ * We do so by first doing a commit on the pipeline to make sure that it
+ * works, change the HDMI helpers pointer, and then try the same commit
+ * again to see if it fails as it should.
+ */
+static void drm_test_check_hdmi_funcs_reject_rate(struct kunit *test)
+{
+   struct drm_atomic_helper_connector_hdmi_priv *priv;
+   struct drm_modeset_acquire_ctx *ctx;
+   struct drm_atomic_state *state;
+   struct drm_display_mode *preferred;
+   struct drm_crtc_state *crtc_state;
+   struct drm_connector *conn;
+   struct drm_device *drm;
+   struct drm_crtc *crtc;
+   int ret;
+
+   priv = drm_atomic_helper_connector_hdmi_init(test,
+BIT(HDMI_COLORSPACE_RGB),
+8);
+   KUNIT_ASSERT_NOT_NULL(test, priv);
+
+   ctx = drm_kunit_helper_acquire_ctx_alloc(test);
+   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+
+   conn = >connector;
+   preferred = find_preferred_mode(conn);
+   KUNIT_ASSERT_NOT_NULL(test, preferred);
+
+   drm = >drm;
+   crtc = priv->crtc;
+   ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
+   KUNIT_ASSERT_EQ(test, ret, 0);
+
+   /* You shouldn't be doing that at home. */
+   conn->hdmi.funcs = _connector_hdmi_funcs;
+
+   state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
+   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+   crtc_state = drm_atomic_get_crtc_state(state, crtc);
+   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+   crtc_state->connectors_changed = true;
+
+   ret = drm_atomic_check_only(state);
+   KUNIT_EXPECT_LT(test, ret, 0);
+}
+
 static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = {
+   KUNIT_CASE(drm_test_check_hdmi_funcs_reject_rate),
KUNIT_CASE(drm_test_check_output_bpc_crtc_mode_changed),
KUNIT_CASE(drm_test_check_output_bpc_crtc_mode_not_changed),
KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_8bpc),
KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_10bpc),
KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_12bpc),

-- 
2.45.0



[PATCH v15 12/29] drm/tests: Add TDMS character rate connector state tests

2024-05-27 Thread Maxime Ripard
The previous patch stores in the connector state the expected TMDS
character rate matching the configuration of the HDMI connector. Let's
add a few tests to make sure it works as expected.

Reviewed-by: Dave Stevenson 
Reviewed-by: Dmitry Baryshkov 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 166 
 drivers/gpu/drm/tests/drm_kunit_edid.h | 216 +
 2 files changed, 382 insertions(+)

diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c 
b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
index 4f46a70a5017..8ff53ee54e97 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -347,13 +347,156 @@ static void 
drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit *test)
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
KUNIT_EXPECT_FALSE(test, crtc_state->mode_changed);
 }
 
+/*
+ * Test that when doing a commit which would use RGB 8bpc, the TMDS
+ * clock rate stored in the connector state is equal to the mode clock
+ */
+static void drm_test_check_tmds_char_rate_rgb_8bpc(struct kunit *test)
+{
+   struct drm_atomic_helper_connector_hdmi_priv *priv;
+   struct drm_modeset_acquire_ctx *ctx;
+   struct drm_connector_state *conn_state;
+   struct drm_display_mode *preferred;
+   struct drm_connector *conn;
+   struct drm_device *drm;
+   struct drm_crtc *crtc;
+   int ret;
+
+   priv = drm_atomic_helper_connector_hdmi_init(test,
+BIT(HDMI_COLORSPACE_RGB),
+8);
+   KUNIT_ASSERT_NOT_NULL(test, priv);
+
+   conn = >connector;
+   ret = set_connector_edid(test, conn,
+test_edid_hdmi_1080p_rgb_max_200mhz,
+
ARRAY_SIZE(test_edid_hdmi_1080p_rgb_max_200mhz));
+   KUNIT_ASSERT_EQ(test, ret, 0);
+
+   ctx = drm_kunit_helper_acquire_ctx_alloc(test);
+   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+
+   preferred = find_preferred_mode(conn);
+   KUNIT_ASSERT_NOT_NULL(test, preferred);
+   KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
+
+   drm = >drm;
+   crtc = priv->crtc;
+   ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
+   KUNIT_ASSERT_EQ(test, ret, 0);
+
+   conn_state = conn->state;
+   KUNIT_ASSERT_NOT_NULL(test, conn_state);
+
+   KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_bpc, 8);
+   KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, 
HDMI_COLORSPACE_RGB);
+   KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock 
* 1000);
+}
+
+/*
+ * Test that when doing a commit which would use RGB 10bpc, the TMDS
+ * clock rate stored in the connector state is equal to 1.25 times the
+ * mode pixel clock
+ */
+static void drm_test_check_tmds_char_rate_rgb_10bpc(struct kunit *test)
+{
+   struct drm_atomic_helper_connector_hdmi_priv *priv;
+   struct drm_modeset_acquire_ctx *ctx;
+   struct drm_connector_state *conn_state;
+   struct drm_display_mode *preferred;
+   struct drm_connector *conn;
+   struct drm_device *drm;
+   struct drm_crtc *crtc;
+   int ret;
+
+   priv = drm_atomic_helper_connector_hdmi_init(test,
+BIT(HDMI_COLORSPACE_RGB),
+10);
+   KUNIT_ASSERT_NOT_NULL(test, priv);
+
+   conn = >connector;
+   ret = set_connector_edid(test, conn,
+test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz,
+
ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz));
+   KUNIT_ASSERT_EQ(test, ret, 0);
+
+   ctx = drm_kunit_helper_acquire_ctx_alloc(test);
+   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+
+   preferred = find_preferred_mode(conn);
+   KUNIT_ASSERT_NOT_NULL(test, preferred);
+   KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
+
+   drm = >drm;
+   crtc = priv->crtc;
+   ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
+   KUNIT_ASSERT_EQ(test, ret, 0);
+
+   conn_state = conn->state;
+   KUNIT_ASSERT_NOT_NULL(test, conn_state);
+
+   KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_bpc, 10);
+   KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, 
HDMI_COLORSPACE_RGB);
+   KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock 
* 1250);
+}
+
+/*
+ * Test that when doing a commit which would use RGB 12bpc, the TMDS
+ * clock rate stored in the connector state is equal to 1.5 times the
+ * mode pixel clock
+ */
+static void drm_test_che

[PATCH v15 15/29] drm/connector: hdmi: Compute bpc and format automatically

2024-05-27 Thread Maxime Ripard
Now that we have all the infrastructure needed, we can add some code
that will, for a given connector state and mode, compute the best output
format and bpc.

The algorithm is equivalent to the one already found in i915 and vc4.

Cc: Ville Syrjälä 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/display/drm_hdmi_state_helper.c| 217 -
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c |  25 ++-
 2 files changed, 230 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c 
b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 063421835dba..1623b96cd97c 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -1,9 +1,11 @@
 // SPDX-License-Identifier: MIT
 
 #include 
 #include 
+#include 
+#include 
 
 #include 
 #include 
 
 /**
@@ -46,10 +48,130 @@ connector_state_get_mode(const struct drm_connector_state 
*conn_state)
return NULL;
 
return _state->mode;
 }
 
+static bool
+sink_supports_format_bpc(const struct drm_connector *connector,
+const struct drm_display_info *info,
+const struct drm_display_mode *mode,
+unsigned int format, unsigned int bpc)
+{
+   struct drm_device *dev = connector->dev;
+   u8 vic = drm_match_cea_mode(mode);
+
+   /*
+* CTA-861-F, section 5.4 - Color Coding & Quantization states
+* that the bpc must be 8, 10, 12 or 16 except for the default
+* 640x480 VIC1 where the value must be 8.
+*
+* The definition of default here is ambiguous but the spec
+* refers to VIC1 being the default timing in several occasions
+* so our understanding is that for the default timing (ie,
+* VIC1), the bpc must be 8.
+*/
+   if (vic == 1 && bpc != 8) {
+   drm_dbg_kms(dev, "VIC1 requires a bpc of 8, got %u\n", bpc);
+   return false;
+   }
+
+   if (!info->is_hdmi &&
+   (format != HDMI_COLORSPACE_RGB || bpc != 8)) {
+   drm_dbg_kms(dev, "DVI Monitors require an RGB output at 8 
bpc\n");
+   return false;
+   }
+
+   if (!(connector->hdmi.supported_formats & BIT(format))) {
+   drm_dbg_kms(dev, "%s format unsupported by the connector.\n",
+   drm_hdmi_connector_get_output_format_name(format));
+   return false;
+   }
+
+   switch (format) {
+   case HDMI_COLORSPACE_RGB:
+   drm_dbg_kms(dev, "RGB Format, checking the constraints.\n");
+
+   /*
+* In some cases, like when the EDID readout fails, or
+* is not an HDMI compliant EDID for some reason, the
+* color_formats field will be blank and not report any
+* format supported. In such a case, assume that RGB is
+* supported so we can keep things going and light up
+* the display.
+*/
+   if (!(info->color_formats & DRM_COLOR_FORMAT_RGB444))
+   drm_warn(dev, "HDMI Sink doesn't support RGB, 
something's wrong.\n");
+
+   if (bpc == 10 && !(info->edid_hdmi_rgb444_dc_modes & 
DRM_EDID_HDMI_DC_30)) {
+   drm_dbg_kms(dev, "10 BPC but sink doesn't support Deep 
Color 30.\n");
+   return false;
+   }
+
+   if (bpc == 12 && !(info->edid_hdmi_rgb444_dc_modes & 
DRM_EDID_HDMI_DC_36)) {
+   drm_dbg_kms(dev, "12 BPC but sink doesn't support Deep 
Color 36.\n");
+   return false;
+   }
+
+   drm_dbg_kms(dev, "RGB format supported in that 
configuration.\n");
+
+   return true;
+
+   case HDMI_COLORSPACE_YUV420:
+   /* TODO: YUV420 is unsupported at the moment. */
+   drm_dbg_kms(dev, "YUV420 format isn't supported yet.\n");
+   return false;
+
+   case HDMI_COLORSPACE_YUV422:
+   drm_dbg_kms(dev, "YUV422 format, checking the constraints.\n");
+
+   if (!(info->color_formats & DRM_COLOR_FORMAT_YCBCR422)) {
+   drm_dbg_kms(dev, "Sink doesn't support YUV422.\n");
+   return false;
+   }
+
+   if (bpc > 12) {
+   drm_dbg_kms(dev, "YUV422 only supports 12 bpc or 
lower.\n");
+   return false;
+   }
+
+   /*
+* HDMI Spec 1.3 - Section 6.5 Pixel Encodings and Color Depth
+* states that Deep Color is not relevant for YUV422 so we
+* don't need to check the Deep Colo

[PATCH v15 08/29] drm/tests: Add output formats tests

2024-05-27 Thread Maxime Ripard
Now that we track the HDMI output format as part of the connector state,
let's add a few tests to make sure it works as expected.

Reviewed-by: Dave Stevenson 
Reviewed-by: Dmitry Baryshkov 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/tests/drm_connector_test.c | 99 +-
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 32 +++
 2 files changed, 130 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/tests/drm_connector_test.c 
b/drivers/gpu/drm/tests/drm_connector_test.c
index 37e6efd46d7e..250348ddfa70 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -361,10 +361,46 @@ static void drm_test_connector_hdmi_init_bpc_12(struct 
kunit *test)
prop = priv->drm.mode_config.hdr_output_metadata_property;
KUNIT_ASSERT_NOT_NULL(test, prop);
KUNIT_EXPECT_NOT_NULL(test, drm_mode_obj_find_prop_id(>base, 
prop->base.id));
 }
 
+/*
+ * Test that the registration of an HDMI connector with no supported
+ * format fails.
+ */
+static void drm_test_connector_hdmi_init_formats_empty(struct kunit *test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   int ret;
+
+   ret = drmm_connector_hdmi_init(>drm, >connector,
+  _funcs,
+  DRM_MODE_CONNECTOR_HDMIA,
+  >ddc,
+  0,
+  8);
+   KUNIT_EXPECT_LT(test, ret, 0);
+}
+
+/*
+ * Test that the registration of an HDMI connector not listing RGB as a
+ * supported format fails.
+ */
+static void drm_test_connector_hdmi_init_formats_no_rgb(struct kunit *test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   int ret;
+
+   ret = drmm_connector_hdmi_init(>drm, >connector,
+  _funcs,
+  DRM_MODE_CONNECTOR_HDMIA,
+  >ddc,
+  BIT(HDMI_COLORSPACE_YUV422),
+  8);
+   KUNIT_EXPECT_LT(test, ret, 0);
+}
+
 /*
  * Test that the registration of an HDMI connector with an HDMI
  * connector type succeeds.
  */
 static void drm_test_connector_hdmi_init_type_valid(struct kunit *test)
@@ -446,10 +482,12 @@ static struct kunit_case drmm_connector_hdmi_init_tests[] 
= {
KUNIT_CASE(drm_test_connector_hdmi_init_bpc_8),
KUNIT_CASE(drm_test_connector_hdmi_init_bpc_10),
KUNIT_CASE(drm_test_connector_hdmi_init_bpc_12),
KUNIT_CASE(drm_test_connector_hdmi_init_bpc_invalid),
KUNIT_CASE(drm_test_connector_hdmi_init_bpc_null),
+   KUNIT_CASE(drm_test_connector_hdmi_init_formats_empty),
+   KUNIT_CASE(drm_test_connector_hdmi_init_formats_no_rgb),
KUNIT_CASE(drm_test_connector_hdmi_init_null_ddc),
KUNIT_CASE_PARAM(drm_test_connector_hdmi_init_type_valid,
 drm_connector_hdmi_init_type_valid_gen_params),
KUNIT_CASE_PARAM(drm_test_connector_hdmi_init_type_invalid,
 drm_connector_hdmi_init_type_invalid_gen_params),
@@ -523,13 +561,72 @@ static struct kunit_case 
drm_get_tv_mode_from_name_tests[] = {
 static struct kunit_suite drm_get_tv_mode_from_name_test_suite = {
.name = "drm_get_tv_mode_from_name",
.test_cases = drm_get_tv_mode_from_name_tests,
 };
 
+struct drm_hdmi_connector_get_output_format_name_test {
+   unsigned int kind;
+   const char *expected_name;
+};
+
+#define OUTPUT_FORMAT_TEST(_kind, _name)   \
+   {   \
+   .kind = _kind,  \
+   .expected_name = _name, \
+   }
+
+static void drm_test_drm_hdmi_connector_get_output_format_name(struct kunit 
*test)
+{
+   const struct drm_hdmi_connector_get_output_format_name_test *params =
+   test->param_value;
+
+   KUNIT_EXPECT_STREQ(test,
+  
drm_hdmi_connector_get_output_format_name(params->kind),
+  params->expected_name);
+}
+
+static const
+struct drm_hdmi_connector_get_output_format_name_test
+drm_hdmi_connector_get_output_format_name_valid_tests[] = {
+   OUTPUT_FORMAT_TEST(HDMI_COLORSPACE_RGB, "RGB"),
+   OUTPUT_FORMAT_TEST(HDMI_COLORSPACE_YUV420, "YUV 4:2:0"),
+   OUTPUT_FORMAT_TEST(HDMI_COLORSPACE_YUV422, "YUV 4:2:2"),
+   OUTPUT_FORMAT_TEST(HDMI_COLORSPACE_YUV444, "YUV 4:4:4"),
+};
+
+static void
+drm_hdmi_connector_get_output_format_name_valid_desc(const struct 
drm_hdmi_connector_get_output_format_name_test *t,
+char *desc)
+{
+   sprintf(desc, "%s", t->expected_name);
+}
+
+KUNIT_ARRAY_PARAM(drm_hdmi_connec

[PATCH v15 09/29] drm/display: hdmi: Add HDMI compute clock helper

2024-05-27 Thread Maxime Ripard
A lot of HDMI drivers have some variation of the formula to calculate
the TMDS character rate from a mode, but few of them actually take all
parameters into account.

Let's create a helper to provide that rate taking all parameters into
account.

Reviewed-by: Dave Stevenson 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/display/drm_hdmi_helper.c | 61 +++
 include/drm/display/drm_hdmi_helper.h |  4 ++
 2 files changed, 65 insertions(+)

diff --git a/drivers/gpu/drm/display/drm_hdmi_helper.c 
b/drivers/gpu/drm/display/drm_hdmi_helper.c
index faf5e9efa7d3..74dd4d01dd9b 100644
--- a/drivers/gpu/drm/display/drm_hdmi_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_helper.c
@@ -193,5 +193,66 @@ void drm_hdmi_avi_infoframe_content_type(struct 
hdmi_avi_infoframe *frame,
}
 
frame->itc = conn_state->content_type != DRM_MODE_CONTENT_TYPE_NO_DATA;
 }
 EXPORT_SYMBOL(drm_hdmi_avi_infoframe_content_type);
+
+/**
+ * drm_hdmi_compute_mode_clock() - Computes the TMDS Character Rate
+ * @mode: Display mode to compute the clock for
+ * @bpc: Bits per character
+ * @fmt: Output Pixel Format used
+ *
+ * Returns the TMDS Character Rate for a given mode, bpc count and output 
format.
+ *
+ * RETURNS:
+ * The TMDS Character Rate, in Hertz, or 0 on error.
+ */
+unsigned long long
+drm_hdmi_compute_mode_clock(const struct drm_display_mode *mode,
+   unsigned int bpc, enum hdmi_colorspace fmt)
+{
+   unsigned long long clock = mode->clock * 1000ULL;
+   unsigned int vic = drm_match_cea_mode(mode);
+
+   /*
+* CTA-861-G Spec, section 5.4 - Color Coding and Quantization
+* mandates that VIC 1 always uses 8 bpc.
+*/
+   if (vic == 1 && bpc != 8)
+   return 0;
+
+   if (fmt == HDMI_COLORSPACE_YUV422) {
+   /*
+* HDMI 1.0 Spec, section 6.5 - Pixel Encoding states that
+* YUV422 sends 24 bits over three channels, with Cb and Cr
+* components being sent on odd and even pixels, respectively.
+*
+* If fewer than 12 bpc are sent, data are left justified.
+*/
+   if (bpc > 12)
+   return 0;
+
+   /*
+* HDMI 1.0 Spec, section 6.5 - Pixel Encoding
+* specifies that YUV422 sends two 12-bits components over
+* three TMDS channels per pixel clock, which is equivalent to
+* three 8-bits components over three channels used by RGB as
+* far as the clock rate goes.
+*/
+   bpc = 8;
+   }
+
+   /*
+* HDMI 2.0 Spec, Section 7.1 - YCbCr 4:2:0 Pixel Encoding
+* specifies that YUV420 encoding is carried at a TMDS Character Rate
+* equal to half the pixel clock rate.
+*/
+   if (fmt == HDMI_COLORSPACE_YUV420)
+   clock = clock / 2;
+
+   if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+   clock = clock * 2;
+
+   return DIV_ROUND_CLOSEST_ULL(clock * bpc, 8);
+}
+EXPORT_SYMBOL(drm_hdmi_compute_mode_clock);
diff --git a/include/drm/display/drm_hdmi_helper.h 
b/include/drm/display/drm_hdmi_helper.h
index 76d234826e22..57e3b18c15ec 100644
--- a/include/drm/display/drm_hdmi_helper.h
+++ b/include/drm/display/drm_hdmi_helper.h
@@ -22,6 +22,10 @@ drm_hdmi_infoframe_set_hdr_metadata(struct 
hdmi_drm_infoframe *frame,
const struct drm_connector_state 
*conn_state);
 
 void drm_hdmi_avi_infoframe_content_type(struct hdmi_avi_infoframe *frame,
 const struct drm_connector_state 
*conn_state);
 
+unsigned long long
+drm_hdmi_compute_mode_clock(const struct drm_display_mode *mode,
+   unsigned int bpc, enum hdmi_colorspace fmt);
+
 #endif

-- 
2.45.0



[PATCH v15 11/29] drm/connector: hdmi: Calculate TMDS character rate

2024-05-27 Thread Maxime Ripard
Most HDMI drivers have some code to calculate the TMDS character rate,
usually to adjust an internal clock to match what the mode requires.

Since the TMDS character rates mostly depends on the resolution, whether
we need to repeat pixels or not, the bpc count and the format, we can
now derive it from the HDMI connector state that stores all those infos
and remove the duplication from drivers.

Reviewed-by: Dave Stevenson 
Reviewed-by: Dmitry Baryshkov 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/display/drm_hdmi_state_helper.c| 67 ++
 drivers/gpu/drm/drm_atomic.c   |  1 +
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c |  3 +
 include/drm/drm_connector.h|  5 ++
 4 files changed, 76 insertions(+)

diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c 
b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index f6cd0612ea2c..08630561d864 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -1,10 +1,11 @@
 // SPDX-License-Identifier: MIT
 
 #include 
 #include 
 
+#include 
 #include 
 
 /**
  * __drm_atomic_helper_connector_hdmi_reset() - Initializes all HDMI 
@drm_connector_state resources
  * @connector: DRM connector
@@ -23,10 +24,67 @@ void __drm_atomic_helper_connector_hdmi_reset(struct 
drm_connector *connector,
new_conn_state->max_bpc = max_bpc;
new_conn_state->max_requested_bpc = max_bpc;
 }
 EXPORT_SYMBOL(__drm_atomic_helper_connector_hdmi_reset);
 
+static const struct drm_display_mode *
+connector_state_get_mode(const struct drm_connector_state *conn_state)
+{
+   struct drm_atomic_state *state;
+   struct drm_crtc_state *crtc_state;
+   struct drm_crtc *crtc;
+
+   state = conn_state->state;
+   if (!state)
+   return NULL;
+
+   crtc = conn_state->crtc;
+   if (!crtc)
+   return NULL;
+
+   crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+   if (!crtc_state)
+   return NULL;
+
+   return _state->mode;
+}
+
+static enum drm_mode_status
+hdmi_clock_valid(const struct drm_connector *connector,
+const struct drm_display_mode *mode,
+unsigned long long clock)
+{
+   const struct drm_display_info *info = >display_info;
+
+   if (info->max_tmds_clock && clock > info->max_tmds_clock * 1000)
+   return MODE_CLOCK_HIGH;
+
+   return MODE_OK;
+}
+
+static int
+hdmi_compute_clock(const struct drm_connector *connector,
+  struct drm_connector_state *conn_state,
+  const struct drm_display_mode *mode,
+  unsigned int bpc, enum hdmi_colorspace fmt)
+{
+   enum drm_mode_status status;
+   unsigned long long clock;
+
+   clock = drm_hdmi_compute_mode_clock(mode, bpc, fmt);
+   if (!clock)
+   return -EINVAL;
+
+   status = hdmi_clock_valid(connector, mode, clock);
+   if (status != MODE_OK)
+   return -EINVAL;
+
+   conn_state->hdmi.tmds_char_rate = clock;
+
+   return 0;
+}
+
 /**
  * drm_atomic_helper_connector_hdmi_check() - Helper to check HDMI connector 
atomic state
  * @connector: DRM Connector
  * @state: the DRM State object
  *
@@ -42,10 +100,19 @@ int drm_atomic_helper_connector_hdmi_check(struct 
drm_connector *connector,
 {
struct drm_connector_state *old_conn_state =
drm_atomic_get_old_connector_state(state, connector);
struct drm_connector_state *new_conn_state =
drm_atomic_get_new_connector_state(state, connector);
+   const struct drm_display_mode *mode =
+   connector_state_get_mode(new_conn_state);
+   int ret;
+
+   ret = hdmi_compute_clock(connector, new_conn_state, mode,
+new_conn_state->hdmi.output_bpc,
+new_conn_state->hdmi.output_format);
+   if (ret)
+   return ret;
 
if (old_conn_state->hdmi.output_bpc != new_conn_state->hdmi.output_bpc 
||
old_conn_state->hdmi.output_format != 
new_conn_state->hdmi.output_format) {
struct drm_crtc *crtc = new_conn_state->crtc;
struct drm_crtc_state *crtc_state;
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 8730137baa86..26f9e525c0a0 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1146,10 +1146,11 @@ static void drm_atomic_connector_print_state(struct 
drm_printer *p,
if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) {
drm_printf(p, "\toutput_bpc=%u\n", state->hdmi.output_bpc);
drm_printf(p, "\toutput_format=%s\n",
   
drm_hdmi_connector_get_output_format_

[PATCH v15 06/29] drm/tests: Add output bpc tests

2024-05-27 Thread Maxime Ripard
Now that we're tracking the output bpc count in the connector state,
let's add a few tests to make sure it works as expected.

Reviewed-by: Dave Stevenson 
Reviewed-by: Dmitry Baryshkov 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/Kconfig|   1 +
 drivers/gpu/drm/tests/Makefile |   1 +
 drivers/gpu/drm/tests/drm_connector_test.c | 155 
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 438 +
 drivers/gpu/drm/tests/drm_kunit_edid.h | 106 +
 5 files changed, 701 insertions(+)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 026444eeb5c6..9703429de6b9 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -77,10 +77,11 @@ config DRM_KUNIT_TEST_HELPERS
 config DRM_KUNIT_TEST
tristate "KUnit tests for DRM" if !KUNIT_ALL_TESTS
depends on DRM && KUNIT && MMU
select DRM_BUDDY
select DRM_DISPLAY_DP_HELPER
+   select DRM_DISPLAY_HDMI_STATE_HELPER
select DRM_DISPLAY_HELPER
select DRM_EXEC
select DRM_EXPORT_FOR_TESTS if m
select DRM_GEM_SHMEM_HELPER
select DRM_KUNIT_TEST_HELPERS
diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile
index d6183b3d7688..56dab563abd7 100644
--- a/drivers/gpu/drm/tests/Makefile
+++ b/drivers/gpu/drm/tests/Makefile
@@ -12,10 +12,11 @@ obj-$(CONFIG_DRM_KUNIT_TEST) += \
drm_exec_test.o \
drm_format_helper_test.o \
drm_format_test.o \
drm_framebuffer_test.o \
drm_gem_shmem_test.o \
+   drm_hdmi_state_helper_test.o \
drm_managed_test.o \
drm_mm_test.o \
drm_modes_test.o \
drm_plane_helper_test.o \
drm_probe_helper_test.o \
diff --git a/drivers/gpu/drm/tests/drm_connector_test.c 
b/drivers/gpu/drm/tests/drm_connector_test.c
index 2661eb64a5cd..9465fa33f3b6 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -10,10 +10,12 @@
 #include 
 #include 
 
 #include 
 
+#include "../drm_crtc_internal.h"
+
 struct drm_connector_init_priv {
struct drm_device drm;
struct drm_connector connector;
struct i2c_adapter ddc;
 };
@@ -204,10 +206,158 @@ static void drm_test_connector_hdmi_init_null_ddc(struct 
kunit *test)
   NULL,
   8);
KUNIT_EXPECT_EQ(test, ret, 0);
 }
 
+/*
+ * Test that the registration of a connector with an invalid maximum bpc
+ * count fails.
+ */
+static void drm_test_connector_hdmi_init_bpc_invalid(struct kunit *test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   int ret;
+
+   ret = drmm_connector_hdmi_init(>drm, >connector,
+  _funcs,
+  DRM_MODE_CONNECTOR_HDMIA,
+  >ddc,
+  9);
+   KUNIT_EXPECT_LT(test, ret, 0);
+}
+
+/*
+ * Test that the registration of a connector with a null maximum bpc
+ * count fails.
+ */
+static void drm_test_connector_hdmi_init_bpc_null(struct kunit *test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   int ret;
+
+   ret = drmm_connector_hdmi_init(>drm, >connector,
+  _funcs,
+  DRM_MODE_CONNECTOR_HDMIA,
+  >ddc,
+  0);
+   KUNIT_EXPECT_LT(test, ret, 0);
+}
+
+/*
+ * Test that the registration of a connector with a maximum bpc count of
+ * 8 succeeds, registers the max bpc property, but doesn't register the
+ * HDR output metadata one.
+ */
+static void drm_test_connector_hdmi_init_bpc_8(struct kunit *test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   struct drm_connector_state *state;
+   struct drm_connector *connector = >connector;
+   struct drm_property *prop;
+   uint64_t val;
+   int ret;
+
+   ret = drmm_connector_hdmi_init(>drm, connector,
+  _funcs,
+  DRM_MODE_CONNECTOR_HDMIA,
+  >ddc,
+  8);
+   KUNIT_EXPECT_EQ(test, ret, 0);
+
+   prop = connector->max_bpc_property;
+   KUNIT_ASSERT_NOT_NULL(test, prop);
+   KUNIT_EXPECT_NOT_NULL(test, drm_mode_obj_find_prop_id(>base, 
prop->base.id));
+
+   ret = drm_object_property_get_default_value(>base, prop, 
);
+   KUNIT_EXPECT_EQ(test, ret, 0);
+   KUNIT_EXPECT_EQ(test, val, 8);
+
+   state = connector->state;
+   KUNIT_EXPECT_EQ(test, state->max_bpc, 8);
+   KUNIT_EXPECT_EQ(test, state->max_requested_bpc, 8);
+
+   prop = priv->drm.mode_config.hdr_out

[PATCH v15 02/29] drm/tests: connector: Add tests for drmm_connector_hdmi_init

2024-05-27 Thread Maxime Ripard
We just introduced a new initialization function for our connectors, so
let's build a kunit test suite for it as well.

Reviewed-by: Dave Stevenson 
Reviewed-by: Dmitry Baryshkov 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/tests/drm_connector_test.c | 123 +
 1 file changed, 123 insertions(+)

diff --git a/drivers/gpu/drm/tests/drm_connector_test.c 
b/drivers/gpu/drm/tests/drm_connector_test.c
index 44f82ed2a958..261d4109946d 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -170,10 +170,132 @@ static struct kunit_suite drmm_connector_init_test_suite 
= {
.name = "drmm_connector_init",
.init = drm_test_connector_init,
.test_cases = drmm_connector_init_tests,
 };
 
+/*
+ * Test that the registration of a bog standard connector works as
+ * expected and doesn't report any error.
+ */
+static void drm_test_connector_hdmi_init_valid(struct kunit *test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   int ret;
+
+   ret = drmm_connector_hdmi_init(>drm, >connector,
+  _funcs,
+  DRM_MODE_CONNECTOR_HDMIA,
+  >ddc);
+   KUNIT_EXPECT_EQ(test, ret, 0);
+}
+
+/*
+ * Test that the registration of a connector without a DDC adapter
+ * doesn't report any error.
+ */
+static void drm_test_connector_hdmi_init_null_ddc(struct kunit *test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   int ret;
+
+   ret = drmm_connector_hdmi_init(>drm, >connector,
+  _funcs,
+  DRM_MODE_CONNECTOR_HDMIA,
+  NULL);
+   KUNIT_EXPECT_EQ(test, ret, 0);
+}
+
+/*
+ * Test that the registration of an HDMI connector with an HDMI
+ * connector type succeeds.
+ */
+static void drm_test_connector_hdmi_init_type_valid(struct kunit *test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   unsigned int connector_type = *(unsigned int *)test->param_value;
+   int ret;
+
+   ret = drmm_connector_hdmi_init(>drm, >connector,
+  _funcs,
+  connector_type,
+  >ddc);
+   KUNIT_EXPECT_EQ(test, ret, 0);
+}
+
+static const unsigned int drm_connector_hdmi_init_type_valid_tests[] = {
+   DRM_MODE_CONNECTOR_HDMIA,
+   DRM_MODE_CONNECTOR_HDMIB,
+};
+
+static void drm_connector_hdmi_init_type_desc(const unsigned int *type, char 
*desc)
+{
+   sprintf(desc, "%s", drm_get_connector_type_name(*type));
+}
+
+KUNIT_ARRAY_PARAM(drm_connector_hdmi_init_type_valid,
+ drm_connector_hdmi_init_type_valid_tests,
+ drm_connector_hdmi_init_type_desc);
+
+/*
+ * Test that the registration of an HDMI connector with an !HDMI
+ * connector type fails.
+ */
+static void drm_test_connector_hdmi_init_type_invalid(struct kunit *test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   unsigned int connector_type = *(unsigned int *)test->param_value;
+   int ret;
+
+   ret = drmm_connector_hdmi_init(>drm, >connector,
+  _funcs,
+  connector_type,
+  >ddc);
+   KUNIT_EXPECT_LT(test, ret, 0);
+}
+
+static const unsigned int drm_connector_hdmi_init_type_invalid_tests[] = {
+   DRM_MODE_CONNECTOR_Unknown,
+   DRM_MODE_CONNECTOR_VGA,
+   DRM_MODE_CONNECTOR_DVII,
+   DRM_MODE_CONNECTOR_DVID,
+   DRM_MODE_CONNECTOR_DVIA,
+   DRM_MODE_CONNECTOR_Composite,
+   DRM_MODE_CONNECTOR_SVIDEO,
+   DRM_MODE_CONNECTOR_LVDS,
+   DRM_MODE_CONNECTOR_Component,
+   DRM_MODE_CONNECTOR_9PinDIN,
+   DRM_MODE_CONNECTOR_DisplayPort,
+   DRM_MODE_CONNECTOR_TV,
+   DRM_MODE_CONNECTOR_eDP,
+   DRM_MODE_CONNECTOR_VIRTUAL,
+   DRM_MODE_CONNECTOR_DSI,
+   DRM_MODE_CONNECTOR_DPI,
+   DRM_MODE_CONNECTOR_WRITEBACK,
+   DRM_MODE_CONNECTOR_SPI,
+   DRM_MODE_CONNECTOR_USB,
+};
+
+KUNIT_ARRAY_PARAM(drm_connector_hdmi_init_type_invalid,
+ drm_connector_hdmi_init_type_invalid_tests,
+ drm_connector_hdmi_init_type_desc);
+
+static struct kunit_case drmm_connector_hdmi_init_tests[] = {
+   KUNIT_CASE(drm_test_connector_hdmi_init_valid),
+   KUNIT_CASE(drm_test_connector_hdmi_init_null_ddc),
+   KUNIT_CASE_PARAM(drm_test_connector_hdmi_init_type_valid,
+drm_connector_hdmi_init_type_valid_gen_params),
+   KUNIT_CASE_PARAM(drm_test_connector_hdmi_init_type_invalid,
+drm_connector_hdmi_init_type_invalid_gen_params),
+   { }
+};
+
+static struct kunit_suite drmm_connector_hdmi_init_t

[PATCH v15 05/29] drm/mode_object: Export drm_mode_obj_find_prop_id for tests

2024-05-27 Thread Maxime Ripard
We'll need to use drm_mode_obj_find_prop_id() for kunit tests to make
sure a given property has been properly created. Let's export it for
tests only.

Reviewed-by: Dmitry Baryshkov 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/drm_mode_object.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/drm_mode_object.c 
b/drivers/gpu/drm/drm_mode_object.c
index 0e8355063eee..df4cc0e8e263 100644
--- a/drivers/gpu/drm/drm_mode_object.c
+++ b/drivers/gpu/drm/drm_mode_object.c
@@ -476,10 +476,11 @@ struct drm_property *drm_mode_obj_find_prop_id(struct 
drm_mode_object *obj,
if (obj->properties->properties[i]->base.id == prop_id)
return obj->properties->properties[i];
 
return NULL;
 }
+EXPORT_SYMBOL_FOR_TESTS_ONLY(drm_mode_obj_find_prop_id);
 
 static int set_property_legacy(struct drm_mode_object *obj,
   struct drm_property *prop,
   uint64_t prop_value)
 {

-- 
2.45.0



[PATCH v15 03/29] drm/connector: hdmi: Create an HDMI sub-state

2024-05-27 Thread Maxime Ripard
The next features we will need to share across drivers will need to
store some parameters for drivers to use, such as the selected output
format.

Let's create a new connector sub-state dedicated to HDMI controllers,
that will eventually store everything we need.

Reviewed-by: Dave Stevenson 
Reviewed-by: Sui Jingfeng 
Reviewed-by: Dmitry Baryshkov 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/display/Kconfig |  7 +
 drivers/gpu/drm/display/Makefile|  2 ++
 drivers/gpu/drm/display/drm_hdmi_state_helper.c | 41 +
 include/drm/display/drm_hdmi_state_helper.h | 16 ++
 include/drm/drm_connector.h |  7 +
 5 files changed, 73 insertions(+)

diff --git a/drivers/gpu/drm/display/Kconfig b/drivers/gpu/drm/display/Kconfig
index 864a6488bfdf..14114b597ef4 100644
--- a/drivers/gpu/drm/display/Kconfig
+++ b/drivers/gpu/drm/display/Kconfig
@@ -68,5 +68,12 @@ config DRM_DISPLAY_HDCP_HELPER
 config DRM_DISPLAY_HDMI_HELPER
bool
depends on DRM_DISPLAY_HELPER
help
  DRM display helpers for HDMI.
+
+config DRM_DISPLAY_HDMI_STATE_HELPER
+   bool
+   depends on DRM_DISPLAY_HELPER
+   depends on DRM_DISPLAY_HDMI_HELPER
+   help
+ DRM KMS state helpers for HDMI.
diff --git a/drivers/gpu/drm/display/Makefile b/drivers/gpu/drm/display/Makefile
index 17d2cc73ff56..629df2f4d322 100644
--- a/drivers/gpu/drm/display/Makefile
+++ b/drivers/gpu/drm/display/Makefile
@@ -12,9 +12,11 @@ drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_TUNNEL) += \
drm_dp_tunnel.o
 drm_display_helper-$(CONFIG_DRM_DISPLAY_HDCP_HELPER) += drm_hdcp_helper.o
 drm_display_helper-$(CONFIG_DRM_DISPLAY_HDMI_HELPER) += \
drm_hdmi_helper.o \
drm_scdc_helper.o
+drm_display_helper-$(CONFIG_DRM_DISPLAY_HDMI_STATE_HELPER) += \
+   drm_hdmi_state_helper.o
 drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_AUX_CHARDEV) += drm_dp_aux_dev.o
 drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_AUX_CEC) += drm_dp_cec.o
 
 obj-$(CONFIG_DRM_DISPLAY_HELPER) += drm_display_helper.o
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c 
b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
new file mode 100644
index ..1e92c1108d23
--- /dev/null
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: MIT
+
+#include 
+#include 
+
+#include 
+
+/**
+ * __drm_atomic_helper_connector_hdmi_reset() - Initializes all HDMI 
@drm_connector_state resources
+ * @connector: DRM connector
+ * @new_conn_state: connector state to reset
+ *
+ * Initializes all HDMI resources from a @drm_connector_state without
+ * actually allocating it. This is useful for HDMI drivers, in
+ * combination with __drm_atomic_helper_connector_reset() or
+ * drm_atomic_helper_connector_reset().
+ */
+void __drm_atomic_helper_connector_hdmi_reset(struct drm_connector *connector,
+ struct drm_connector_state 
*new_conn_state)
+{
+}
+EXPORT_SYMBOL(__drm_atomic_helper_connector_hdmi_reset);
+
+/**
+ * drm_atomic_helper_connector_hdmi_check() - Helper to check HDMI connector 
atomic state
+ * @connector: DRM Connector
+ * @state: the DRM State object
+ *
+ * Provides a default connector state check handler for HDMI connectors.
+ * Checks that a desired connector update is valid, and updates various
+ * fields of derived state.
+ *
+ * RETURNS:
+ * Zero on success, or an errno code otherwise.
+ */
+int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector,
+  struct drm_atomic_state *state)
+{
+   return 0;
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_check);
diff --git a/include/drm/display/drm_hdmi_state_helper.h 
b/include/drm/display/drm_hdmi_state_helper.h
new file mode 100644
index ..6021983e2602
--- /dev/null
+++ b/include/drm/display/drm_hdmi_state_helper.h
@@ -0,0 +1,16 @@
+#/* SPDX-License-Identifier: MIT */
+
+#ifndef DRM_HDMI_STATE_HELPER_H_
+#define DRM_HDMI_STATE_HELPER_H_
+
+struct drm_atomic_state;
+struct drm_connector;
+struct drm_connector_state;
+
+void __drm_atomic_helper_connector_hdmi_reset(struct drm_connector *connector,
+ struct drm_connector_state 
*new_conn_state);
+
+int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector,
+  struct drm_atomic_state *state);
+
+#endif // DRM_HDMI_STATE_HELPER_H_
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 4491c4c2fb6e..000a2a156619 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1029,10 +1029,17 @@ struct drm_connector_state {
/**
 * @hdr_output_metadata:
 * DRM blob property for HDR output metadata
 */
struct drm_property_blob *hdr_output_metadata;
+
+   /**
+* @hdmi: HDMI-related variable and properties

[PATCH v15 04/29] drm/connector: hdmi: Add output BPC to the connector state

2024-05-27 Thread Maxime Ripard
We'll add automatic selection of the output BPC in a following patch,
but let's add it to the HDMI connector state already.

Reviewed-by: Dave Stevenson 
Reviewed-by: Dmitry Baryshkov 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/display/drm_hdmi_state_helper.c | 20 
 drivers/gpu/drm/drm_atomic.c|  5 +
 drivers/gpu/drm/drm_connector.c | 20 +++-
 drivers/gpu/drm/tests/drm_connector_test.c  | 12 
 include/drm/drm_connector.h | 12 +++-
 5 files changed, 63 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c 
b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 1e92c1108d23..82293d93b5f8 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -16,10 +16,14 @@
  * drm_atomic_helper_connector_reset().
  */
 void __drm_atomic_helper_connector_hdmi_reset(struct drm_connector *connector,
  struct drm_connector_state 
*new_conn_state)
 {
+   unsigned int max_bpc = connector->max_bpc;
+
+   new_conn_state->max_bpc = max_bpc;
+   new_conn_state->max_requested_bpc = max_bpc;
 }
 EXPORT_SYMBOL(__drm_atomic_helper_connector_hdmi_reset);
 
 /**
  * drm_atomic_helper_connector_hdmi_check() - Helper to check HDMI connector 
atomic state
@@ -34,8 +38,24 @@ EXPORT_SYMBOL(__drm_atomic_helper_connector_hdmi_reset);
  * Zero on success, or an errno code otherwise.
  */
 int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector,
   struct drm_atomic_state *state)
 {
+   struct drm_connector_state *old_conn_state =
+   drm_atomic_get_old_connector_state(state, connector);
+   struct drm_connector_state *new_conn_state =
+   drm_atomic_get_new_connector_state(state, connector);
+
+   if (old_conn_state->hdmi.output_bpc != new_conn_state->hdmi.output_bpc) 
{
+   struct drm_crtc *crtc = new_conn_state->crtc;
+   struct drm_crtc_state *crtc_state;
+
+   crtc_state = drm_atomic_get_crtc_state(state, crtc);
+   if (IS_ERR(crtc_state))
+   return PTR_ERR(crtc_state);
+
+   crtc_state->mode_changed = true;
+   }
+
return 0;
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_check);
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index a91737adf8e7..4e11cfb4518b 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1141,10 +1141,15 @@ static void drm_atomic_connector_print_state(struct 
drm_printer *p,
drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : 
"(null)");
drm_printf(p, "\tself_refresh_aware=%d\n", state->self_refresh_aware);
drm_printf(p, "\tmax_requested_bpc=%d\n", state->max_requested_bpc);
drm_printf(p, "\tcolorspace=%s\n", 
drm_get_colorspace_name(state->colorspace));
 
+   if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
+   connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) {
+   drm_printf(p, "\toutput_bpc=%u\n", state->hdmi.output_bpc);
+   }
+
if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
if (state->writeback_job && state->writeback_job->fb)
drm_printf(p, "\tfb=%d\n", 
state->writeback_job->fb->base.id);
 
if (connector->funcs->atomic_print_state)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index d9961cce8245..da51a2bcb978 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -457,10 +457,11 @@ EXPORT_SYMBOL(drmm_connector_init);
  * @dev: DRM device
  * @connector: A pointer to the HDMI connector to init
  * @funcs: callbacks for this connector
  * @connector_type: user visible type of the connector
  * @ddc: optional pointer to the associated ddc adapter
+ * @max_bpc: Maximum bits per char the HDMI connector supports
  *
  * Initialises a preallocated HDMI connector. Connectors can be
  * subclassed as part of driver connector objects.
  *
  * Cleanup is automatically handled with a call to
@@ -473,22 +474,39 @@ EXPORT_SYMBOL(drmm_connector_init);
  */
 int drmm_connector_hdmi_init(struct drm_device *dev,
 struct drm_connector *connector,
 const struct drm_connector_funcs *funcs,
 int connector_type,
-struct i2c_adapter *ddc)
+struct i2c_adapter *ddc,
+unsigned int max_bpc)
 {
int ret;
 
if (!(connector_type == DRM_MODE_CONNECTOR_HDMIA ||

[PATCH v15 00/29] drm/connector: Create HDMI Connector infrastructure

2024-05-27 Thread Maxime Ripard
Hi,

Here's a series that creates some extra infrastructure specifically
targeted at HDMI controllers.

The idea behind this series came from a recent discussion on IRC during
which we discussed infoframes generation of i915 vs everything else.

Infoframes generation code still requires some decent boilerplate, with
each driver doing some variation of it.

In parallel, while working on vc4, we ended up converting a lot of i915
logic (mostly around format / bpc selection, and scrambler setup) to
apply on top of a driver that relies only on helpers.

While currently sitting in the vc4 driver, none of that logic actually
relies on any driver or hardware-specific behaviour.

The only missing piece to make it shareable are a bunch of extra
variables stored in a state (current bpc, format, RGB range selection,
etc.).

The initial implementation was relying on some generic subclass of
drm_connector to address HDMI connectors, with a bunch of helpers that
will take care of all the "HDMI Spec" related code. Scrambler setup is
missing at the moment but can easily be plugged in.

The feedback was that creating a connector subclass like was done for
writeback would prevent the adoption of those helpers since it couldn't
be used in all situations (like when the connector driver can implement
multiple output) and required more churn to cast between the
drm_connector and its subclass. The decision was thus to provide a set
of helper and to store the required variables in drm_connector and
drm_connector_state. This what has been implemented now.

Hans Verkuil also expressed interest in implementing a mechanism in v4l2
to retrieve infoframes from HDMI receiver and implementing a tool to
decode (and eventually check) infoframes. His current work on
edid-decode to enable that based on that series can be found here:
https://git.linuxtv.org/hverkuil/edid-decode.git/log/?h=hverkuil

And some more context here:
https://lore.kernel.org/dri-devel/50db7366-cd3d-4675-aaad-b85720223...@xs4all.nl/

This series thus leverages the infoframe generation code to expose it
through debugfs.

I also used the occasion to unit-test everything but the infoframe
generation, which can come later once I get a proper understanding of
what the infoframe are supposed to look like. This required to add some
extra kunit helpers and infrastructure to have multiple EDIDs and allow
each test to run with a particular set of capabilities.

This entire series has been tested on a Pi4, passes all its unittests
(125 new tests), and has only been build-tested for sunxi and rockchip.

Let me know what you think,
Maxime

Signed-off-by: Maxime Ripard 
---
Changes in v15:
- Fix YUV422 bpc check
- Mention explicitly (and in the logs) that YUV420 isn't supported for
  now
- Fix warning when running the bpc test
- Change the order of the drm_mode_obj_find_prop_id export patch
- Fix some sun4i changes having made their way into the rockchip patch
- Drop spurious Broadcast RGB documentation
- Link to v14: 
https://lore.kernel.org/r/20240521-kms-hdmi-connector-state-v14-0-51950db4f...@kernel.org

Changes in v14:
- Warn instead of rejecting the configuration if RGB is missing due to
  some bad or faulty EDID
- Link to v13: 
https://lore.kernel.org/r/20240507-kms-hdmi-connector-state-v13-0-8fafc5efe...@kernel.org

Changes in v13:
- Adapt to latest Kconfig helper changes
- Fixes for sun4i and rockchip
- Rebase on current drm-misc-next
- Link to v12: 
https://lore.kernel.org/r/20240423-kms-hdmi-connector-state-v12-0-3338e4c0b...@kernel.org

Changes in v12:
- Rebase on current drm-misc-next
- Remove VIC check in clock rate computation function
- Invert RGB range logic to signal limited range instead of full like
  before
- Link to v11: 
https://lore.kernel.org/r/20240326-kms-hdmi-connector-state-v11-0-c5680ffcf...@kernel.org

Changes in v11:
- Turn the HDMI state helpers into a separate C file under
  drivers/gpu/drm/display
- Rework the Kconfig options too to prevent configuration breakages.
- Link to v10: 
https://lore.kernel.org/r/20240321-kms-hdmi-connector-state-v10-0-e6c178361...@kernel.org

Changes in v10:
- Drop the YUV422 fallback, and adjust the tests accordingly
- Fix HDMI infoframe handling
- Remove the infoframe copy in drm_connector
- Add a TODO that drm_hdmi_avi_infoframe_quant_range() only works for
  RGB
- Add a TODO for the YUV420 selection
- Fix a few bugs in vc4
- Change the logging from driver to KMS for the helpers
- Drop UPDATE_INFOFRAME macro
- Add infoframe code logging
- Document the selection of 8bpc for VIC1
- Rename state to conn_state where relevant
- Link to v9: 
https://lore.kernel.org/r/20240311-kms-hdmi-connector-state-v9-0-d45890323...@kernel.org

Changes in v9:
- Generate every infoframe but the HDMI vendor one if has_hdmi_infoframe
  isn't set
- Fix typos in the doc
- Removed undef for inexisting macro
- Improve the Broadcast RGB sanitation test
- Make EDID bytes array const
- Link to v8: 
https://lore.kernel.org/r/2024030

[PATCH v15 01/29] drm/connector: Introduce an HDMI connector initialization function

2024-05-27 Thread Maxime Ripard
A lot of the various HDMI drivers duplicate some logic that depends on
the HDMI spec itself and not really a particular hardware
implementation.

Output BPC or format selection, infoframe generation are good examples
of such areas.

This creates a lot of boilerplate, with a lot of variations, which makes
it hard for userspace to rely on, and makes it difficult to get it right
for drivers.

In the next patches, we'll add a lot of infrastructure around the
drm_connector and drm_connector_state structures, which will allow to
abstract away the duplicated logic. This infrastructure comes with a few
requirements though, and thus we need a new initialization function.

Hopefully, this will make drivers simpler to handle, and their behaviour
more consistent.

Reviewed-by: Dave Stevenson 
Reviewed-by: Sui Jingfeng 
Reviewed-by: Dmitry Baryshkov 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/drm_connector.c | 39 +++
 include/drm/drm_connector.h |  5 +
 2 files changed, 44 insertions(+)

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index b0516505f7ae..d9961cce8245 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -450,10 +450,49 @@ int drmm_connector_init(struct drm_device *dev,
 
return 0;
 }
 EXPORT_SYMBOL(drmm_connector_init);
 
+/**
+ * drmm_connector_hdmi_init - Init a preallocated HDMI connector
+ * @dev: DRM device
+ * @connector: A pointer to the HDMI connector to init
+ * @funcs: callbacks for this connector
+ * @connector_type: user visible type of the connector
+ * @ddc: optional pointer to the associated ddc adapter
+ *
+ * Initialises a preallocated HDMI connector. Connectors can be
+ * subclassed as part of driver connector objects.
+ *
+ * Cleanup is automatically handled with a call to
+ * drm_connector_cleanup() in a DRM-managed action.
+ *
+ * The connector structure should be allocated with drmm_kzalloc().
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drmm_connector_hdmi_init(struct drm_device *dev,
+struct drm_connector *connector,
+const struct drm_connector_funcs *funcs,
+int connector_type,
+struct i2c_adapter *ddc)
+{
+   int ret;
+
+   if (!(connector_type == DRM_MODE_CONNECTOR_HDMIA ||
+ connector_type == DRM_MODE_CONNECTOR_HDMIB))
+   return -EINVAL;
+
+   ret = drmm_connector_init(dev, connector, funcs, connector_type, ddc);
+   if (ret)
+   return ret;
+
+   return 0;
+}
+EXPORT_SYMBOL(drmm_connector_hdmi_init);
+
 /**
  * drm_connector_attach_edid_property - attach edid property.
  * @connector: the connector
  *
  * Some connector types like DRM_MODE_CONNECTOR_VIRTUAL do not get a
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index fe88d7fc6b8f..4491c4c2fb6e 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1902,10 +1902,15 @@ int drm_connector_init_with_ddc(struct drm_device *dev,
 int drmm_connector_init(struct drm_device *dev,
struct drm_connector *connector,
const struct drm_connector_funcs *funcs,
int connector_type,
struct i2c_adapter *ddc);
+int drmm_connector_hdmi_init(struct drm_device *dev,
+struct drm_connector *connector,
+const struct drm_connector_funcs *funcs,
+int connector_type,
+struct i2c_adapter *ddc);
 void drm_connector_attach_edid_property(struct drm_connector *connector);
 int drm_connector_register(struct drm_connector *connector);
 void drm_connector_unregister(struct drm_connector *connector);
 int drm_connector_attach_encoder(struct drm_connector *connector,
  struct drm_encoder *encoder);

-- 
2.45.0



Re: [PATCH v14 17/28] drm/connector: hdmi: Add Broadcast RGB property

2024-05-27 Thread Maxime Ripard
Hi,

On Mon, May 27, 2024 at 12:43:18PM GMT, Dmitry Baryshkov wrote:
> On Mon, May 27, 2024 at 11:02:13AM +0200, Maxime Ripard wrote:
> > Hi,
> > 
> > Thanks again for that thorough review :)
> > 
> > On Thu, May 23, 2024 at 01:22:56PM GMT, Dmitry Baryshkov wrote:
> > > On Tue, May 21, 2024 at 12:13:50PM +0200, Maxime Ripard wrote:
> > > > The i915 driver has a property to force the RGB range of an HDMI output.
> > > > The vc4 driver then implemented the same property with the same
> > > > semantics. KWin has support for it, and a PR for mutter is also there to
> > > > support it.
> > > > 
> > > > Both drivers implementing the same property with the same semantics,
> > > > plus the userspace having support for it, is proof enough that it's
> > > > pretty much a de-facto standard now and we can provide helpers for it.
> > > > 
> > > > Let's plumb it into the newly created HDMI connector.
> > > > 
> > > > Reviewed-by: Dave Stevenson 
> > > > Acked-by: Pekka Paalanen 
> > > > Reviewed-by: Sebastian Wick 
> > > > Signed-off-by: Maxime Ripard 
> > > > ---
> > > >  Documentation/gpu/kms-properties.csv|  1 -
> > > >  drivers/gpu/drm/display/drm_hdmi_state_helper.c |  4 +-
> > > >  drivers/gpu/drm/drm_atomic.c|  2 +
> > > >  drivers/gpu/drm/drm_atomic_uapi.c   |  4 ++
> > > >  drivers/gpu/drm/drm_connector.c | 88 
> > > > +
> > > >  include/drm/drm_connector.h | 36 ++
> > > >  6 files changed, 133 insertions(+), 2 deletions(-)
> > > > 
> > > > diff --git a/Documentation/gpu/kms-properties.csv 
> > > > b/Documentation/gpu/kms-properties.csv
> > > > index 0f9590834829..caef14c532d4 100644
> > > > --- a/Documentation/gpu/kms-properties.csv
> > > > +++ b/Documentation/gpu/kms-properties.csv
> > > > @@ -15,11 +15,10 @@ Owner Module/Drivers,Group,Property 
> > > > Name,Type,Property Values,Object attached,De
> > > >  ,,“saturation”,RANGE,"Min=0, Max=100",Connector,TBD
> > > >  ,,“hue”,RANGE,"Min=0, Max=100",Connector,TBD
> > > >  ,Virtual GPU,“suggested X”,RANGE,"Min=0, 
> > > > Max=0x",Connector,property to suggest an X offset for a 
> > > > connector
> > > >  ,,“suggested Y”,RANGE,"Min=0, Max=0x",Connector,property to 
> > > > suggest an Y offset for a connector
> > > >  ,Optional,"""aspect ratio""",ENUM,"{ ""None"", ""4:3"", ""16:9"" 
> > > > }",Connector,TDB
> > > > -i915,Generic,"""Broadcast RGB""",ENUM,"{ ""Automatic"", ""Full"", 
> > > > ""Limited 16:235"" }",Connector,"When this property is set to Limited 
> > > > 16:235 and CTM is set, the hardware will be programmed with the result 
> > > > of the multiplication of CTM by the limited range matrix to ensure the 
> > > > pixels normally in the range 0..1.0 are remapped to the range 
> > > > 16/255..235/255."
> > > 
> > > Should it still be defined as a generic property?
> > 
> > I'm not sure what you mean here, sorry. It's being documented as a
> > connector property now, so it's very much still listed as a generic
> > property?
> 
> I didn't perform my duty well enough and I didn't check the file for
> other instances of the property. Now I indeed see a generic "Broadcast
> RGB" property, but to me it looks like having a different set of values:
> 
> ,,"""Broadcast RGB""",ENUM,"{ “off”, “auto”, “on” }",Connector,TBD

That's not really what I meant: that file is deprecated now and it's not
where we document the properties anymore. This patch has improved that
documentation and moved it to the new place, and removed the deprecated
part.

However, this line shouldn't be there at all. I'll add a patch to remove
it.

Thanks!
Maxime


signature.asc
Description: PGP signature


Re: [PATCH v14 17/28] drm/connector: hdmi: Add Broadcast RGB property

2024-05-27 Thread Maxime Ripard
Hi,

Thanks again for that thorough review :)

On Thu, May 23, 2024 at 01:22:56PM GMT, Dmitry Baryshkov wrote:
> On Tue, May 21, 2024 at 12:13:50PM +0200, Maxime Ripard wrote:
> > The i915 driver has a property to force the RGB range of an HDMI output.
> > The vc4 driver then implemented the same property with the same
> > semantics. KWin has support for it, and a PR for mutter is also there to
> > support it.
> > 
> > Both drivers implementing the same property with the same semantics,
> > plus the userspace having support for it, is proof enough that it's
> > pretty much a de-facto standard now and we can provide helpers for it.
> > 
> > Let's plumb it into the newly created HDMI connector.
> > 
> > Reviewed-by: Dave Stevenson 
> > Acked-by: Pekka Paalanen 
> > Reviewed-by: Sebastian Wick 
> > Signed-off-by: Maxime Ripard 
> > ---
> >  Documentation/gpu/kms-properties.csv|  1 -
> >  drivers/gpu/drm/display/drm_hdmi_state_helper.c |  4 +-
> >  drivers/gpu/drm/drm_atomic.c|  2 +
> >  drivers/gpu/drm/drm_atomic_uapi.c   |  4 ++
> >  drivers/gpu/drm/drm_connector.c | 88 
> > +
> >  include/drm/drm_connector.h | 36 ++
> >  6 files changed, 133 insertions(+), 2 deletions(-)
> > 
> > diff --git a/Documentation/gpu/kms-properties.csv 
> > b/Documentation/gpu/kms-properties.csv
> > index 0f9590834829..caef14c532d4 100644
> > --- a/Documentation/gpu/kms-properties.csv
> > +++ b/Documentation/gpu/kms-properties.csv
> > @@ -15,11 +15,10 @@ Owner Module/Drivers,Group,Property Name,Type,Property 
> > Values,Object attached,De
> >  ,,“saturation”,RANGE,"Min=0, Max=100",Connector,TBD
> >  ,,“hue”,RANGE,"Min=0, Max=100",Connector,TBD
> >  ,Virtual GPU,“suggested X”,RANGE,"Min=0, 
> > Max=0x",Connector,property to suggest an X offset for a connector
> >  ,,“suggested Y”,RANGE,"Min=0, Max=0x",Connector,property to 
> > suggest an Y offset for a connector
> >  ,Optional,"""aspect ratio""",ENUM,"{ ""None"", ""4:3"", ""16:9"" 
> > }",Connector,TDB
> > -i915,Generic,"""Broadcast RGB""",ENUM,"{ ""Automatic"", ""Full"", 
> > ""Limited 16:235"" }",Connector,"When this property is set to Limited 
> > 16:235 and CTM is set, the hardware will be programmed with the result of 
> > the multiplication of CTM by the limited range matrix to ensure the pixels 
> > normally in the range 0..1.0 are remapped to the range 16/255..235/255."
> 
> Should it still be defined as a generic property?

I'm not sure what you mean here, sorry. It's being documented as a
connector property now, so it's very much still listed as a generic
property?

Maxime


signature.asc
Description: PGP signature


Re: UAPI Re: [PATCH 1/3] drm: Add DRM_MODE_TV_MODE_MONOCHROME

2024-05-23 Thread Maxime Ripard
Hi,

Reviving this thread because I'm not sure what the outcome was.

On Thu, Feb 29, 2024 at 11:52:12AM GMT, Daniel Vetter wrote:
> > The only thing I'm saying is that this breaks the usual DRM requirements.
> > If, as a maintainer, you're fine with breaking the rules and have a good
> > motivation to do so, that's fine by me. Rules are meant to be broken from
> > time to time depending on the situation. But please don't pretend that
> > modetest/xrandr is valid user-space to pass the rules.
> 
> I think it bends it pretty badly, because people running native Xorg are
> slowly going away, and the modetest hack does not clear the bar for "is it
> a joke/test/demo hack" for me.
> 
> I think some weston (or whatever compositor you like) config file support
> to set a bunch of "really only way to configure is by hand" output
> properties would clear the bar here for me. Because that is a feature I
> already mentioned that xrandr _does_ have, and which modetest hackery very
> much does not.

The expectation (and general usage) for that property was that it was
set by the kernel command line and then was forgotten about. Old TVs
require one mode and that's it, so it doesn't make much sense to change
it while the system is live, you just want the default to work.

So it's not really a matter of "the user-space code should be open"
here, there's no user-space code, and there will likely never be given
that it's mostly used to deal with decades-old systems at this point.

Maxime


signature.asc
Description: PGP signature


Re: Safety of opening up /dev/dma_heap/* to physically present users (udev uaccess tag) ?

2024-05-22 Thread Maxime Ripard
Hi,

On Mon, May 06, 2024 at 03:38:24PM GMT, Daniel Vetter wrote:
> On Mon, May 06, 2024 at 02:05:12PM +0200, Maxime Ripard wrote:
> > Hi,
> > 
> > On Mon, May 06, 2024 at 01:49:17PM GMT, Hans de Goede wrote:
> > > Hi dma-buf maintainers, et.al.,
> > > 
> > > Various people have been working on making complex/MIPI cameras work OOTB
> > > with mainline Linux kernels and an opensource userspace stack.
> > > 
> > > The generic solution adds a software ISP (for Debayering and 3A) to
> > > libcamera. Libcamera's API guarantees that buffers handed to applications
> > > using it are dma-bufs so that these can be passed to e.g. a video encoder.
> > > 
> > > In order to meet this API guarantee the libcamera software ISP allocates
> > > dma-bufs from userspace through one of the /dev/dma_heap/* heaps. For
> > > the Fedora COPR repo for the PoC of this:
> > > https://hansdegoede.dreamwidth.org/28153.html
> > 
> > For the record, we're also considering using them for ARM KMS devices,
> > so it would be better if the solution wasn't only considering v4l2
> > devices.
> > 
> > > I have added a simple udev rule to give physically present users access
> > > to the dma_heap-s:
> > > 
> > > KERNEL=="system", SUBSYSTEM=="dma_heap", TAG+="uaccess"
> > > 
> > > (and on Rasperry Pi devices any users in the video group get access)
> > > 
> > > This was just a quick fix for the PoC. Now that we are ready to move out
> > > of the PoC phase and start actually integrating this into distributions
> > > the question becomes if this is an acceptable solution; or if we need some
> > > other way to deal with this ?
> > > 
> > > Specifically the question is if this will have any negative security
> > > implications? I can certainly see this being used to do some sort of
> > > denial of service attack on the system (1). This is especially true for
> > > the cma heap which generally speaking is a limited resource.
> > 
> > There's plenty of other ways to exhaust CMA, like allocating too much
> > KMS or v4l2 buffers. I'm not sure we should consider dma-heaps
> > differently than those if it's part of our threat model.
> 
> So generally for an arm soc where your display needs cma, your render node
> doesn't. And user applications only have access to the later, while only
> the compositor gets a kms fd through logind. At least in drm aside from
> vc4 there's really no render driver that just gives you access to cma and
> allows you to exhaust that, you need to be a compositor with drm master
> access to the display.
> 
> Which means we're mostly protected against bad applications, and that's
> not a threat the "user physically sits in front of the machine accounts
> for", and which giving cma access to everyone would open up. And with
> flathub/snaps/... this is very much an issue.
> 
> So you need more, either:
> 
> - cgroups limits on dma-buf and dma-buf heaps. This has been bikeshedded
>   for years and is just not really moving.

For reference, are you talking about:

https://lore.kernel.org/r/20220502231944.3891435-1-tjmerc...@google.com

Or has there been a new version of that recently?

Maxime


signature.asc
Description: PGP signature


Re: [PATCH 0/8] dma-buf: heaps: Support carved-out heaps and ECC related-flags

2024-05-22 Thread Maxime Ripard
On Tue, May 21, 2024 at 02:06:19PM GMT, Daniel Vetter wrote:
> On Thu, May 16, 2024 at 09:51:35AM -0700, John Stultz wrote:
> > On Thu, May 16, 2024 at 3:56 AM Daniel Vetter  wrote:
> > > On Wed, May 15, 2024 at 11:42:58AM -0700, John Stultz wrote:
> > > > But it makes me a little nervous to add a new generic allocation flag
> > > > for a feature most hardware doesn't support (yet, at least). So it's
> > > > hard to weigh how common the actual usage will be across all the
> > > > heaps.
> > > >
> > > > I apologize as my worry is mostly born out of seeing vendors really
> > > > push opaque feature flags in their old ion heaps, so in providing a
> > > > flags argument, it was mostly intended as an escape hatch for
> > > > obviously common attributes. So having the first be something that
> > > > seems reasonable, but isn't actually that common makes me fret some.
> > > >
> > > > So again, not an objection, just something for folks to stew on to
> > > > make sure this is really the right approach.
> > >
> > > Another good reason to go with full heap names instead of opaque flags on
> > > existing heaps is that with the former we can use symlinks in sysfs to
> > > specify heaps, with the latter we need a new idea. We haven't yet gotten
> > > around to implement this anywhere, but it's been in the dma-buf/heap todo
> > > since forever, and I like it as a design approach. So would be a good idea
> > > to not toss it. With that display would have symlinks to cma-ecc and cma,
> > > and rendering maybe cma-ecc, shmem, cma heaps (in priority order) for a
> > > SoC where the display needs contig memory for scanout.
> > 
> > So indeed that is a good point to keep in mind, but I also think it
> > might re-inforce the choice of having ECC as a flag here.
> > 
> > Since my understanding of the sysfs symlinks to heaps idea is about
> > being able to figure out a common heap from a collection of devices,
> > it's really about the ability for the driver to access the type of
> > memory. If ECC is just an attribute of the type of memory (as in this
> > patch series), it being on or off won't necessarily affect
> > compatibility of the buffer with the device.  Similarly "uncached"
> > seems more of an attribute of memory type and not a type itself.
> > Hardware that can access non-contiguous "system" buffers can access
> > uncached system buffers.
> 
> Yeah, but in graphics there's a wide band where "shit performance" is
> defacto "not useable (as intended at least)".

Right, but "not useable" is still kind of usage dependent, which
reinforces the need for flags (and possibly some way to discover what
the heap supports).

Like, if I just want to allocate a buffer for a single writeback frame,
then I probably don't have the same requirements than a compositor that
needs to output a frame at 120Hz.

The former probably doesn't care about the buffer attributes aside that
it's accessible by the device. The latter probably can't make any kind
of compromise over what kind of memory characteristics it uses.

If we look into the current discussions we have, a compositor would
probably need a buffer without ECC, non-secure, and probably wouldn't
care about caching and being physically contiguous.

Libcamera's SoftISP would probably require that the buffer is cacheable,
non-secure, without ECC and might ask for physically contiguous buffers.

As we add more memory types / attributes, I think being able to discover
and enforce a particular set of flags will be more and more important,
even more so if we tie heaps to devices, because it just gives a hint
about the memory being reachable from the device, but as you said, you
can still get a buffer with shit performance that won't be what you
want.

> So if we limit the symlink idea to just making sure zero-copy access is
> possible, then we might not actually solve the real world problem we need
> to solve. And so the symlinks become somewhat useless, and we need to
> somewhere encode which flags you need to use with each symlink.
> 
> But I also see the argument that there's a bit a combinatorial explosion
> possible. So I guess the question is where we want to handle it ...
> 
> Also wondering whether we should get the symlink/allocator idea off the
> ground first, but given that that hasn't moved in a decade it might be too
> much. But then the question is, what userspace are we going to use for all
> these new heaps (or heaps with new flags)?

For ECC here, the compositors are the obvious target. Which loops backs
into the discussion with John. Do you consider dma-buf code have the
same uapi requirements as DRM?

Maxime


signature.asc
Description: PGP signature


Re: [PATCH v4 10/10] drm/vs: add simple dsi encoder

2024-05-22 Thread Maxime Ripard
Hi,

On Tue, May 21, 2024 at 06:58:17PM GMT, keith wrote:
> add encoder to match cdns dsi driver
> 
> Signed-off-by: keith 
> ---
>  drivers/gpu/drm/verisilicon/Makefile|   3 +-
>  drivers/gpu/drm/verisilicon/vs_drv.c|   1 +
>  drivers/gpu/drm/verisilicon/vs_drv.h|   1 +
>  drivers/gpu/drm/verisilicon/vs_simple_enc.c | 190 
>  drivers/gpu/drm/verisilicon/vs_simple_enc.h |  25 +++
>  5 files changed, 219 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/verisilicon/vs_simple_enc.c
>  create mode 100644 drivers/gpu/drm/verisilicon/vs_simple_enc.h
> 
> diff --git a/drivers/gpu/drm/verisilicon/Makefile 
> b/drivers/gpu/drm/verisilicon/Makefile
> index 2d02b4a3a567..c35ba9bd6f81 100644
> --- a/drivers/gpu/drm/verisilicon/Makefile
> +++ b/drivers/gpu/drm/verisilicon/Makefile
> @@ -4,7 +4,8 @@ vs_drm-objs := vs_dc_hw.o \
>   vs_modeset.o \
>   vs_plane.o \
>   vs_crtc.o \
> - vs_drv.o
> + vs_drv.o \
> + vs_simple_enc.o
>  
>  vs_drm-$(CONFIG_DRM_INNO_STARFIVE_HDMI) += inno_hdmi-starfive.o
>  obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o
> diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c 
> b/drivers/gpu/drm/verisilicon/vs_drv.c
> index 6f04102b05b3..2748d48f2c7e 100644
> --- a/drivers/gpu/drm/verisilicon/vs_drv.c
> +++ b/drivers/gpu/drm/verisilicon/vs_drv.c
> @@ -612,6 +612,7 @@ static struct platform_driver *drm_sub_drivers[] = {
>  #ifdef CONFIG_DRM_INNO_STARFIVE_HDMI
>   _hdmi_driver,
>  #endif
> + _encoder_driver,
>  };
>  
>  static struct component_match *vs_add_external_components(struct device *dev)
> diff --git a/drivers/gpu/drm/verisilicon/vs_drv.h 
> b/drivers/gpu/drm/verisilicon/vs_drv.h
> index c3c08ed5f8ac..f3f0f170777d 100644
> --- a/drivers/gpu/drm/verisilicon/vs_drv.h
> +++ b/drivers/gpu/drm/verisilicon/vs_drv.h
> @@ -17,6 +17,7 @@
>  #include 
>  
>  #include "vs_dc_hw.h"
> +#include "vs_simple_enc.h"
>  
>  /*@pitch_alignment: buffer pitch alignment required by sub-devices.*/
>  struct vs_drm_device {
> diff --git a/drivers/gpu/drm/verisilicon/vs_simple_enc.c 
> b/drivers/gpu/drm/verisilicon/vs_simple_enc.c
> new file mode 100644
> index ..d0b1755d77d2
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_simple_enc.c
> @@ -0,0 +1,190 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2020 VeriSilicon Holdings Co., Ltd.
> + */
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +#include "vs_crtc.h"
> +#include "vs_simple_enc.h"
> +
> +static const struct simple_encoder_priv dsi_priv = {
> + .encoder_type = DRM_MODE_ENCODER_DSI
> +};

A simple encoder is a thing in KMS, and it's not what you are doing /
using. Please use a different name.

> +static inline struct vs_simple_encoder *to_simple_encoder(struct drm_encoder 
> *enc)
> +{
> + return container_of(enc, struct vs_simple_encoder, encoder);
> +}
> +
> +static int encoder_parse_dt(struct device *dev)
> +{
> + struct vs_simple_encoder *simple = dev_get_drvdata(dev);
> + unsigned int args[2];
> +
> + simple->dss_regmap = syscon_regmap_lookup_by_phandle_args(dev->of_node,
> +   
> "starfive,syscon",
> +   2, args);
> +
> + if (IS_ERR(simple->dss_regmap)) {
> + return dev_err_probe(dev, PTR_ERR(simple->dss_regmap),
> +  "getting the regmap failed\n");
> + }
> +
> + simple->offset = args[0];
> + simple->mask = args[1];
> +
> + return 0;
> +}
> +
> +static void vs_encoder_atomic_enable(struct drm_encoder *encoder, struct 
> drm_atomic_state *state)
> +{
> + struct vs_simple_encoder *simple = to_simple_encoder(encoder);
> +
> + regmap_update_bits(simple->dss_regmap, simple->offset, simple->mask, 
> simple->mask);
> +}

That should be handled through cdns_dsi_platform_ops.enable.

> +static int vs_encoder_atomic_check(struct drm_encoder *encoder,
> +struct drm_crtc_state *crtc_state,
> +struct drm_connector_state *conn_state)
> +{
> + struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc_state);
> + struct drm_connector *connector = conn_state->connector;
> + int ret = 0;
> +
> + vs_crtc_state->encoder_type = encoder->encoder_type;
> + if (connector->display_info.num_bus_formats)
> + vs_crtc_state->output_fmt = 
> connector->display_info.bus_formats[0];
> + else
> + vs_crtc_state->output_fmt = MEDIA_BUS_FMT_FIXED;
> +
> + switch (vs_crtc_state->output_fmt) {
> + case MEDIA_BUS_FMT_FIXED:
> + case MEDIA_BUS_FMT_RGB565_1X16:
> + case MEDIA_BUS_FMT_RGB666_1X18:
> + case MEDIA_BUS_FMT_RGB888_1X24:
> + case 

Re: [PATCH v4 03/10] drm/rockchip:hdmi: migrate to use inno-hdmi bridge driver

2024-05-22 Thread Maxime Ripard
Hi,

On Tue, May 21, 2024 at 06:58:10PM GMT, keith wrote:
> Add the ROCKCHIP inno hdmi driver that uses the Inno DesignWare
> HDMI TX bridge and remove the old separate one.
> 
> Signed-off-by: keith 
> ---
>  drivers/gpu/drm/rockchip/Kconfig  |1 +
>  drivers/gpu/drm/rockchip/Makefile |2 +-
>  drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c |  517 
>  .../{inno_hdmi.h => inno_hdmi-rockchip.h} |   45 -
>  drivers/gpu/drm/rockchip/inno_hdmi.c  | 1073 -
>  5 files changed, 519 insertions(+), 1119 deletions(-)
>  create mode 100644 drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
>  rename drivers/gpu/drm/rockchip/{inno_hdmi.h => inno_hdmi-rockchip.h} (85%)
>  delete mode 100644 drivers/gpu/drm/rockchip/inno_hdmi.c
> 
> diff --git a/drivers/gpu/drm/rockchip/Kconfig 
> b/drivers/gpu/drm/rockchip/Kconfig
> index 1bf3e2829cd0..cc6cfd5a30d6 100644
> --- a/drivers/gpu/drm/rockchip/Kconfig
> +++ b/drivers/gpu/drm/rockchip/Kconfig
> @@ -74,6 +74,7 @@ config ROCKCHIP_DW_MIPI_DSI
>  
>  config ROCKCHIP_INNO_HDMI
>   bool "Rockchip specific extensions for Innosilicon HDMI"
> + select DRM_INNO_HDMI
>   help
> This selects support for Rockchip SoC specific extensions
> for the Innosilicon HDMI driver. If you want to enable
> diff --git a/drivers/gpu/drm/rockchip/Makefile 
> b/drivers/gpu/drm/rockchip/Makefile
> index 3ff7b21c0414..4b2d0cba8db3 100644
> --- a/drivers/gpu/drm/rockchip/Makefile
> +++ b/drivers/gpu/drm/rockchip/Makefile
> @@ -12,7 +12,7 @@ rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += 
> analogix_dp-rockchip.o
>  rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
>  rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
>  rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi-rockchip.o
> -rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
> +rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi-rockchip.o
>  rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o
>  rockchipdrm-$(CONFIG_ROCKCHIP_RGB) += rockchip_rgb.o
>  rockchipdrm-$(CONFIG_ROCKCHIP_RK3066_HDMI) += rk3066_hdmi.o
> diff --git a/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c 
> b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
> new file mode 100644
> index ..69d0e913e13b
> --- /dev/null
> +++ b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
> @@ -0,0 +1,517 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
> + *Zheng Yang 
> + *Yakir Yang 
> + */
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +#include "rockchip_drm_drv.h"
> +
> +#include "inno_hdmi-rockchip.h"
> +
> +#define INNO_HDMI_MIN_TMDS_CLOCK  2500U
> +
> +struct rk_inno_hdmi {
> + struct rockchip_encoder encoder;
> + struct inno_hdmi inno_hdmi;
> + struct clk *pclk;
> + struct clk *refclk;
> +};
> +
> +static struct inno_hdmi *rk_encoder_to_inno_hdmi(struct drm_encoder *encoder)
> +{
> + struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
> + struct rk_inno_hdmi *rk_hdmi = container_of(rkencoder, struct 
> rk_inno_hdmi, encoder);
> +
> + return _hdmi->inno_hdmi;
> +}
> +
> +enum {
> + CSC_RGB_0_255_TO_ITU601_16_235_8BIT,
> + CSC_RGB_0_255_TO_ITU709_16_235_8BIT,
> + CSC_RGB_0_255_TO_RGB_16_235_8BIT,
> +};
> +
> +static const char coeff_csc[][24] = {
> + /*
> +  * RGB2YUV:601 SD mode:
> +  *   Cb = -0.291G - 0.148R + 0.439B + 128
> +  *   Y  = 0.504G  + 0.257R + 0.098B + 16
> +  *   Cr = -0.368G + 0.439R - 0.071B + 128
> +  */
> + {
> + 0x11, 0x5f, 0x01, 0x82, 0x10, 0x23, 0x00, 0x80,
> + 0x02, 0x1c, 0x00, 0xa1, 0x00, 0x36, 0x00, 0x1e,
> + 0x11, 0x29, 0x10, 0x59, 0x01, 0x82, 0x00, 0x80
> + },
> + /*
> +  * RGB2YUV:709 HD mode:
> +  *   Cb = - 0.338G - 0.101R + 0.439B + 128
> +  *   Y  = 0.614G   + 0.183R + 0.062B + 16
> +  *   Cr = - 0.399G + 0.439R - 0.040B + 128
> +  */
> + {
> + 0x11, 0x98, 0x01, 0xc1, 0x10, 0x28, 0x00, 0x80,
> + 0x02, 0x74, 0x00, 0xbb, 0x00, 0x3f, 0x00, 0x10,
> + 0x11, 0x5a, 0x10, 0x67, 0x01, 0xc1, 0x00, 0x80
> + },
> + /*
> +  * RGB[0:255]2RGB[16:235]:
> +  *   R' = R x (235-16)/255 + 16;
> +  *   G' = G x (235-16)/255 + 16;
> +  *   B' = B x (235-16)/255 + 16;
> +  */
> + {
> + 0x00, 0x00, 0x03, 0x6F, 0x00, 0x00, 0x00, 0x10,
> + 0x03, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
> + 0x00, 0x00, 0x00, 0x00, 0x03, 0x6F, 0x00, 0x10
> + },
> +};
> +
> +static struct inno_hdmi_phy_config rk3036_hdmi_phy_configs[] = {
> + {  7425, 0x3f, 0xbb },
> + { 16500, 0x6f, 0xbb },
> + {  ~0UL, 0x00, 0x00 }
> +};
> +
> +static struct 

Re: [PATCH 1/7] drm/tidss: Add CRTC mode_fixup

2024-05-21 Thread Maxime Ripard
On Thu, May 16, 2024 at 04:33:40PM GMT, Aradhya Bhatia wrote:
> Hi Maxime,
> 
> Thank you for reviewing the patches.
> 
> On 16/05/24 13:40, Maxime Ripard wrote:
> > Hi,
> > 
> > On Sat, May 11, 2024 at 09:00:45PM +0530, Aradhya Bhatia wrote:
> >> Add support for mode_fixup for the tidss CRTC.
> >>
> >> Some bridges like the cdns-dsi consume the crtc_* timing parameters for
> >> programming the blanking values. Allow for the normal timing parameters
> >> to get copied to crtc_* timing params.
> >>
> >> Signed-off-by: Aradhya Bhatia 
> >> ---
> >>  drivers/gpu/drm/tidss/tidss_crtc.c | 11 +++
> >>  1 file changed, 11 insertions(+)
> >>
> >> diff --git a/drivers/gpu/drm/tidss/tidss_crtc.c 
> >> b/drivers/gpu/drm/tidss/tidss_crtc.c
> >> index 94f8e3178df5..797ef53d9ad2 100644
> >> --- a/drivers/gpu/drm/tidss/tidss_crtc.c
> >> +++ b/drivers/gpu/drm/tidss/tidss_crtc.c
> >> @@ -309,12 +309,23 @@ enum drm_mode_status tidss_crtc_mode_valid(struct 
> >> drm_crtc *crtc,
> >>return dispc_vp_mode_valid(tidss->dispc, tcrtc->hw_videoport, mode);
> >>  }
> >>  
> >> +static
> >> +bool tidss_crtc_mode_fixup(struct drm_crtc *crtc,
> >> + const struct drm_display_mode *mode,
> >> + struct drm_display_mode *adjusted_mode)
> >> +{
> >> +  drm_mode_set_crtcinfo(adjusted_mode, 0);
> >> +
> >> +  return true;
> >> +}
> >> +
> >>  static const struct drm_crtc_helper_funcs tidss_crtc_helper_funcs = {
> >>.atomic_check = tidss_crtc_atomic_check,
> >>.atomic_flush = tidss_crtc_atomic_flush,
> >>.atomic_enable = tidss_crtc_atomic_enable,
> >>.atomic_disable = tidss_crtc_atomic_disable,
> >>  
> >> +  .mode_fixup = tidss_crtc_mode_fixup,
> >>.mode_valid = tidss_crtc_mode_valid,
> >>  };
> > 
> > mode_fixup is deprecated for atomic drivers, so the solution must be
> > different there.
> > 
> > It's also not clear to me how it could change anything there:
> > drm_mode_set_crtcinfo with no flags will make crtc_* field exactly
> > identical to their !crtc counterparts.
> >
> 
> I checked the flag options. There isn't any flag required. The only
> reason to add this call is because cdns-dsi strictly requires the crtc_*
> fields to be populated during the bridge enable.
> 
> Secondly, if mode_fixup is deprecated, I think the crtc_atomic_check
> would be the next best place to add this call.

That would be better, yes, but we shouldn't even have to do that in the
first place. AFAIK all the path that create a drm_display_mode will call
drm_mode_set_crtcinfo on it to fill those fields. So if they are missing
somewhere, that's what the actual bug is, not something we should work
around of at the driver level.

Maxime


signature.asc
Description: PGP signature


Re: [PATCH 6/7] drm/bridge: Introduce early_enable and late disable

2024-05-21 Thread Maxime Ripard
Hi,

On Thu, May 16, 2024 at 03:10:15PM GMT, Aradhya Bhatia wrote:
> >>/**
> >> * @pre_enable:
> >> *
> >> @@ -285,6 +319,26 @@ struct drm_bridge_funcs {
> >> */
> >>void (*enable)(struct drm_bridge *bridge);
> >>  
> >> +  /**
> >> +   * @atomic_early_enable:
> >> +   *
> >> +   * This callback should enable the bridge. It is called right before
> >> +   * the preceding element in the display pipe is enabled. If the
> >> +   * preceding element is a bridge this means it's called before that
> >> +   * bridge's @atomic_early_enable. If the preceding element is a
> >> +   * _crtc it's called right before the crtc's
> >> +   * _crtc_helper_funcs.atomic_enable hook.
> >> +   *
> >> +   * The display pipe (i.e. clocks and timing signals) feeding this bridge
> >> +   * will not yet be running when this callback is called. The bridge can
> >> +   * enable the display link feeding the next bridge in the chain (if
> >> +   * there is one) when this callback is called.
> >> +   *
> >> +   * The @early_enable callback is optional.
> >> +   */
> >> +  void (*atomic_early_enable)(struct drm_bridge *bridge,
> >> +  struct drm_bridge_state *old_bridge_state);
> >> +
> >>/**
> >> * @atomic_pre_enable:
> >> *
> >> @@ -361,6 +415,21 @@ struct drm_bridge_funcs {
> >>void (*atomic_post_disable)(struct drm_bridge *bridge,
> >>struct drm_bridge_state *old_bridge_state);
> >>  
> >> +  /**
> >> +   * @atomic_late_disable:
> >> +   *
> >> +   * This callback should disable the bridge. It is called right after the
> >> +   * preceding element in the display pipe is disabled. If the preceding
> >> +   * element is a bridge this means it's called after that bridge's
> >> +   * @atomic_late_disable. If the preceding element is a _crtc it's
> >> +   * called right after the crtc's _crtc_helper_funcs.atomic_disable
> >> +   * hook.
> >> +   *
> >> +   * The @atomic_late_disable callback is optional.
> >> +   */
> >> +  void (*atomic_late_disable)(struct drm_bridge *bridge,
> >> +  struct drm_bridge_state *old_bridge_state);
> >> +
> > 
> > But more importantly, I don't quite get the use case you're trying to
> > solve here.
> > 
> > If I got the rest of your series, the Cadence DSI bridge needs to be
> > powered up before its source is started. You can't use atomic_enable or
> > atomic_pre_enable because it would start the source before the DSI
> > bridge. Is that correct?
> > 
> 
> That's right. I cannot use bridge_atomic_pre_enable /
> bridge_atomic_enable here. But that's because my source is CRTC, which
> gets enabled via crtc_atomic_enable.
> 
> 
> > If it is, then how is it different from what
> > drm_atomic_bridge_chain_pre_enable is doing? The assumption there is
> > that it starts enabling bridges last to first, to it should be enabled
> > before anything starts.
> > 
> > The whole bridge enabling order code starts to be a bit of a mess, so it
> > would be great if you could list all the order variations we have
> > currently, and why none work for cdns-dsi.
> > 
> 
> Of course! I can elaborate on the order.
> 
> Without my patches (and given there isn't any bridge setting the
> "pre_enable_prev_first" flag) the order of enable for any single display
> chain, looks like this -
> 
>   crtc_enable
>   
>   bridge[n]_pre_enable
>   ---
>   bridge[1]_pre_enable
> 
>   encoder_enable
> 
>   bridge[1]_enable
>   ---
>   bridge[n]_enable
> 
> The tidss enables at the crtc_enable level, and hence is the first
> entity with stream on. cdns-dsi doesn't stand a chance with
> bridge_atmoic_pre_enable / bridge_atmoic_enable hooks. And there is no
> bridge call happening before crtc currently.

Thanks for filling the blanks :)

I assume that since cdns-dsi is a bridge, and it only has a simple
encoder implementation, for it to receive some video signal we need to
enable the CRTC before the bridge.

If so, I think that's the original intent between the bridge pre_enable.
The original documentation had:

  pre_enable: this contains things needed to be done for the bridge
  before this contains things needed to be done for the bridge before
  this contains things needed to be done for the bridge before.

and the current one has:

  The display pipe (i.e. clocks and timing signals) feeding this bridge
  will not yet be running when this callback is called. The bridge must
  not enable the display link feeding the next bridge in the chain (if
  there is one) when this callback is called.

I would say the CRTC is such a source, even more so now that the encoder
is usually transparent, so I think we should instead move the crtc
enable call after the bridge pre_enable.

Would that work?

Maxime


signature.asc
Description: PGP signature


[PATCH v14 14/28] drm/tests: Add HDMI connector rate filter hook tests

2024-05-21 Thread Maxime Ripard
The previous patch adds a new hook for HDMI connectors to filter out
configurations based on the TMDS character rate. Let's add some tests to
make sure it works as expected.

Reviewed-by: Dave Stevenson 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 65 ++
 1 file changed, 65 insertions(+)

diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c 
b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
index 7f9a48902db4..ead998a691e7 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -113,10 +113,22 @@ static int set_connector_edid(struct kunit *test, struct 
drm_connector *connecto
 }
 
 static const struct drm_connector_hdmi_funcs dummy_connector_hdmi_funcs = {
 };
 
+static enum drm_mode_status
+reject_connector_tmds_char_rate_valid(const struct drm_connector *connector,
+  const struct drm_display_mode *mode,
+  unsigned long long tmds_rate)
+{
+   return MODE_BAD;
+}
+
+static const struct drm_connector_hdmi_funcs reject_connector_hdmi_funcs = {
+   .tmds_char_rate_valid   = reject_connector_tmds_char_rate_valid,
+};
+
 static int dummy_connector_get_modes(struct drm_connector *connector)
 {
struct drm_atomic_helper_connector_hdmi_priv *priv =
connector_to_priv(connector);
const struct drm_edid *edid;
@@ -491,11 +503,64 @@ static void 
drm_test_check_tmds_char_rate_rgb_12bpc(struct kunit *test)
KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_bpc, 12);
KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, 
HDMI_COLORSPACE_RGB);
KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock 
* 1500);
 }
 
+/*
+ * Test that if we filter a rate through our hook, it's indeed rejected
+ * by the whole atomic_check logic.
+ *
+ * We do so by first doing a commit on the pipeline to make sure that it
+ * works, change the HDMI helpers pointer, and then try the same commit
+ * again to see if it fails as it should.
+ */
+static void drm_test_check_hdmi_funcs_reject_rate(struct kunit *test)
+{
+   struct drm_atomic_helper_connector_hdmi_priv *priv;
+   struct drm_modeset_acquire_ctx *ctx;
+   struct drm_atomic_state *state;
+   struct drm_display_mode *preferred;
+   struct drm_crtc_state *crtc_state;
+   struct drm_connector *conn;
+   struct drm_device *drm;
+   struct drm_crtc *crtc;
+   int ret;
+
+   priv = drm_atomic_helper_connector_hdmi_init(test,
+BIT(HDMI_COLORSPACE_RGB),
+8);
+   KUNIT_ASSERT_NOT_NULL(test, priv);
+
+   ctx = drm_kunit_helper_acquire_ctx_alloc(test);
+   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+
+   conn = >connector;
+   preferred = find_preferred_mode(conn);
+   KUNIT_ASSERT_NOT_NULL(test, preferred);
+
+   drm = >drm;
+   crtc = priv->crtc;
+   ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
+   KUNIT_ASSERT_EQ(test, ret, 0);
+
+   /* You shouldn't be doing that at home. */
+   conn->hdmi.funcs = _connector_hdmi_funcs;
+
+   state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
+   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+   crtc_state = drm_atomic_get_crtc_state(state, crtc);
+   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+   crtc_state->connectors_changed = true;
+
+   ret = drm_atomic_check_only(state);
+   KUNIT_EXPECT_LT(test, ret, 0);
+}
+
 static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = {
+   KUNIT_CASE(drm_test_check_hdmi_funcs_reject_rate),
KUNIT_CASE(drm_test_check_output_bpc_crtc_mode_changed),
KUNIT_CASE(drm_test_check_output_bpc_crtc_mode_not_changed),
KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_8bpc),
KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_10bpc),
KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_12bpc),

-- 
2.45.0



[PATCH v14 24/28] drm/vc4: hdmi: Switch to HDMI connector

2024-05-21 Thread Maxime Ripard
The new HDMI connector infrastructure allows us to remove a lot of
boilerplate, so let's switch to it.

Acked-by: Sui Jingfeng 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/vc4/Kconfig|   1 +
 drivers/gpu/drm/vc4/vc4_hdmi.c | 644 +
 drivers/gpu/drm/vc4/vc4_hdmi.h |  44 +--
 drivers/gpu/drm/vc4/vc4_hdmi_phy.c |   6 +-
 4 files changed, 92 insertions(+), 603 deletions(-)

diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig
index 91dcf8d174d6..269b5f26b2ea 100644
--- a/drivers/gpu/drm/vc4/Kconfig
+++ b/drivers/gpu/drm/vc4/Kconfig
@@ -8,10 +8,11 @@ config DRM_VC4
depends on DRM
depends on SND && SND_SOC
depends on COMMON_CLK
depends on PM
select DRM_DISPLAY_HDMI_HELPER
+   select DRM_DISPLAY_HDMI_STATE_HELPER
select DRM_DISPLAY_HELPER
select DRM_KMS_HELPER
select DRM_GEM_DMA_HELPER
select DRM_PANEL_BRIDGE
select SND_PCM
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index d30f8e8e8967..d57c4a5948c8 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -30,10 +30,11 @@
  * The driver does not yet support CEC control, though the HDMI
  * encoder block has CEC support.
  */
 
 #include 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
@@ -108,29 +109,10 @@
 #define HSM_MIN_CLOCK_FREQ 12000
 #define CEC_CLOCK_FREQ 4
 
 #define HDMI_14_MAX_TMDS_CLK   (340 * 1000 * 1000)
 
-static const char * const output_format_str[] = {
-   [VC4_HDMI_OUTPUT_RGB]   = "RGB",
-   [VC4_HDMI_OUTPUT_YUV420]= "YUV 4:2:0",
-   [VC4_HDMI_OUTPUT_YUV422]= "YUV 4:2:2",
-   [VC4_HDMI_OUTPUT_YUV444]= "YUV 4:4:4",
-};
-
-static const char *vc4_hdmi_output_fmt_str(enum vc4_hdmi_output_format fmt)
-{
-   if (fmt >= ARRAY_SIZE(output_format_str))
-   return "invalid";
-
-   return output_format_str[fmt];
-}
-
-static unsigned long long
-vc4_hdmi_encoder_compute_mode_clock(const struct drm_display_mode *mode,
-   unsigned int bpc, enum 
vc4_hdmi_output_format fmt);
-
 static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi *vc4_hdmi)
 {
struct drm_display_info *display = _hdmi->connector.display_info;
 
lockdep_assert_held(_hdmi->mutex);
@@ -145,32 +127,17 @@ static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi 
*vc4_hdmi)
return true;
 }
 
 static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode,
   unsigned int bpc,
-  enum vc4_hdmi_output_format fmt)
+  enum hdmi_colorspace fmt)
 {
-   unsigned long long clock = vc4_hdmi_encoder_compute_mode_clock(mode, 
bpc, fmt);
+   unsigned long long clock = drm_hdmi_compute_mode_clock(mode, bpc, fmt);
 
return clock > HDMI_14_MAX_TMDS_CLK;
 }
 
-static bool vc4_hdmi_is_full_range(struct vc4_hdmi *vc4_hdmi,
-  struct vc4_hdmi_connector_state *vc4_state)
-{
-   const struct drm_display_mode *mode = _hdmi->saved_adjusted_mode;
-   struct drm_display_info *display = _hdmi->connector.display_info;
-
-   if (vc4_state->broadcast_rgb == VC4_HDMI_BROADCAST_RGB_LIMITED)
-   return false;
-   else if (vc4_state->broadcast_rgb == VC4_HDMI_BROADCAST_RGB_FULL)
-   return true;
-
-   return !display->is_hdmi ||
-   drm_default_rgb_quant_range(mode) == 
HDMI_QUANTIZATION_RANGE_FULL;
-}
-
 static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
 {
struct drm_debugfs_entry *entry = m->private;
struct vc4_hdmi *vc4_hdmi = entry->file.data;
struct drm_device *drm = vc4_hdmi->connector.dev;
@@ -522,11 +489,11 @@ static int vc4_hdmi_connector_get_modes(struct 
drm_connector *connector)
if (!vc4->hvs->vc5_hdmi_enable_hdmi_20) {
struct drm_device *drm = connector->dev;
const struct drm_display_mode *mode;
 
list_for_each_entry(mode, >probed_modes, head) {
-   if (vc4_hdmi_mode_needs_scrambling(mode, 8, 
VC4_HDMI_OUTPUT_RGB)) {
+   if (vc4_hdmi_mode_needs_scrambling(mode, 8, 
HDMI_COLORSPACE_RGB)) {
drm_warn_once(drm, "The core clock cannot reach 
frequencies high enough to support 4k @ 60Hz.");
drm_warn_once(drm, "Please change your 
config.txt file to add hdmi_enable_4kp60.");
}
}
}
@@ -537,16 +504,12 @@ static int vc4_hdmi_connector_get_modes(struct 
drm_connector *connector)
 static int vc4_hdmi_connector_atomic_check(struct drm_connector *connecto

[PATCH v14 19/28] drm/connector: hdmi: Add RGB Quantization Range to the connector state

2024-05-21 Thread Maxime Ripard
HDMI controller drivers will need to figure out the RGB range they need
to configure based on a mode and property values. Let's expose that in
the HDMI connector state so drivers can just use that value.

Reviewed-by: Dave Stevenson 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/display/drm_hdmi_state_helper.c | 29 +
 drivers/gpu/drm/drm_atomic.c|  1 +
 include/drm/drm_connector.h |  6 +
 3 files changed, 36 insertions(+)

diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c 
b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 888fe1fe9594..6d30c47fca65 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -49,10 +49,37 @@ connector_state_get_mode(const struct drm_connector_state 
*conn_state)
return NULL;
 
return _state->mode;
 }
 
+static bool hdmi_is_limited_range(const struct drm_connector *connector,
+ const struct drm_connector_state *conn_state)
+{
+   const struct drm_display_info *info = >display_info;
+   const struct drm_display_mode *mode =
+   connector_state_get_mode(conn_state);
+
+   /*
+* The Broadcast RGB property only applies to RGB format, and
+* i915 just assumes limited range for YCbCr output, so let's
+* just do the same.
+*/
+   if (conn_state->hdmi.output_format != HDMI_COLORSPACE_RGB)
+   return true;
+
+   if (conn_state->hdmi.broadcast_rgb == DRM_HDMI_BROADCAST_RGB_FULL)
+   return false;
+
+   if (conn_state->hdmi.broadcast_rgb == DRM_HDMI_BROADCAST_RGB_LIMITED)
+   return true;
+
+   if (!info->is_hdmi)
+   return false;
+
+   return drm_default_rgb_quant_range(mode) == 
HDMI_QUANTIZATION_RANGE_LIMITED;
+}
+
 static bool
 sink_supports_format_bpc(const struct drm_connector *connector,
 const struct drm_display_info *info,
 const struct drm_display_mode *mode,
 unsigned int format, unsigned int bpc)
@@ -315,10 +342,12 @@ int drm_atomic_helper_connector_hdmi_check(struct 
drm_connector *connector,
drm_atomic_get_new_connector_state(state, connector);
const struct drm_display_mode *mode =
connector_state_get_mode(new_conn_state);
int ret;
 
+   new_conn_state->hdmi.is_limited_range = 
hdmi_is_limited_range(connector, new_conn_state);
+
ret = hdmi_compute_config(connector, new_conn_state, mode);
if (ret)
return ret;
 
if (old_conn_state->hdmi.broadcast_rgb != 
new_conn_state->hdmi.broadcast_rgb ||
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 3e57d98d8418..07b4b394e3bf 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1145,10 +1145,11 @@ static void drm_atomic_connector_print_state(struct 
drm_printer *p,
 
if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) {
drm_printf(p, "\tbroadcast_rgb=%s\n",
   
drm_hdmi_connector_get_broadcast_rgb_name(state->hdmi.broadcast_rgb));
+   drm_printf(p, "\tis_limited_range=%c\n", 
state->hdmi.is_limited_range ? 'y' : 'n');
drm_printf(p, "\toutput_bpc=%u\n", state->hdmi.output_bpc);
drm_printf(p, "\toutput_format=%s\n",
   
drm_hdmi_connector_get_output_format_name(state->hdmi.output_format));
drm_printf(p, "\ttmds_char_rate=%llu\n", 
state->hdmi.tmds_char_rate);
}
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index a40eaf3a8ce4..1fca26d51218 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1068,10 +1068,16 @@ struct drm_connector_state {
 * @broadcast_rgb: Connector property to pass the
 * Broadcast RGB selection value.
 */
enum drm_hdmi_broadcast_rgb broadcast_rgb;
 
+   /**
+* @is_full_range: Is the output supposed to use a full
+* RGB Quantization Range or not?
+*/
+   bool is_limited_range;
+
/**
 * @output_bpc: Bits per color channel to output.
 */
unsigned int output_bpc;
 

-- 
2.45.0



[PATCH v14 25/28] drm/vc4: tests: Remove vc4_dummy_plane structure

2024-05-21 Thread Maxime Ripard
The vc4_dummy_plane structure was introduced as a mean to add
mock-specific fields.

However, we never really used it and it's still strictly equivalent to
vc4_plane (which is in the same situation vs drm_plane), so we can
simply remove the vc4_dummy_plane structure and make the mock code
cleaner.

Reviewed-by: Maíra Canal 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/vc4/tests/vc4_mock.c   |  6 ++
 drivers/gpu/drm/vc4/tests/vc4_mock.h   |  9 ++---
 drivers/gpu/drm/vc4/tests/vc4_mock_plane.c | 14 +-
 3 files changed, 9 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.c 
b/drivers/gpu/drm/vc4/tests/vc4_mock.c
index becb3dbaa548..0731a7d85d7a 100644
--- a/drivers/gpu/drm/vc4/tests/vc4_mock.c
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock.c
@@ -107,20 +107,18 @@ static const struct vc4_mock_desc vc5_mock =
 );
 
 static int __build_one_pipe(struct kunit *test, struct drm_device *drm,
const struct vc4_mock_pipe_desc *pipe)
 {
-   struct vc4_dummy_plane *dummy_plane;
struct drm_plane *plane;
struct vc4_dummy_crtc *dummy_crtc;
struct drm_crtc *crtc;
unsigned int i;
 
-   dummy_plane = vc4_dummy_plane(test, drm, DRM_PLANE_TYPE_PRIMARY);
-   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_plane);
+   plane = vc4_dummy_plane(test, drm, DRM_PLANE_TYPE_PRIMARY);
+   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane);
 
-   plane = _plane->plane.base;
dummy_crtc = vc4_mock_pv(test, drm, plane, pipe->data);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_crtc);
 
crtc = _crtc->crtc.base;
for (i = 0; i < pipe->noutputs; i++) {
diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.h 
b/drivers/gpu/drm/vc4/tests/vc4_mock.h
index 2d0b339bd9f3..002b6218960c 100644
--- a/drivers/gpu/drm/vc4/tests/vc4_mock.h
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock.h
@@ -19,17 +19,12 @@ struct drm_crtc *vc4_find_crtc_for_encoder(struct kunit 
*test,
return crtc;
 
return NULL;
 }
 
-struct vc4_dummy_plane {
-   struct vc4_plane plane;
-};
-
-struct vc4_dummy_plane *vc4_dummy_plane(struct kunit *test,
-   struct drm_device *drm,
-   enum drm_plane_type type);
+struct drm_plane *vc4_dummy_plane(struct kunit *test, struct drm_device *drm,
+ enum drm_plane_type type);
 
 struct vc4_dummy_crtc {
struct vc4_crtc crtc;
 };
 
diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c 
b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c
index 62b18f5f41db..973f5f929097 100644
--- a/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c
@@ -20,28 +20,24 @@ static const struct drm_plane_funcs vc4_dummy_plane_funcs = 
{
 
 static const uint32_t vc4_dummy_plane_formats[] = {
DRM_FORMAT_XRGB,
 };
 
-struct vc4_dummy_plane *vc4_dummy_plane(struct kunit *test,
-   struct drm_device *drm,
-   enum drm_plane_type type)
+struct drm_plane *vc4_dummy_plane(struct kunit *test, struct drm_device *drm,
+ enum drm_plane_type type)
 {
-   struct vc4_dummy_plane *dummy_plane;
struct drm_plane *plane;
 
-   dummy_plane = drmm_universal_plane_alloc(drm,
-struct vc4_dummy_plane, 
plane.base,
+   plane = __drmm_universal_plane_alloc(drm, sizeof(struct drm_plane), 0,
 0,
 _dummy_plane_funcs,
 vc4_dummy_plane_formats,
 
ARRAY_SIZE(vc4_dummy_plane_formats),
 NULL,
 DRM_PLANE_TYPE_PRIMARY,
 NULL);
-   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_plane);
+   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane);
 
-   plane = _plane->plane.base;
drm_plane_helper_add(plane, _dummy_plane_helper_funcs);
 
-   return dummy_plane;
+   return plane;
 }

-- 
2.45.0



[PATCH v14 26/28] drm/vc4: tests: Convert to plane creation helper

2024-05-21 Thread Maxime Ripard
Now that we have a plane create helper for kunit mocked drivers, let's
convert to it in vc4.

Reviewed-by: Maíra Canal 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/vc4/tests/vc4_mock_plane.c | 34 +++---
 1 file changed, 8 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c 
b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c
index 973f5f929097..14357db82238 100644
--- a/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c
@@ -1,43 +1,25 @@
 // SPDX-License-Identifier: GPL-2.0
 
-#include 
-#include 
-#include 
+#include 
 #include 
 
 #include 
 
 #include "vc4_mock.h"
 
-static const struct drm_plane_helper_funcs vc4_dummy_plane_helper_funcs = {
-};
-
-static const struct drm_plane_funcs vc4_dummy_plane_funcs = {
-   .atomic_destroy_state   = drm_atomic_helper_plane_destroy_state,
-   .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
-   .reset  = drm_atomic_helper_plane_reset,
-};
-
-static const uint32_t vc4_dummy_plane_formats[] = {
-   DRM_FORMAT_XRGB,
-};
-
 struct drm_plane *vc4_dummy_plane(struct kunit *test, struct drm_device *drm,
  enum drm_plane_type type)
 {
struct drm_plane *plane;
 
-   plane = __drmm_universal_plane_alloc(drm, sizeof(struct drm_plane), 0,
-0,
-_dummy_plane_funcs,
-vc4_dummy_plane_formats,
-
ARRAY_SIZE(vc4_dummy_plane_formats),
-NULL,
-DRM_PLANE_TYPE_PRIMARY,
-NULL);
-   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane);
+   KUNIT_ASSERT_EQ(test, type, DRM_PLANE_TYPE_PRIMARY);
 
-   drm_plane_helper_add(plane, _dummy_plane_helper_funcs);
+   plane = drm_kunit_helper_create_primary_plane(test, drm,
+ NULL,
+ NULL,
+ NULL, 0,
+ NULL);
+   KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane);
 
return plane;
 }

-- 
2.45.0



[PATCH v14 18/28] drm/tests: Add tests for Broadcast RGB property

2024-05-21 Thread Maxime Ripard
This had a bunch of kunit tests to make sure our code to handle the
Broadcast RGB property behaves properly.

This requires bringing a bit of infrastructure to create mock HDMI
connectors, with custom EDIDs.

Reviewed-by: Dave Stevenson 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/tests/drm_connector_test.c | 116 
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 151 +
 2 files changed, 267 insertions(+)

diff --git a/drivers/gpu/drm/tests/drm_connector_test.c 
b/drivers/gpu/drm/tests/drm_connector_test.c
index 34d96f7fbb25..672b74bc9e23 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -564,10 +564,67 @@ static struct kunit_case 
drm_get_tv_mode_from_name_tests[] = {
 static struct kunit_suite drm_get_tv_mode_from_name_test_suite = {
.name = "drm_get_tv_mode_from_name",
.test_cases = drm_get_tv_mode_from_name_tests,
 };
 
+struct drm_hdmi_connector_get_broadcast_rgb_name_test {
+   unsigned int kind;
+   const char *expected_name;
+};
+
+#define BROADCAST_RGB_TEST(_kind, _name)   \
+   {   \
+   .kind = _kind,  \
+   .expected_name = _name, \
+   }
+
+static void drm_test_drm_hdmi_connector_get_broadcast_rgb_name(struct kunit 
*test)
+{
+   const struct drm_hdmi_connector_get_broadcast_rgb_name_test *params =
+   test->param_value;
+
+   KUNIT_EXPECT_STREQ(test,
+  
drm_hdmi_connector_get_broadcast_rgb_name(params->kind),
+  params->expected_name);
+}
+
+static const
+struct drm_hdmi_connector_get_broadcast_rgb_name_test
+drm_hdmi_connector_get_broadcast_rgb_name_valid_tests[] = {
+   BROADCAST_RGB_TEST(DRM_HDMI_BROADCAST_RGB_AUTO, "Automatic"),
+   BROADCAST_RGB_TEST(DRM_HDMI_BROADCAST_RGB_FULL, "Full"),
+   BROADCAST_RGB_TEST(DRM_HDMI_BROADCAST_RGB_LIMITED, "Limited 16:235"),
+};
+
+static void
+drm_hdmi_connector_get_broadcast_rgb_name_valid_desc(const struct 
drm_hdmi_connector_get_broadcast_rgb_name_test *t,
+char *desc)
+{
+   sprintf(desc, "%s", t->expected_name);
+}
+
+KUNIT_ARRAY_PARAM(drm_hdmi_connector_get_broadcast_rgb_name_valid,
+ drm_hdmi_connector_get_broadcast_rgb_name_valid_tests,
+ drm_hdmi_connector_get_broadcast_rgb_name_valid_desc);
+
+static void drm_test_drm_hdmi_connector_get_broadcast_rgb_name_invalid(struct 
kunit *test)
+{
+   KUNIT_EXPECT_NULL(test, drm_hdmi_connector_get_broadcast_rgb_name(3));
+};
+
+static struct kunit_case drm_hdmi_connector_get_broadcast_rgb_name_tests[] = {
+   KUNIT_CASE_PARAM(drm_test_drm_hdmi_connector_get_broadcast_rgb_name,
+
drm_hdmi_connector_get_broadcast_rgb_name_valid_gen_params),
+   KUNIT_CASE(drm_test_drm_hdmi_connector_get_broadcast_rgb_name_invalid),
+   { }
+};
+
+static struct kunit_suite drm_hdmi_connector_get_broadcast_rgb_name_test_suite 
= {
+   .name = "drm_hdmi_connector_get_broadcast_rgb_name",
+   .test_cases = drm_hdmi_connector_get_broadcast_rgb_name_tests,
+};
+
 struct drm_hdmi_connector_get_output_format_name_test {
unsigned int kind;
const char *expected_name;
 };
 
@@ -622,10 +679,67 @@ static struct kunit_case 
drm_hdmi_connector_get_output_format_name_tests[] = {
 static struct kunit_suite drm_hdmi_connector_get_output_format_name_test_suite 
= {
.name = "drm_hdmi_connector_get_output_format_name",
.test_cases = drm_hdmi_connector_get_output_format_name_tests,
 };
 
+static void drm_test_drm_connector_attach_broadcast_rgb_property(struct kunit 
*test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   struct drm_connector *connector = >connector;
+   struct drm_property *prop;
+   int ret;
+
+   ret = drmm_connector_init(>drm, connector,
+ _funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ >ddc);
+   KUNIT_ASSERT_EQ(test, ret, 0);
+
+   ret = drm_connector_attach_broadcast_rgb_property(connector);
+   KUNIT_ASSERT_EQ(test, ret, 0);
+
+   prop = connector->broadcast_rgb_property;
+   KUNIT_ASSERT_NOT_NULL(test, prop);
+   KUNIT_EXPECT_NOT_NULL(test, drm_mode_obj_find_prop_id(>base, 
prop->base.id));
+}
+
+static void 
drm_test_drm_connector_attach_broadcast_rgb_property_hdmi_connector(struct 
kunit *test)
+{
+   struct drm_connector_init_priv *priv = test->priv;
+   struct drm_connector *connector = >connector;
+   struct drm_property *prop;
+   int ret;
+
+   ret = drmm_connector_hdmi_init(>drm, connector,
+  _funcs,
+  

[PATCH v14 27/28] drm/rockchip: inno_hdmi: Switch to HDMI connector

2024-05-21 Thread Maxime Ripard
The new HDMI connector infrastructure allows to remove some boilerplate,
especially to generate infoframes. Let's switch to it.

Reviewed-by: Heiko Stuebner 
Acked-by: Heiko Stuebner 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/rockchip/Kconfig   |   3 +
 drivers/gpu/drm/rockchip/inno_hdmi.c   | 172 -
 drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c |   3 +
 3 files changed, 69 insertions(+), 109 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 1bf3e2829cd0..7df875e38517 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -72,10 +72,13 @@ config ROCKCHIP_DW_MIPI_DSI
  enable MIPI DSI on RK3288 or RK3399 based SoC, you should
  select this option.
 
 config ROCKCHIP_INNO_HDMI
bool "Rockchip specific extensions for Innosilicon HDMI"
+   select DRM_DISPLAY_HDMI_HELPER
+   select DRM_DISPLAY_HDMI_STATE_HELPER
+   select DRM_DISPLAY_HELPER
help
  This selects support for Rockchip SoC specific extensions
  for the Innosilicon HDMI driver. If you want to enable
  HDMI on RK3036 based SoC, you should select this option.
 
diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c 
b/drivers/gpu/drm/rockchip/inno_hdmi.c
index 3df2cfcf9998..2241e53a2946 100644
--- a/drivers/gpu/drm/rockchip/inno_hdmi.c
+++ b/drivers/gpu/drm/rockchip/inno_hdmi.c
@@ -20,10 +20,13 @@
 #include 
 #include 
 #include 
 #include 
 
+#include 
+#include 
+
 #include "rockchip_drm_drv.h"
 
 #include "inno_hdmi.h"
 
 #define INNO_HDMI_MIN_TMDS_CLOCK  2500U
@@ -65,13 +68,11 @@ struct inno_hdmi {
const struct inno_hdmi_variant *variant;
 };
 
 struct inno_hdmi_connector_state {
struct drm_connector_state  base;
-   unsigned intenc_out_format;
unsigned intcolorimetry;
-   boolrgb_limited_range;
 };
 
 static struct inno_hdmi *encoder_to_inno_hdmi(struct drm_encoder *encoder)
 {
struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
@@ -255,90 +256,53 @@ static void inno_hdmi_reset(struct inno_hdmi *hdmi)
hdmi_modb(hdmi, HDMI_SYS_CTRL, msk, val);
 
inno_hdmi_standby(hdmi);
 }
 
-static void inno_hdmi_disable_frame(struct inno_hdmi *hdmi,
-   enum hdmi_infoframe_type type)
+static int inno_hdmi_disable_frame(struct drm_connector *connector,
+  enum hdmi_infoframe_type type)
 {
-   struct drm_connector *connector = >connector;
-
-   if (type != HDMI_INFOFRAME_TYPE_AVI) {
-   drm_err(connector->dev,
-   "Unsupported infoframe type: %u\n", type);
-   return;
-   }
-
-   hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI);
-}
-
-static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi,
- union hdmi_infoframe *frame, enum 
hdmi_infoframe_type type)
-{
-   struct drm_connector *connector = >connector;
-   u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE];
-   ssize_t rc, i;
+   struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector);
 
if (type != HDMI_INFOFRAME_TYPE_AVI) {
drm_err(connector->dev,
"Unsupported infoframe type: %u\n", type);
return 0;
}
 
-   inno_hdmi_disable_frame(hdmi, type);
+   hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI);
 
-   rc = hdmi_infoframe_pack(frame, packed_frame,
-sizeof(packed_frame));
-   if (rc < 0)
-   return rc;
+   return 0;
+}
 
-   for (i = 0; i < rc; i++)
+static int inno_hdmi_upload_frame(struct drm_connector *connector,
+ enum hdmi_infoframe_type type,
+ const u8 *buffer, size_t len)
+{
+   struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector);
+   u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE];
+   ssize_t i;
+
+   if (type != HDMI_INFOFRAME_TYPE_AVI) {
+   drm_err(connector->dev,
+   "Unsupported infoframe type: %u\n", type);
+   return 0;
+   }
+
+   inno_hdmi_disable_frame(connector, type);
+
+   for (i = 0; i < len; i++)
hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_ADDR + i,
packed_frame[i]);
 
return 0;
 }
 
-static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi,
- struct drm_display_mode *mode)
-{
-   struct drm_connector *connector = >connector;
-   struct drm_connector_state *conn_state = connector->state;
-   struct inno_hdmi_connector_state *inno_conn_state =
-   to_inno_hdm

[PATCH v14 15/28] drm/connector: hdmi: Compute bpc and format automatically

2024-05-21 Thread Maxime Ripard
Now that we have all the infrastructure needed, we can add some code
that will, for a given connector state and mode, compute the best output
format and bpc.

The algorithm is equivalent to the one already found in i915 and vc4.

Cc: Ville Syrjälä 
Signed-off-by: Maxime Ripard 
---
 drivers/gpu/drm/display/drm_hdmi_state_helper.c| 205 -
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c |  25 ++-
 2 files changed, 218 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c 
b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 063421835dba..93cb30dba86e 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -1,9 +1,11 @@
 // SPDX-License-Identifier: MIT
 
 #include 
 #include 
+#include 
+#include 
 
 #include 
 #include 
 
 /**
@@ -46,10 +48,118 @@ connector_state_get_mode(const struct drm_connector_state 
*conn_state)
return NULL;
 
return _state->mode;
 }
 
+static bool
+sink_supports_format_bpc(const struct drm_connector *connector,
+const struct drm_display_info *info,
+const struct drm_display_mode *mode,
+unsigned int format, unsigned int bpc)
+{
+   struct drm_device *dev = connector->dev;
+   u8 vic = drm_match_cea_mode(mode);
+
+   /*
+* CTA-861-F, section 5.4 - Color Coding & Quantization states
+* that the bpc must be 8, 10, 12 or 16 except for the default
+* 640x480 VIC1 where the value must be 8.
+*
+* The definition of default here is ambiguous but the spec
+* refers to VIC1 being the default timing in several occasions
+* so our understanding is that for the default timing (ie,
+* VIC1), the bpc must be 8.
+*/
+   if (vic == 1 && bpc != 8) {
+   drm_dbg_kms(dev, "VIC1 requires a bpc of 8, got %u\n", bpc);
+   return false;
+   }
+
+   if (!info->is_hdmi &&
+   (format != HDMI_COLORSPACE_RGB || bpc != 8)) {
+   drm_dbg_kms(dev, "DVI Monitors require an RGB output at 8 
bpc\n");
+   return false;
+   }
+
+   if (!(connector->hdmi.supported_formats & BIT(format))) {
+   drm_dbg_kms(dev, "%s format unsupported by the connector.\n",
+   drm_hdmi_connector_get_output_format_name(format));
+   return false;
+   }
+
+   switch (format) {
+   case HDMI_COLORSPACE_RGB:
+   drm_dbg_kms(dev, "RGB Format, checking the constraints.\n");
+
+   /*
+* In some cases, like when the EDID readout fails, or
+* is not an HDMI compliant EDID for some reason, the
+* color_formats field will be blank and not report any
+* format supported. In such a case, assume that RGB is
+* supported so we can keep things going and light up
+* the display.
+*/
+   if (!(info->color_formats & DRM_COLOR_FORMAT_RGB444))
+   drm_warn(dev, "HDMI Sink doesn't support RGB, 
something's wrong.\n");
+
+   if (bpc == 10 && !(info->edid_hdmi_rgb444_dc_modes & 
DRM_EDID_HDMI_DC_30)) {
+   drm_dbg_kms(dev, "10 BPC but sink doesn't support Deep 
Color 30.\n");
+   return false;
+   }
+
+   if (bpc == 12 && !(info->edid_hdmi_rgb444_dc_modes & 
DRM_EDID_HDMI_DC_36)) {
+   drm_dbg_kms(dev, "12 BPC but sink doesn't support Deep 
Color 36.\n");
+   return false;
+   }
+
+   drm_dbg_kms(dev, "RGB format supported in that 
configuration.\n");
+
+   return true;
+
+   case HDMI_COLORSPACE_YUV422:
+   drm_dbg_kms(dev, "YUV422 format, checking the constraints.\n");
+
+   if (!(info->color_formats & DRM_COLOR_FORMAT_YCBCR422)) {
+   drm_dbg_kms(dev, "Sink doesn't support YUV422.\n");
+   return false;
+   }
+
+   if (bpc != 12) {
+   drm_dbg_kms(dev, "YUV422 only supports 12 bpc.\n");
+   return false;
+   }
+
+   drm_dbg_kms(dev, "YUV422 format supported in that 
configuration.\n");
+
+   return true;
+
+   case HDMI_COLORSPACE_YUV444:
+   drm_dbg_kms(dev, "YUV444 format, checking the constraints.\n");
+
+   if (!(info->color_formats & DRM_COLOR_FORMAT_YCBCR444)) {
+   drm_dbg_kms(dev, "Sink doesn't support YUV444.\n");
+ 

  1   2   3   4   5   6   7   8   9   10   >