Re: [RFC PATCH v4 31/42] drm/amd/display: Add support for sRGB EOTF in DEGAM block

2024-05-21 Thread Melissa Wen
On 05/21, Melissa Wen wrote:
> On 02/26, Harry Wentland wrote:
> > From: Alex Hung 
> > 
> > Expose one 1D curve colorop with support for
> > DRM_COLOROP_1D_CURVE_SRGB_EOTF and program HW to perform
> > the sRGB transform when the colorop is not in bypass.
> > 
> > With this change the following IGT test passes:
> > kms_colorop --run plane-XR30-XR30-srgb_eotf
> > 
> > The color pipeline now consists of a single colorop:
> > 1. 1D curve colorop w/ sRGB EOTF
> > 
> > Signed-off-by: Alex Hung 
> > Signed-off-by: Harry Wentland 
> > Co-developed-by: Harry Wentland 
> > ---
> >  .../gpu/drm/amd/display/amdgpu_dm/Makefile|  3 +-
> >  .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 88 +++
> >  .../amd/display/amdgpu_dm/amdgpu_dm_colorop.c | 58 
> >  .../amd/display/amdgpu_dm/amdgpu_dm_colorop.h | 34 +++
> >  .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 10 +++
> >  5 files changed, 192 insertions(+), 1 deletion(-)
> >  create mode 100644 
> > drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
> >  create mode 100644 
> > drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.h
> > 
> > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile 
> > b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
> > index ab2a97e354da..46158d67ab12 100644
> > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
> > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
> > @@ -38,7 +38,8 @@ AMDGPUDM = \
> > amdgpu_dm_pp_smu.o \
> > amdgpu_dm_psr.o \
> > amdgpu_dm_replay.o \
> > -   amdgpu_dm_wb.o
> > +   amdgpu_dm_wb.o \
> > +   amdgpu_dm_colorop.o
> >  
> >  ifdef CONFIG_DRM_AMD_DC_FP
> >  AMDGPUDM += dc_fpu.o
> > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
> > b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
> > index 9b527bffe11a..3ec759934669 100644
> > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
> > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
> > @@ -668,6 +668,19 @@ amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf)
> > }
> >  }
> >  
> > +static enum dc_transfer_func_predefined
> > +amdgpu_colorop_tf_to_dc_tf(enum drm_colorop_curve_1d_type tf)
> > +{
> > +   switch (tf)
> > +   {
> > +   case DRM_COLOROP_1D_CURVE_SRGB_EOTF:
> > +   case DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF:
> > +   return TRANSFER_FUNCTION_SRGB;
> > +   default:
> > +   return TRANSFER_FUNCTION_LINEAR;;
Nitpick: double `;` 

> > +   }
> > +}
> > +
> >  static void __to_dc_lut3d_color(struct dc_rgb *rgb,
> > const struct drm_color_lut lut,
> > int bit_precision)
> > @@ -1137,6 +1150,59 @@ __set_dm_plane_degamma(struct drm_plane_state 
> > *plane_state,
> > return 0;
> >  }
> >  
> > +static int
> > +__set_colorop_in_tf_1d_curve(struct dc_plane_state *dc_plane_state,
> > +  struct drm_colorop_state *colorop_state)
> > +{
> > +   struct dc_transfer_func *tf = dc_plane_state->in_transfer_func;
> 
> For this patch and the next two, it ^ should be:
> `_plane_state->in_transfer_func` (same for shape and blend), right?
> 
> > +   struct drm_colorop *colorop = colorop_state->colorop;
> > +   struct drm_device *drm = colorop->dev;
> > +
> > +   if (colorop->type != DRM_COLOROP_1D_CURVE &&
> > +   colorop_state->curve_1d_type != DRM_COLOROP_1D_CURVE_SRGB_EOTF)
> > +   return -EINVAL;
> > +
> > +   if (colorop_state->bypass) {
> > +   tf->type = TF_TYPE_BYPASS;
> > +   tf->tf = TRANSFER_FUNCTION_LINEAR;
> > +   return 0;
> > +   }
> > +
> > +   drm_dbg(drm, "Degamma colorop with ID: %d\n", colorop->base.id);
> > +
> > +   tf->type = TF_TYPE_PREDEFINED;
> > +   tf->tf = amdgpu_colorop_tf_to_dc_tf(colorop_state->curve_1d_type);
> > +
> > +   return 0;
> > +}
> > +
> > +static int
> > +__set_dm_plane_colorop_degamma(struct drm_plane_state *plane_state,
> > +  struct dc_plane_state *dc_plane_state,
> > +  struct drm_colorop *colorop)
> > +{
> > +   struct drm_colorop *old_colorop;
> > +   struct drm_colorop_state *colorop_state = NULL, *new_colorop_state;
> > +   struct drm_atomic_state *state = plane_state->state;
> > +   int i = 0;
> > +
> > 

Re: [RFC PATCH v4 00/42] Color Pipeline API w/ VKMS

2024-05-21 Thread Melissa Wen
On 02/26, Harry Wentland wrote:
> This is an RFC set for a color pipeline API, along with a sample
> implementation in VKMS. All the key API bits are here. VKMS now
> supports two named transfer function colorops and two matrix
> colorops. We have IGT tests that check all four of these colorops
> with a pixel-by-pixel comparison that checks that these colorops
> do what we expect them to do with a +/- 1 8 bpc code point margin.
> 
> The big new change with v4 is the addition of an amdgpu color
> pipeline, for all AMD GPUs with DCN 3 and newer. Amdgpu now support
> the following:
> 
> 1. 1D Curve EOTF
> 2. 3x4 CTM
> 3. Multiplier
> 4. 1D Curve Inverse EOTF
> 5. 1D LUT
> 6. 1D Curve EOTF
> 7. 1D LUT
> 
> The supported curves for the 1D Curve type are:
> - sRGB EOTF and its inverse
> - PQ EOTF, scaled to [0.0, 125.0] and its inverse
> - BT.2020/BT.709 OETF and its inverse
> 
> Note that the 1st and 5th colorops take the EOTF or Inverse
> OETF while the 3rd colorop takes the Inverse EOTF or OETF.
> 
> We are working on two more ops for amdgpu, the HDR multiplier
> and the 3DLUT, which will give us this:
> 
> 1. 1D Curve EOTF
> 2. 3x4 CTM
> 3. HDR Multiplier
> 4. 1D Curve Inverse EOTF
> 5. 1D LUT
> 6. 3D LUT
> 7. 1D Curve EOTF
> 8. 1D LUT
> 
> This, essentially mirrors the color pipeline used by gamescope
> and presented by Melissa Wen, with the exception of the DEGAM
> LUT, which is not currently used. See
> [1] 
> https://indico.freedesktop.org/event/4/contributions/186/attachments/138/218/xdc2023-TheRainbowTreasureMap-MelissaWen.pdf
> 
> After this we'd like to also add the following ops:
> - Scaler (Informational only)
> - Color Encoding, to replace drm_plane's COLOR_ENCODING
> - Color Range, to replace drm_plane's COLOR_RANGE
> 
> This patchset is grouped as follows:
>  - Patches 1-3: couple general patches/fixes
>  - Patches 4-7: introduce kunit to VKMS
>  - Patch 7: description of motivation and details behind the
> Color Pipeline API. If you're reading nothing else
> but are interested in the topic I highly recommend
> you take a look at this.
>  - Patches 7-27: DRM core and VKMS changes for color pipeline API
>  - Patches 28-40: DRM core and amdgpu changes for color pipeline API
> 
> VKMS patches could still be improved in a few ways, though the
> payoff might be limited and I would rather focus on other work
> at the moment. The most obvious thing to improve would be to
> eliminate the hard-coded LUTs for identity, and sRGB, and replace
> them with fixed-point math instead.
> 
> There are plenty of things that I would like to see here but
> haven't had a chance to look at. These will (hopefully) be
> addressed in future iterations, either in VKMS or amdgpu:
>  - Clear documentation for each drm_colorop_type
>  - Add custom LUT colorops to VKMS
>  - Add pre-blending 3DLUT
>  - How to support HW which can't bypass entire pipeline?
>  - Add ability to create colorops that don't have BYPASS
>  - Can we do a LOAD / COMMIT model for LUTs (and other properties)?
>  - read-only scaling colorop which defines scaling taps and position
>  - read-only color format colorop to define supported color formats
>for a pipeline
>  - named matrices, for things like converting YUV to RGB
> 
> IGT tests can be found at
> https://gitlab.freedesktop.org/hwentland/igt-gpu-tools/-/merge_requests/1
> 
> IGT patches are also being sent to the igt-dev mailing list.
> 
> If you prefer a gitlab MR for review you can find it at
> https://gitlab.freedesktop.org/hwentland/linux/-/merge_requests/5
> 
> v4:

Hey,

I'm not sure if this is the latest version, but this is the one I'm
using now. I just pointed out some minor issues that I found when
applying this series for testing, so I won't forget to report. But I'm
still performing tests and validations on my side.

Melissa

>  - Add amdgpu color pipeline (WIP)
>  - Don't block setting of deprecated properties, instead pass client cap
>to atomic check so drivers can ignore these props
>  - Drop IOCTL definitions (Pekka)
>  - Use enum property for colorop TYPE (Pekka)
>  - A few cleanups to the docs (Pekka)
>  - Rework the TYPE enum to name relation to avoid code duplication (Pekka)
>  - Add missing function declarations (Chaitanya Kumar Borah)
>  - Allow setting of NEXT property to NULL in _set_ function (Chaitanya Kumar 
> Borah)
>  - Add helper for creation of pipeline drm_plane property (Pekka)
>  - Always create Bypass pipeline (Pekka)
>  - A bunch of changes to VKMS kunit tests (Pekka)
>  - Fix index in CTM doc (Pekka)
> 
> v3:
>  - Abandon IOCTLs and discover colorops as clients iterate the pipeline
>  - Remove need for l

Re: [RFC PATCH v4 31/42] drm/amd/display: Add support for sRGB EOTF in DEGAM block

2024-05-21 Thread Melissa Wen
On 02/26, Harry Wentland wrote:
> From: Alex Hung 
> 
> Expose one 1D curve colorop with support for
> DRM_COLOROP_1D_CURVE_SRGB_EOTF and program HW to perform
> the sRGB transform when the colorop is not in bypass.
> 
> With this change the following IGT test passes:
> kms_colorop --run plane-XR30-XR30-srgb_eotf
> 
> The color pipeline now consists of a single colorop:
> 1. 1D curve colorop w/ sRGB EOTF
> 
> Signed-off-by: Alex Hung 
> Signed-off-by: Harry Wentland 
> Co-developed-by: Harry Wentland 
> ---
>  .../gpu/drm/amd/display/amdgpu_dm/Makefile|  3 +-
>  .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 88 +++
>  .../amd/display/amdgpu_dm/amdgpu_dm_colorop.c | 58 
>  .../amd/display/amdgpu_dm/amdgpu_dm_colorop.h | 34 +++
>  .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 10 +++
>  5 files changed, 192 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
>  create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.h
> 
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile 
> b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
> index ab2a97e354da..46158d67ab12 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
> @@ -38,7 +38,8 @@ AMDGPUDM = \
>   amdgpu_dm_pp_smu.o \
>   amdgpu_dm_psr.o \
>   amdgpu_dm_replay.o \
> - amdgpu_dm_wb.o
> + amdgpu_dm_wb.o \
> + amdgpu_dm_colorop.o
>  
>  ifdef CONFIG_DRM_AMD_DC_FP
>  AMDGPUDM += dc_fpu.o
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
> index 9b527bffe11a..3ec759934669 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
> @@ -668,6 +668,19 @@ amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf)
>   }
>  }
>  
> +static enum dc_transfer_func_predefined
> +amdgpu_colorop_tf_to_dc_tf(enum drm_colorop_curve_1d_type tf)
> +{
> + switch (tf)
> + {
> + case DRM_COLOROP_1D_CURVE_SRGB_EOTF:
> + case DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF:
> + return TRANSFER_FUNCTION_SRGB;
> + default:
> + return TRANSFER_FUNCTION_LINEAR;;
> + }
> +}
> +
>  static void __to_dc_lut3d_color(struct dc_rgb *rgb,
>   const struct drm_color_lut lut,
>   int bit_precision)
> @@ -1137,6 +1150,59 @@ __set_dm_plane_degamma(struct drm_plane_state 
> *plane_state,
>   return 0;
>  }
>  
> +static int
> +__set_colorop_in_tf_1d_curve(struct dc_plane_state *dc_plane_state,
> +struct drm_colorop_state *colorop_state)
> +{
> + struct dc_transfer_func *tf = dc_plane_state->in_transfer_func;

For this patch and the next two, it ^ should be:
`_plane_state->in_transfer_func` (same for shape and blend), right?

> + struct drm_colorop *colorop = colorop_state->colorop;
> + struct drm_device *drm = colorop->dev;
> +
> + if (colorop->type != DRM_COLOROP_1D_CURVE &&
> + colorop_state->curve_1d_type != DRM_COLOROP_1D_CURVE_SRGB_EOTF)
> + return -EINVAL;
> +
> + if (colorop_state->bypass) {
> + tf->type = TF_TYPE_BYPASS;
> + tf->tf = TRANSFER_FUNCTION_LINEAR;
> + return 0;
> + }
> +
> + drm_dbg(drm, "Degamma colorop with ID: %d\n", colorop->base.id);
> +
> + tf->type = TF_TYPE_PREDEFINED;
> + tf->tf = amdgpu_colorop_tf_to_dc_tf(colorop_state->curve_1d_type);
> +
> + return 0;
> +}
> +
> +static int
> +__set_dm_plane_colorop_degamma(struct drm_plane_state *plane_state,
> +struct dc_plane_state *dc_plane_state,
> +struct drm_colorop *colorop)
> +{
> + struct drm_colorop *old_colorop;
> + struct drm_colorop_state *colorop_state = NULL, *new_colorop_state;
> + struct drm_atomic_state *state = plane_state->state;
> + int i = 0;
> +
> + old_colorop = colorop;
> +
> + /* 1st op: 1d curve - degamma */
> + for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) {
> + if (new_colorop_state->colorop == old_colorop &&
> + new_colorop_state->curve_1d_type == 
> DRM_COLOROP_1D_CURVE_SRGB_EOTF) {
> + colorop_state = new_colorop_state;
> + break;
> + }
> + }
> +
> + if (!colorop_state)
> + return -EINVAL;
> +
> + return __set_colorop_in_tf_1d_curve(dc_plane_state, colorop_state);
> +}
> +
>  static int
>  amdgpu_dm_plane_set_color_properties(struct drm_plane_state *plane_state,
>struct dc_plane_state *dc_plane_state)
> @@ -1187,6 +1253,25 @@ amdgpu_dm_plane_set_color_properties(struct 
> drm_plane_state *plane_state,
>   return 0;
>  }
>  
> +static int
> +amdgpu_dm_plane_set_colorop_properties(struct 

Re: [RFC PATCH v4 41/42] drm/colorop: Add mutliplier type

2024-05-21 Thread Melissa Wen
On 02/26, Harry Wentland wrote:
> From: Alex Hung 
> 
> This introduces a new drm_colorop_type: DRM_COLOROP_MULTIPLIER.
> 
> It's a simple multiplier to all pixel values. The value is
> specified via a S31.32 fixed point provided via the
> "MULTIPLIER" property.
> 
> Signed-off-by: Alex Hung 
> ---
>  drivers/gpu/drm/drm_atomic.c  |  3 +++
>  drivers/gpu/drm/drm_atomic_uapi.c |  4 
>  drivers/gpu/drm/drm_colorop.c | 29 +++--
>  include/drm/drm_colorop.h | 16 
>  include/uapi/drm/drm_mode.h   |  1 +
>  5 files changed, 51 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index f7d51839ca03..af0b6338a55c 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -806,6 +806,9 @@ static void drm_atomic_colorop_print_state(struct 
> drm_printer *p,
>   case DRM_COLOROP_CTM_3X4:
>   drm_printf(p, "\tdata blob id=%d\n", state->data ? 
> state->data->base.id : 0);
>   break;
> + case DRM_COLOROP_MULTIPLIER:
> + drm_printf(p, "\tmultiplier=%u\n", state->multiplier);

Compiler complains of unsigned int instead of llu.

> + break;
>   default:
>   break;
>   }
> diff --git a/drivers/gpu/drm/drm_atomic_uapi.c 
> b/drivers/gpu/drm/drm_atomic_uapi.c
> index 6bfe857720cd..b4ecda563728 100644
> --- a/drivers/gpu/drm/drm_atomic_uapi.c
> +++ b/drivers/gpu/drm/drm_atomic_uapi.c
> @@ -727,6 +727,8 @@ static int drm_atomic_colorop_set_property(struct 
> drm_colorop *colorop,
>   state->bypass = val;
>   } else if (property == colorop->curve_1d_type_property) {
>   state->curve_1d_type = val;
> + } else if (property == colorop->multiplier_property) {
> + state->multiplier = val;
>   } else if (property == colorop->data_property) {
>   return drm_atomic_color_set_data_property(colorop,
>   state, property, val);
> @@ -752,6 +754,8 @@ drm_atomic_colorop_get_property(struct drm_colorop 
> *colorop,
>   *val = state->bypass;
>   } else if (property == colorop->curve_1d_type_property) {
>   *val = state->curve_1d_type;
> + } else if (property == colorop->multiplier_property) {
> + *val = state->multiplier;
>   } else if (property == colorop->size_property) {
>   *val = state->size;
>   } else if (property == colorop->data_property) {
> diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c
> index 4452eaeeb242..c6cdd743de51 100644
> --- a/drivers/gpu/drm/drm_colorop.c
> +++ b/drivers/gpu/drm/drm_colorop.c
> @@ -35,7 +35,8 @@
>  static const struct drm_prop_enum_list drm_colorop_type_enum_list[] = {
>   { DRM_COLOROP_1D_CURVE, "1D Curve" },
>   { DRM_COLOROP_1D_LUT, "1D Curve Custom LUT" },
> - { DRM_COLOROP_CTM_3X4, "3x4 Matrix"}
> + { DRM_COLOROP_CTM_3X4, "3x4 Matrix"},
> + { DRM_COLOROP_MULTIPLIER, "Multiplier"},
>  };
>  
>  static const char * const colorop_curve_1d_type_names[] = {
> @@ -231,6 +232,29 @@ int drm_colorop_ctm_3x4_init(struct drm_device *dev, 
> struct drm_colorop *colorop
>  }
>  EXPORT_SYMBOL(drm_colorop_ctm_3x4_init);
>  
> +int drm_colorop_mult_init(struct drm_device *dev, struct drm_colorop 
> *colorop,
> +   struct drm_plane *plane)
> +{
> + struct drm_property *prop;
> + int ret;
> +
> + ret = drm_colorop_init(dev, colorop, plane, DRM_COLOROP_MULTIPLIER);
> + if (ret)
> + return ret;
> +
> + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 
> "MULTIPLIER", 0, U64_MAX);
> + if (!prop)
> + return -ENOMEM;
> +
> + colorop->multiplier_property = prop;
> + drm_object_attach_property(>base, 
> colorop->multiplier_property, 0);
> +
> + drm_colorop_reset(colorop);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(drm_colorop_mult_init);
> +
>  static void __drm_atomic_helper_colorop_duplicate_state(struct drm_colorop 
> *colorop,
>   struct 
> drm_colorop_state *state)
>  {
> @@ -333,7 +357,8 @@ EXPORT_SYMBOL(drm_colorop_reset);
>  static const char * const colorop_type_name[] = {
>   [DRM_COLOROP_1D_CURVE] = "1D Curve",
>   [DRM_COLOROP_1D_LUT] = "1D Curve Custom LUT",
> - [DRM_COLOROP_CTM_3X4] = "3x4 Matrix"
> + [DRM_COLOROP_CTM_3X4] = "3x4 Matrix",
> + [DRM_COLOROP_MULTIPLIER] = "Multiplier",
>  };
>  
>  /**
> diff --git a/include/drm/drm_colorop.h b/include/drm/drm_colorop.h
> index 8adc7ece3bd1..f9f83644cc9f 100644
> --- a/include/drm/drm_colorop.h
> +++ b/include/drm/drm_colorop.h
> @@ -64,6 +64,13 @@ struct drm_colorop_state {
>*/
>   enum drm_colorop_curve_1d_type curve_1d_type;
>  
> + /**
> +  * @multiplier:
> +  *
> +  * Multiplier to 'gain' the plane. Format is S31.32 sign-magnitude.
> +  */

Re: [RFC PATCH v4 09/42] drm/colorop: Introduce new drm_colorop mode object

2024-05-21 Thread Melissa Wen
On 02/26, Harry Wentland wrote:
> This patches introduces a new drm_colorop mode object. This
> object represents color transformations and can be used to
> define color pipelines.
> 
> We also introduce the drm_colorop_state here, as well as
> various helpers and state tracking bits.
> 
> v4:
>  - Drop IOCTL definitions (Pekka)
>  - add missing declaration (Chaitanya Kumar Borah)
> 
> v3:
>  - Drop TODO for lock (it's handled in drm_modeset_drop_locks)
>(Melissa)
>  - Don't get plane state when getting colorop state
>  - Make some functions static (kernel test robot)
> 
> Signed-off-by: Harry Wentland 
> ---
>  drivers/gpu/drm/Makefile|   1 +
>  drivers/gpu/drm/drm_atomic.c|  70 
>  drivers/gpu/drm/drm_atomic_helper.c |  12 +++
>  drivers/gpu/drm/drm_atomic_uapi.c   |  48 +
>  drivers/gpu/drm/drm_colorop.c   | 152 ++
>  drivers/gpu/drm/drm_mode_config.c   |   7 ++
>  include/drm/drm_atomic.h|  82 +++
>  include/drm/drm_atomic_uapi.h   |   1 +
>  include/drm/drm_colorop.h   | 158 
>  include/drm/drm_mode_config.h   |  18 
>  include/drm/drm_plane.h |   2 +
>  include/uapi/drm/drm_mode.h |   1 +
>  12 files changed, 552 insertions(+)
>  create mode 100644 drivers/gpu/drm/drm_colorop.c
>  create mode 100644 include/drm/drm_colorop.h
> 
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 104b42df2e95..4b14dcbb6117 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -16,6 +16,7 @@ drm-y := \
>   drm_client.o \
>   drm_client_modeset.o \
>   drm_color_mgmt.o \
> + drm_colorop.o \
>   drm_connector.o \
>   drm_crtc.o \
>   drm_displayid.o \
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index a91737adf8e7..62e87e6a9653 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -42,6 +42,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  #include "drm_crtc_internal.h"
>  #include "drm_internal.h"
> @@ -108,6 +109,7 @@ void drm_atomic_state_default_release(struct 
> drm_atomic_state *state)
>   kfree(state->connectors);
>   kfree(state->crtcs);
>   kfree(state->planes);
> + kfree(state->colorops);
>   kfree(state->private_objs);
>  }
>  EXPORT_SYMBOL(drm_atomic_state_default_release);
> @@ -139,6 +141,10 @@ drm_atomic_state_init(struct drm_device *dev, struct 
> drm_atomic_state *state)
>   sizeof(*state->planes), GFP_KERNEL);
>   if (!state->planes)
>   goto fail;
> + state->colorops = kcalloc(dev->mode_config.num_colorop,
> +   sizeof(*state->colorops), GFP_KERNEL);
> + if (!state->colorops)
> + goto fail;
>  
>   /*
>* Because drm_atomic_state can be committed asynchronously we need our
> @@ -250,6 +256,20 @@ void drm_atomic_state_default_clear(struct 
> drm_atomic_state *state)
>   state->planes[i].new_state = NULL;
>   }
>  
> + for (i = 0; i < config->num_colorop; i++) {
> + struct drm_colorop *colorop = state->colorops[i].ptr;
> +
> + if (!colorop)
> + continue;
> +
> + drm_colorop_atomic_destroy_state(colorop,
> +  state->colorops[i].state);
> + state->colorops[i].ptr = NULL;
> + state->colorops[i].state = NULL;
> + state->colorops[i].old_state = NULL;
> + state->colorops[i].new_state = NULL;
> + }
> +
>   for (i = 0; i < state->num_private_objs; i++) {
>   struct drm_private_obj *obj = state->private_objs[i].ptr;
>  
> @@ -571,6 +591,56 @@ drm_atomic_get_plane_state(struct drm_atomic_state 
> *state,
>  }
>  EXPORT_SYMBOL(drm_atomic_get_plane_state);
>  
> +
> +/**
> + * drm_atomic_get_colorop_state - get colorop state
> + * @state: global atomic state object
> + * @colorop: colorop to get state object for
> + *
> + * This function returns the colorop state for the given colorop, allocating 
> it
> + * if needed. It will also grab the relevant plane lock to make sure that the
> + * state is consistent.
> + *
> + * Returns:
> + *
> + * Either the allocated state or the error code encoded into the pointer. 
> When
> + * the error is EDEADLK then the w/w mutex code has detected a deadlock and 
> the
> + * entire atomic sequence must be restarted. All other errors are fatal.
> + */
> +struct drm_colorop_state *
> +drm_atomic_get_colorop_state(struct drm_atomic_state *state,
> +  struct drm_colorop *colorop)
> +{
> + int ret, index = drm_colorop_index(colorop);
> + struct drm_colorop_state *colorop_state;
> +
> + WARN_ON(!state->acquire_ctx);
> +
> + colorop_state = drm_atomic_get_existing_colorop_state(state, colorop);
> + if (colorop_state)
> +  

Re: [PATCH 02/25] drm/amd/display: Add a function for checking tmds mode

2024-04-15 Thread Melissa Wen




On 10/04/2024 18:25, Rodrigo Siqueira wrote:

From: Chris Park 

[Why]
DVI is TMDS signal like HDMI but without audio.  Current signal check
does not correctly reflect DVI clock programming.

[How]
Define a new signal check for TMDS that includes DVI to HDMI TMDS
programming.

Reviewed-by: Dillon Varone 
Acked-by: Rodrigo Siqueira 
Signed-off-by: Chris Park 
---
  drivers/gpu/drm/amd/display/include/signal_types.h | 13 +
  1 file changed, 13 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/include/signal_types.h 
b/drivers/gpu/drm/amd/display/include/signal_types.h
index 1b14b17a79c7..a10d6b988aab 100644
--- a/drivers/gpu/drm/amd/display/include/signal_types.h
+++ b/drivers/gpu/drm/amd/display/include/signal_types.h
@@ -118,6 +118,19 @@ static inline bool dc_is_dvi_signal(enum signal_type 
signal)
}
  }
  
+static inline bool dc_is_tmds_signal(enum signal_type signal)

+{
+   switch (signal) {
+   case SIGNAL_TYPE_DVI_SINGLE_LINK:
+   case SIGNAL_TYPE_DVI_DUAL_LINK:
+   case SIGNAL_TYPE_HDMI_TYPE_A:
+   return true;
+   break;
+   default:
+   return false;
+   }
+}
+
  static inline bool dc_is_dvi_single_link_signal(enum signal_type signal)
  {
return (signal == SIGNAL_TYPE_DVI_SINGLE_LINK);

Is this patch complete? It creates a helper that isn't used anywhere (?)

BR,

Melissa



Re: [PATCH] drm/amd/display: Enable ogam_ram for dcn32+dcn35+dcn351

2024-04-15 Thread Melissa Wen
On 04/12, Harry Wentland wrote:
> 
> 
> On 2024-04-12 16:22, Harry Wentland wrote:
> > 
> > 
> > On 2024-04-12 12:26, Melissa Wen wrote:
> >> On 04/12, Joshua Ashton wrote:
> >>>
> >>>
> >>> On 4/11/24 3:26 PM, Melissa Wen wrote:
> >>>> On 04/10, Joshua Ashton wrote:
> >>>>> The comment here states "no OGAM in DPP since DCN1", yet that is not
> >>>>> true.
> >>>>>
> >>>>> Testing on an RX 7900XTX (dcn32), it actually does exist in hardware and
> >>>>> works fine.
> >>>>> My best guess is the comment is confused with OGAM ROM for DPP, rather
> >>>>> than OGAM RAM.
> >>>>>
> >>>>> I did not test dcn35/351 as I do not have that hardware, but I assume
> >>>>> the same follows there given the seemingly erroneous comment.
> >>>>> Someone at AMD should check that before merging this commit.
> >>>>
> >>>> hmm... I don't have any of these hw versions, but AFAIU if there is
> >>>> ogam/blend lut block in dcn32, the helper implementation for programming
> >>>> it properly (i.e. dpp_program_blnd_lut) is also missing here:
> >>>> - 
> >>>> https://gitlab.freedesktop.org/agd5f/linux/-/blob/amd-staging-drm-next/drivers/gpu/drm/amd/display/dc/dpp/dcn32/dcn32_dpp.c#L125
> >>>> right? So, it's good if AMD people can check it too.
> >>>>
> >>>> Melissa
> >>>
> >>> Hmm, yes. But, see dcn32_set_mcm_luts, that seems to handle per-plane 
> >>> blend
> >>> + shaper + 3D LUT state which is equivalent to what existed before?
> >>
> >> oh, cool! nice finding. blnd_lut is set on plane state, but programmed
> >> on MPC now.
> >>
> >> But I see the color pipeline changed in many stages from this version:
> >> - shaper + 3dlut before **or** after blending, but not before **and** 
> >> after?
> >> - where post-blending gamut_remap_matrix is located now in this
> >>   pipeline with mpcc postblend_1dlut and shaper+3dlut with mutable
> >>   position?
> >>   I guess something like:
> >>   - [shaper -> 3dlut -> blnd_lut] -> ctm -> regamma ??
> > 
> > [1dlut -> 3dlut -> 1dlut] is now a movable block, called Movable CM
> > (color management), or MCM for short. It can occur before blending or
> > after. Because of that it moved to MPC (multi-plane combiner).
> > 
> > If it's positioned for pre-blending it looks like this:
> > 
> > DPP -> MCM -> BLND -> Blending -> Gamut Remap -> Out Gam -> OPP -> ...
> > 
> > If it's positioned for post-blending it looks like this:
> > 
> > DPP -> BLND -> Blending -> MCM -> Gamut Remap -> Out Gam -> OPP
> > 
> > This is the case since DCN 3.2.
> > 
> > Because of that you don't have an ogam_ram in dpp anymore for DCN 3.2
> > and newer.
> > 
> >>>
> >>> Therefore, I think I am actually wrong with enabling the ogam_ram in DPP 
> >>> cap
> >>> here, and the right solution is to change the check for exposing the
> >>> property to account for these LUTs being available per-plane with mcm.
> >>>
> >>> (what is mcm btw...? lots of acronyms and stuff moving around in hw hehe)
> >>
> >> yes, shaper, 3dlut, blend_lut don't seem DPP caps anymore. MCM looks
> >> like a component of MPC, so I think we need new mpc.color caps to
> >> describe them properly (?)
> >>
> >> I also didn't find in the Linux/AMD glossary or code comment that
> >> describe what MCM is...
> >>
> >>>
> >>> What's a good way for us to check for that? Seems like the caps don't help
> >>> much there. We could check for the literal function ptr I guess...?
> >>>
> >>> What are your thoughts, Harry and Melissa?
> >>
> > 
> > I wonder if it makes sense to add an mcm cap to mpc_color_caps. Will need to
> > chat with some people about that.
> > 
> 
> I dug through the code a bit and talked with our resident expert. It looks
> like all the programming for in_shaper_func, lut_3d_func, and blend_tf should
> still work and assume a fixed pre-blending mcm, which is what we want.

Hi Harry,

Thank you for explaning the latest changes in the color pipeline.
Since MCM is fixed pre-blending in the current dcn32 driver:

1. I understand that the implementation for post-b

[PATCH] drm/amd/display: use mpcc_count to log MPC state

2024-04-12 Thread Melissa Wen
According to [1]:
```
DTN only logs 'pipe_count' instances of MPCC. However in some cases
there are different number of MPCC than DPP (pipe_count).
```

As DTN log still relies on pipe_count to print mpcc state, switch to
mpcc_count in all occurrences.

[1] https://lore.kernel.org/amd-gfx/20240328195047.2843715-39-roman...@amd.com/

Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c | 2 +-
 drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c | 2 +-
 drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c 
b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
index 3940f25f7d9f..088224571029 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
@@ -367,7 +367,7 @@ static void dcn10_log_color_state(struct dc *dc,
 dc->caps.color.dpp.ocsc);
 
DTN_INFO("MPCC:  OPP  DPP  MPCCBOT  MODE  ALPHA_MODE  PREMULT  
OVERLAP_ONLY  IDLE\n");
-   for (i = 0; i < pool->pipe_count; i++) {
+   for (i = 0; i < pool->mpcc_count; i++) {
struct mpcc_state s = {0};
 
pool->mpc->funcs->read_mpcc_state(pool->mpc, i, );
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c 
b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
index 87b43cb50c1e..a38333152654 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
@@ -155,7 +155,7 @@ void dcn20_log_color_state(struct dc *dc,
DTN_INFO("MPCC:  OPP  DPP  MPCCBOT  MODE  ALPHA_MODE  PREMULT  
OVERLAP_ONLY  IDLE"
 "  OGAM mode\n");
 
-   for (i = 0; i < pool->pipe_count; i++) {
+   for (i = 0; i < pool->mpcc_count; i++) {
struct mpcc_state s = {0};
 
pool->mpc->funcs->read_mpcc_state(pool->mpc, i, );
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c 
b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
index 40391dd16944..ed9141a67db3 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
@@ -166,7 +166,7 @@ void dcn30_log_color_state(struct dc *dc,
 "C21C22C23C24"
 "C31C32C33C34\n");
 
-   for (i = 0; i < pool->pipe_count; i++) {
+   for (i = 0; i < pool->mpcc_count; i++) {
struct mpcc_state s = {0};
 
pool->mpc->funcs->read_mpcc_state(pool->mpc, i, );
-- 
2.43.0



Re: [PATCH] drm/amd/display: Enable ogam_ram for dcn32+dcn35+dcn351

2024-04-12 Thread Melissa Wen
On 04/12, Joshua Ashton wrote:
> 
> 
> On 4/11/24 3:26 PM, Melissa Wen wrote:
> > On 04/10, Joshua Ashton wrote:
> > > The comment here states "no OGAM in DPP since DCN1", yet that is not
> > > true.
> > > 
> > > Testing on an RX 7900XTX (dcn32), it actually does exist in hardware and
> > > works fine.
> > > My best guess is the comment is confused with OGAM ROM for DPP, rather
> > > than OGAM RAM.
> > > 
> > > I did not test dcn35/351 as I do not have that hardware, but I assume
> > > the same follows there given the seemingly erroneous comment.
> > > Someone at AMD should check that before merging this commit.
> > 
> > hmm... I don't have any of these hw versions, but AFAIU if there is
> > ogam/blend lut block in dcn32, the helper implementation for programming
> > it properly (i.e. dpp_program_blnd_lut) is also missing here:
> > - 
> > https://gitlab.freedesktop.org/agd5f/linux/-/blob/amd-staging-drm-next/drivers/gpu/drm/amd/display/dc/dpp/dcn32/dcn32_dpp.c#L125
> > right? So, it's good if AMD people can check it too.
> > 
> > Melissa
> 
> Hmm, yes. But, see dcn32_set_mcm_luts, that seems to handle per-plane blend
> + shaper + 3D LUT state which is equivalent to what existed before?

oh, cool! nice finding. blnd_lut is set on plane state, but programmed
on MPC now.

But I see the color pipeline changed in many stages from this version:
- shaper + 3dlut before **or** after blending, but not before **and** after?
- where post-blending gamut_remap_matrix is located now in this
  pipeline with mpcc postblend_1dlut and shaper+3dlut with mutable
  position?
  I guess something like:
  - [shaper -> 3dlut -> blnd_lut] -> ctm -> regamma ??
> 
> Therefore, I think I am actually wrong with enabling the ogam_ram in DPP cap
> here, and the right solution is to change the check for exposing the
> property to account for these LUTs being available per-plane with mcm.
> 
> (what is mcm btw...? lots of acronyms and stuff moving around in hw hehe)

yes, shaper, 3dlut, blend_lut don't seem DPP caps anymore. MCM looks
like a component of MPC, so I think we need new mpc.color caps to
describe them properly (?)

I also didn't find in the Linux/AMD glossary or code comment that
describe what MCM is...

> 
> What's a good way for us to check for that? Seems like the caps don't help
> much there. We could check for the literal function ptr I guess...?
> 
> What are your thoughts, Harry and Melissa?

yeah, AFAIK color caps values are manually set and may contain
misleading information. I'm unsure that using function ptr would solve
the issue of having undocumented caps introduced to the color pipeline,
such as MCM, but your suggestion seems more reliable.

Anyway, the timing where the color pipeline was merged didn't help, but
if new caps and functions are not documented and the DM handles are not
updated accordingly, we will have the same issue in the future. 
For example, I see two new ptrs were introduced and implemented here:
- https://gitlab.freedesktop.org/agd5f/linux/-/commit/a820190204aef
- https://gitlab.freedesktop.org/agd5f/linux/-/commit/90f33674a0756
and we would need to update the DM color mgmt anyway to check these
new/unknown functions.

Seems okay if we check program_1dlut instead of ogam_ram caps, but what
should we do for dpp/mpc shaper+3d lut in set_mcm_luts? I mean, should
we enable plane or CRTC shaper+3dlut on DM? x_X

Anyway, thanks for all these findings!

I would like to hear more from AMD too.

Melissa

> 
> - Joshie ✨
> 
> > 
> > > 
> > > Signed-off-by: Joshua Ashton 
> > > 
> > > Cc: Harry Wentland 
> > > Cc: Xaver Hugl 
> > > Cc: Melissa Wen 
> > > Cc: Ethan Lee 
> > > ---
> > >   drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c  | 2 +-
> > >   drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c  | 2 +-
> > >   .../gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c| 2 +-
> > >   3 files changed, 3 insertions(+), 3 deletions(-)
> > > 
> > > diff --git 
> > > a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c 
> > > b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
> > > index 9aa39bd25be9..94f5d2b5aadf 100644
> > > --- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
> > > +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
> > > @@ -2182,7 +2182,7 @@ static bool dcn32_resource_construct(
> > >   dc->caps.color.dpp.dgam_rom_for_yuv = 0;
> > >   dc->caps.color.dpp.hw_3d_lut = 1;
> > > - dc->caps.color.dpp.ogam_ram = 0;  // no OGAM i

Re: [PATCH] Revert "drm/amd/display: Enable cur_rom_en even if cursor degamma is not enabled"

2024-04-11 Thread Melissa Wen
On 04/11, Rodrigo Siqueira wrote:
> This reverts commit 5aba567a2988400d4e01d44493c84bed92820d8d.
> 
> The original patch introduces cursor gamma issue to multiple
> Linux compositors. For this reason this commit reverts this change.

Thanks for checking the issue.

Reviewed-by: Melissa Wen 

> 
> Cc: Melissa Wen 
> Cc: Harry Wentland 
> Signed-off-by: Rodrigo Siqueira 
> ---
>  drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c 
> b/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c
> index ed1e2f65f5b5..f8c0cee34080 100644
> --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c
> +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c
> @@ -395,7 +395,9 @@ void dpp3_set_cursor_attributes(
>  
>   if (color_format == CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA ||
>   color_format == CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA) {
> - cur_rom_en = 1;
> + if 
> (cursor_attributes->attribute_flags.bits.ENABLE_CURSOR_DEGAMMA) {
> + cur_rom_en = 1;
> + }
>   }
>  
>   REG_UPDATE_3(CURSOR0_CONTROL,
> -- 
> 2.43.0
> 


Re: [PATCH] drm/amd/display: Enable ogam_ram for dcn32+dcn35+dcn351

2024-04-11 Thread Melissa Wen
On 04/10, Joshua Ashton wrote:
> The comment here states "no OGAM in DPP since DCN1", yet that is not
> true.
> 
> Testing on an RX 7900XTX (dcn32), it actually does exist in hardware and
> works fine.
> My best guess is the comment is confused with OGAM ROM for DPP, rather
> than OGAM RAM.
> 
> I did not test dcn35/351 as I do not have that hardware, but I assume
> the same follows there given the seemingly erroneous comment.
> Someone at AMD should check that before merging this commit.

hmm... I don't have any of these hw versions, but AFAIU if there is
ogam/blend lut block in dcn32, the helper implementation for programming
it properly (i.e. dpp_program_blnd_lut) is also missing here:
- 
https://gitlab.freedesktop.org/agd5f/linux/-/blob/amd-staging-drm-next/drivers/gpu/drm/amd/display/dc/dpp/dcn32/dcn32_dpp.c#L125
right? So, it's good if AMD people can check it too.

Melissa

> 
> Signed-off-by: Joshua Ashton 
> 
> Cc: Harry Wentland 
> Cc: Xaver Hugl 
> Cc: Melissa Wen 
> Cc: Ethan Lee 
> ---
>  drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c  | 2 +-
>  drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c  | 2 +-
>  .../gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c| 2 +-
>  3 files changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c 
> b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
> index 9aa39bd25be9..94f5d2b5aadf 100644
> --- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
> +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
> @@ -2182,7 +2182,7 @@ static bool dcn32_resource_construct(
>   dc->caps.color.dpp.dgam_rom_for_yuv = 0;
>  
>   dc->caps.color.dpp.hw_3d_lut = 1;
> - dc->caps.color.dpp.ogam_ram = 0;  // no OGAM in DPP since DCN1
> + dc->caps.color.dpp.ogam_ram = 1;
>   // no OGAM ROM on DCN2 and later ASICs
>   dc->caps.color.dpp.ogam_rom_caps.srgb = 0;
>   dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0;
> diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c 
> b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c
> index 25ac450944e7..708d63cc3f7f 100644
> --- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c
> +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c
> @@ -1861,7 +1861,7 @@ static bool dcn35_resource_construct(
>   dc->caps.color.dpp.dgam_rom_for_yuv = 0;
>  
>   dc->caps.color.dpp.hw_3d_lut = 1;
> - dc->caps.color.dpp.ogam_ram = 0;  // no OGAM in DPP since DCN1
> + dc->caps.color.dpp.ogam_ram = 1;
>   // no OGAM ROM on DCN301
>   dc->caps.color.dpp.ogam_rom_caps.srgb = 0;
>   dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0;
> diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c 
> b/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c
> index 8a57adb27264..053e8ec6d1ef 100644
> --- a/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c
> +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c
> @@ -1841,7 +1841,7 @@ static bool dcn351_resource_construct(
>   dc->caps.color.dpp.dgam_rom_for_yuv = 0;
>  
>   dc->caps.color.dpp.hw_3d_lut = 1;
> - dc->caps.color.dpp.ogam_ram = 0;  // no OGAM in DPP since DCN1
> + dc->caps.color.dpp.ogam_ram = 1;
>   // no OGAM ROM on DCN301
>   dc->caps.color.dpp.ogam_rom_caps.srgb = 0;
>   dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0;
> -- 
> 2.44.0
> 


Re: [RFC PATCH v3 0/6] drm/amd/display: switch amdgpu_dm_connector to use struct drm_edid

2024-04-08 Thread Melissa Wen
On 03/28, Jani Nikula wrote:
> On Wed, 27 Mar 2024, Melissa Wen  wrote:
> > 2. Most of the edid data handled by `dm_helpers_parse_edid_caps()` are
> >in drm_edid halpers, but there are still a few that are not managed by
> >them yet. For example:
> >```
> > edid_caps->serial_number = edid_buf->serial;
> > edid_caps->manufacture_week = edid_buf->mfg_week;
> > edid_caps->manufacture_year = edid_buf->mfg_year;
> >```
> >AFAIU I see the same pending issue in i915/pnpid_get_panel_type() -
> >that still uses drm_edid_raw().
> 
> See https://lore.kernel.org/r/cover.1711015462.git.jani.nik...@intel.com

Thanks!
I'll work on top of your series.

Melissa

> 
> BR,
> Jani.
> 
> 
> -- 
> Jani Nikula, Intel


Re: [RFC PATCH v3 3/6] drm/amd/display: switch amdgpu_dm_connector to use struct drm_edid

2024-04-08 Thread Melissa Wen
On 03/28, Jani Nikula wrote:
> On Wed, 27 Mar 2024, Melissa Wen  wrote:
> > Replace raw edid handling (struct edid) with the opaque EDID type
> > (struct drm_edid) on amdgpu_dm_connector for consistency. It may also
> > prevent mismatch of approaches in different parts of the driver code.
> > Working in progress. It was only exercised with IGT tests.
> >
> > v2: use const to fix warnings (Alex Hung)
> > v3: fix general protection fault on mst
> >
> > Signed-off-by: Melissa Wen 
> > ---
> >  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 99 +--
> >  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  4 +-
> >  .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  8 +-
> >  .../display/amdgpu_dm/amdgpu_dm_mst_types.c   | 24 ++---
> >  4 files changed, 67 insertions(+), 68 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
> > b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> > index 280562707cd0..bbbf9c9d40d5 100644
> > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> > @@ -3269,18 +3269,19 @@ void amdgpu_dm_update_connector_after_detect(
> > aconnector->dc_sink = sink;
> > dc_sink_retain(aconnector->dc_sink);
> > if (sink->dc_edid.length == 0) {
> > -   aconnector->edid = NULL;
> > +   drm_edid_free(aconnector->edid);
> 
> If aconnector->edid is used as some kind of cache, it might be prudent
> to still set it to NULL.

Makes sense. Thanks for pointing it out.
> 
> It's up to the amd maintainers, but personally I've renamed any ->edid
> fields to ->drm_edid when I've done these conversions to ensure every
> single place is covered, and also later stable backports will give a
> build failure if the change is not taken into account.

I see. Good points. I'll follow your advice and do this name change in
the next version.
> 
> > if (aconnector->dc_link->aux_mode) {
> > drm_dp_cec_unset_edid(
> > >dm_dp_aux.aux);
> > }
> > } else {
> > -   aconnector->edid =
> > -   (struct edid *)sink->dc_edid.raw_edid;
> > +   const struct edid *edid = (const struct edid 
> > *)sink->dc_edid.raw_edid;
> > +   aconnector->edid = drm_edid_alloc(edid, 
> > sink->dc_edid.length);
> >  
> > +   /* FIXME: Get rid of drm_edid_raw() */
> > if (aconnector->dc_link->aux_mode)
> > drm_dp_cec_set_edid(>dm_dp_aux.aux,
> > -   aconnector->edid);
> > +   
> > drm_edid_raw(aconnector->edid));
> 
> The goal should be to switch to use CEC functions that take the source
> physical address directly instead of parsing the EDID.

Yes, I understand I have the same goal as in the next patch:
- https://lore.kernel.org/dri-devel/20240327214953.367126-5-m...@igalia.com/

Am I missing something?

> 
> > }
> >  
> > if (!aconnector->timing_requested) {
> > @@ -3291,17 +3292,17 @@ void amdgpu_dm_update_connector_after_detect(
> > "failed to create 
> > aconnector->requested_timing\n");
> > }
> >  
> > -   drm_connector_update_edid_property(connector, aconnector->edid);
> > +   drm_edid_connector_update(connector, aconnector->edid);
> > amdgpu_dm_update_freesync_caps(connector, aconnector->edid);
> > update_connector_ext_caps(aconnector);
> > } else {
> > drm_dp_cec_unset_edid(>dm_dp_aux.aux);
> > amdgpu_dm_update_freesync_caps(connector, NULL);
> > -   drm_connector_update_edid_property(connector, NULL);
> > +   drm_edid_connector_update(connector, NULL);
> > aconnector->num_modes = 0;
> > dc_sink_release(aconnector->dc_sink);
> > aconnector->dc_sink = NULL;
> > -   aconnector->edid = NULL;
> > +   drm_edid_free(aconnector->edid);
> > kfree(aconnector->timing_requested);
> > aconnector->timing_requested = NULL;
> > /* Set CP to DESIRED if it was ENABLED, so we can re-enable it 
> > again on hotplug */
> > @@ -6661,13 +6662,

Re: [PATCH 30/43] drm/amd/display: Enable cur_rom_en even if cursor degamma is not enabled

2024-04-01 Thread Melissa Wen




On 28/03/2024 16:50, roman...@amd.com wrote:

From: Rodrigo Siqueira 

Signed-off-by: Rodrigo Siqueira 
Tested-by: Daniel Wheeler 
---
  drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c | 4 +---
  1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c 
b/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c
index f8c0cee34080..ed1e2f65f5b5 100644
--- a/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c
+++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.c
@@ -395,9 +395,7 @@ void dpp3_set_cursor_attributes(
  
  	if (color_format == CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA ||

color_format == CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA) {
-   if 
(cursor_attributes->attribute_flags.bits.ENABLE_CURSOR_DEGAMMA) {
-   cur_rom_en = 1;
-   }
+   cur_rom_en = 1;

ugh. At first glance, I think it will cause a regression with legacy gamma.

For references:
- https://gitlab.freedesktop.org/drm/amd/-/issues/1513
- https://lore.kernel.org/amd-gfx/20230731083505.1500965-1-m...@igalia.com/
- https://lore.kernel.org/amd-gfx/20230824133810.10627-1-m...@igalia.com/

BR,

Melissa

}
  
  	REG_UPDATE_3(CURSOR0_CONTROL,




Re: [PATCH 38/43] drm/amd/display: Fix MPCC DTN logging

2024-04-01 Thread Melissa Wen




On 28/03/2024 16:50, roman...@amd.com wrote:

From: Eric Bernstein 

[Why]
DTN only logs 'pipe_count' instances of MPCC.
However in some cases there are different number of
MPCC than DPP (pipe_count).

[How]
Add mpcc_count parameter to resource_pool and set it
during pool construction and use it for DTN logging of
MPCC state.
Should we do the same in dcn*_log_color_state() for the loop of 
`pool->mpx->funcs->read_mpcc_state()` there?


It affects the following files:
drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c

BR,

Melissa


Signed-off-by: Eric Bernstein 
Reviewed-by: Rodrigo Siqueira 
Tested-by: Daniel Wheeler 
---
  drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c 
b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c
index 9033b39e0e0c..c51b717e5622 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c
@@ -392,7 +392,7 @@ static unsigned int dcn10_get_mpcc_states(struct dc *dc, 
char *pBuf, unsigned in
remaining_buffer -= chars_printed;
pBuf += chars_printed;
  
-	for (i = 0; i < pool->pipe_count; i++) {

+   for (i = 0; i < pool->mpcc_count; i++) {
struct mpcc_state s = {0};
  
  		pool->mpc->funcs->read_mpcc_state(pool->mpc, i, );




[RFC PATCH v3 6/6] drm/amd/display: remove redundant freesync parser for DP

2024-03-27 Thread Melissa Wen
When updating connector under drm_edid infrastructure, many calculations
and validations are already done and become redundant inside AMD driver.
Remove those driver-specific code in favor of the DRM common code.

Signed-off-by: Melissa Wen 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 86 +--
 1 file changed, 4 insertions(+), 82 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index b3c396d626e9..7e0f93de27e6 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -10994,24 +10994,6 @@ static int amdgpu_dm_atomic_check(struct drm_device 
*dev,
return ret;
 }
 
-static bool is_dp_capable_without_timing_msa(struct dc *dc,
-struct amdgpu_dm_connector 
*amdgpu_dm_connector)
-{
-   u8 dpcd_data;
-   bool capable = false;
-
-   if (amdgpu_dm_connector->dc_link &&
-   dm_helpers_dp_read_dpcd(
-   NULL,
-   amdgpu_dm_connector->dc_link,
-   DP_DOWN_STREAM_PORT_COUNT,
-   _data,
-   sizeof(dpcd_data))) {
-   capable = (dpcd_data & DP_MSA_TIMING_PAR_IGNORED) ? true:false;
-   }
-
-   return capable;
-}
 
 static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm,
unsigned int offset,
@@ -11225,9 +11207,6 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
const struct drm_edid *drm_edid)
 {
int i = 0;
-   const struct detailed_timing *timing;
-   const struct detailed_non_pixel *data;
-   const struct detailed_data_monitor_range *range;
struct amdgpu_dm_connector *amdgpu_dm_connector =
to_amdgpu_dm_connector(connector);
struct dm_connector_state *dm_con_state = NULL;
@@ -11254,8 +11233,6 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
 
amdgpu_dm_connector->min_vfreq = 0;
amdgpu_dm_connector->max_vfreq = 0;
-   connector->display_info.monitor_range.min_vfreq = 0;
-   connector->display_info.monitor_range.max_vfreq = 0;
freesync_capable = false;
 
goto update;
@@ -11269,65 +11246,11 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw()
if (edid && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
 sink->sink_signal == SIGNAL_TYPE_EDP)) {
-   bool edid_check_required = false;
+   amdgpu_dm_connector->min_vfreq = 
connector->display_info.monitor_range.min_vfreq;
+   amdgpu_dm_connector->max_vfreq = 
connector->display_info.monitor_range.max_vfreq;
+   if (amdgpu_dm_connector->max_vfreq - 
amdgpu_dm_connector->min_vfreq > 10)
+   freesync_capable = true;
 
-   if (is_dp_capable_without_timing_msa(adev->dm.dc,
-amdgpu_dm_connector)) {
-   if (edid->features & DRM_EDID_FEATURE_CONTINUOUS_FREQ) {
-   freesync_capable = true;
-   amdgpu_dm_connector->min_vfreq = 
connector->display_info.monitor_range.min_vfreq;
-   amdgpu_dm_connector->max_vfreq = 
connector->display_info.monitor_range.max_vfreq;
-   } else {
-   edid_check_required = edid->version > 1 ||
- (edid->version == 1 &&
-  edid->revision > 1);
-   }
-   }
-
-   if (edid_check_required) {
-   for (i = 0; i < 4; i++) {
-
-   timing  = >detailed_timings[i];
-   data= >data.other_data;
-   range   = >data.range;
-   /*
-* Check if monitor has continuous frequency 
mode
-*/
-   if (data->type != EDID_DETAIL_MONITOR_RANGE)
-   continue;
-   /*
-* Check for flag range limits only. If flag == 
1 then
-* no additional timing information provided.
-* Default GTF, GTF Secondary curve and CVT are 
not
-* supported
- 

[RFC PATCH v3 5/6] drm/amd/display: always call connector_update when parsing freesync_caps

2024-03-27 Thread Melissa Wen
Update connector caps with drm_edid data before parsing info for
freesync.

Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index edc5418db5be..b3c396d626e9 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3292,13 +3292,11 @@ void amdgpu_dm_update_connector_after_detect(
"failed to create 
aconnector->requested_timing\n");
}
 
-   drm_edid_connector_update(connector, aconnector->edid);
amdgpu_dm_update_freesync_caps(connector, aconnector->edid);
update_connector_ext_caps(aconnector);
} else {
drm_dp_cec_unset_edid(>dm_dp_aux.aux);
amdgpu_dm_update_freesync_caps(connector, NULL);
-   drm_edid_connector_update(connector, NULL);
aconnector->num_modes = 0;
dc_sink_release(aconnector->dc_sink);
aconnector->dc_sink = NULL;
@@ -11249,6 +11247,8 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
amdgpu_dm_connector->dc_sink :
amdgpu_dm_connector->dc_em_sink;
 
+   drm_edid_connector_update(connector, drm_edid);
+
if (!drm_edid || !sink) {
dm_con_state = to_dm_connector_state(connector->state);
 
-- 
2.43.0



[RFC PATCH v3 4/6] drm/amd/display: switch to setting physical address directly

2024-03-27 Thread Melissa Wen
Connectors have source physical address available in display
info. Use drm_dp_cec_attach() to use it instead of parsing the EDID
again.

Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index bbbf9c9d40d5..edc5418db5be 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3277,11 +3277,11 @@ void amdgpu_dm_update_connector_after_detect(
} else {
const struct edid *edid = (const struct edid 
*)sink->dc_edid.raw_edid;
aconnector->edid = drm_edid_alloc(edid, 
sink->dc_edid.length);
+   drm_edid_connector_update(connector, aconnector->edid);
 
-   /* FIXME: Get rid of drm_edid_raw() */
if (aconnector->dc_link->aux_mode)
-   drm_dp_cec_set_edid(>dm_dp_aux.aux,
-   
drm_edid_raw(aconnector->edid));
+   drm_dp_cec_attach(>dm_dp_aux.aux,
+ 
connector->display_info.source_physical_address);
}
 
if (!aconnector->timing_requested) {
-- 
2.43.0



[RFC PATCH v3 3/6] drm/amd/display: switch amdgpu_dm_connector to use struct drm_edid

2024-03-27 Thread Melissa Wen
Replace raw edid handling (struct edid) with the opaque EDID type
(struct drm_edid) on amdgpu_dm_connector for consistency. It may also
prevent mismatch of approaches in different parts of the driver code.
Working in progress. It was only exercised with IGT tests.

v2: use const to fix warnings (Alex Hung)
v3: fix general protection fault on mst

Signed-off-by: Melissa Wen 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 99 +--
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  4 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  8 +-
 .../display/amdgpu_dm/amdgpu_dm_mst_types.c   | 24 ++---
 4 files changed, 67 insertions(+), 68 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 280562707cd0..bbbf9c9d40d5 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3269,18 +3269,19 @@ void amdgpu_dm_update_connector_after_detect(
aconnector->dc_sink = sink;
dc_sink_retain(aconnector->dc_sink);
if (sink->dc_edid.length == 0) {
-   aconnector->edid = NULL;
+   drm_edid_free(aconnector->edid);
if (aconnector->dc_link->aux_mode) {
drm_dp_cec_unset_edid(
>dm_dp_aux.aux);
}
} else {
-   aconnector->edid =
-   (struct edid *)sink->dc_edid.raw_edid;
+   const struct edid *edid = (const struct edid 
*)sink->dc_edid.raw_edid;
+   aconnector->edid = drm_edid_alloc(edid, 
sink->dc_edid.length);
 
+   /* FIXME: Get rid of drm_edid_raw() */
if (aconnector->dc_link->aux_mode)
drm_dp_cec_set_edid(>dm_dp_aux.aux,
-   aconnector->edid);
+   
drm_edid_raw(aconnector->edid));
}
 
if (!aconnector->timing_requested) {
@@ -3291,17 +3292,17 @@ void amdgpu_dm_update_connector_after_detect(
"failed to create 
aconnector->requested_timing\n");
}
 
-   drm_connector_update_edid_property(connector, aconnector->edid);
+   drm_edid_connector_update(connector, aconnector->edid);
amdgpu_dm_update_freesync_caps(connector, aconnector->edid);
update_connector_ext_caps(aconnector);
} else {
drm_dp_cec_unset_edid(>dm_dp_aux.aux);
amdgpu_dm_update_freesync_caps(connector, NULL);
-   drm_connector_update_edid_property(connector, NULL);
+   drm_edid_connector_update(connector, NULL);
aconnector->num_modes = 0;
dc_sink_release(aconnector->dc_sink);
aconnector->dc_sink = NULL;
-   aconnector->edid = NULL;
+   drm_edid_free(aconnector->edid);
kfree(aconnector->timing_requested);
aconnector->timing_requested = NULL;
/* Set CP to DESIRED if it was ENABLED, so we can re-enable it 
again on hotplug */
@@ -6661,13 +6662,7 @@ static void amdgpu_dm_connector_funcs_force(struct 
drm_connector *connector)
struct amdgpu_dm_connector *aconnector = 
to_amdgpu_dm_connector(connector);
struct dc_link *dc_link = aconnector->dc_link;
struct dc_sink *dc_em_sink = aconnector->dc_em_sink;
-   struct edid *edid;
-   struct i2c_adapter *ddc;
-
-   if (dc_link && dc_link->aux_mode)
-   ddc = >dm_dp_aux.aux.ddc;
-   else
-   ddc = >i2c->base;
+   const struct drm_edid *drm_edid;
 
/*
 * Note: drm_get_edid gets edid in the following order:
@@ -6675,18 +6670,20 @@ static void amdgpu_dm_connector_funcs_force(struct 
drm_connector *connector)
 * 2) firmware EDID if set via edid_firmware module parameter
 * 3) regular DDC read.
 */
-   edid = drm_get_edid(connector, ddc);
-   if (!edid) {
+   drm_edid = drm_edid_read(connector);
+
+   if (!drm_edid) {
DRM_ERROR("No EDID found on connector: %s.\n", connector->name);
return;
}
-
-   aconnector->edid = edid;
-
+   aconnector->edid = drm_edid;
+   drm_edid_connector_update(connector, drm_edid);
/* Update emulated (virtual) sink's EDID */
if (dc_em_sink && dc_link) {
+   const struct edid *edid = drm_edid_raw(drm_edid); // FIXME: Get 
rid of drm_edid_raw()
+
memset(_em_sink->edid_caps, 0, sizeo

[RFC PATCH v3 2/6] drm/amd/display: clean unused variables for hdmi freesync parser

2024-03-27 Thread Melissa Wen
Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 05ffe844b1fc..280562707cd0 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -11344,9 +11344,6 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
} else if (edid && sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) {
i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, _info);
if (i >= 0 && vsdb_info.freesync_supported) {
-   timing  = >detailed_timings[i];
-   data= >data.other_data;
-
amdgpu_dm_connector->min_vfreq = 
vsdb_info.min_refresh_rate_hz;
amdgpu_dm_connector->max_vfreq = 
vsdb_info.max_refresh_rate_hz;
if (amdgpu_dm_connector->max_vfreq - 
amdgpu_dm_connector->min_vfreq > 10)
-- 
2.43.0



[RFC PATCH v3 1/6] drm/amd/display: remove unused pixel_clock_mhz from amdgpu_dm_connector

2024-03-27 Thread Melissa Wen
We set pixel_clock_mhz when updating freesync caps, but it's not used
anywhere. Remove it.

Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 ---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 1 -
 2 files changed, 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index ef546932f6c9..05ffe844b1fc 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -11260,7 +11260,6 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
 
amdgpu_dm_connector->min_vfreq = 0;
amdgpu_dm_connector->max_vfreq = 0;
-   amdgpu_dm_connector->pixel_clock_mhz = 0;
connector->display_info.monitor_range.min_vfreq = 0;
connector->display_info.monitor_range.max_vfreq = 0;
freesync_capable = false;
@@ -11324,8 +11323,6 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,

connector->display_info.monitor_range.min_vfreq;
amdgpu_dm_connector->max_vfreq =

connector->display_info.monitor_range.max_vfreq;
-   amdgpu_dm_connector->pixel_clock_mhz =
-   range->pixel_clock_mhz * 10;
 
break;
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 09519b7abf67..67647bb5999b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -678,7 +678,6 @@ struct amdgpu_dm_connector {
 * value is set to zero when there is no FreeSync support.
 */
int max_vfreq ;
-   int pixel_clock_mhz;
 
/* Audio instance - protected by audio_lock. */
int audio_inst;
-- 
2.43.0



[RFC PATCH v3 0/6] drm/amd/display: switch amdgpu_dm_connector to use struct drm_edid

2024-03-27 Thread Melissa Wen
Hi,

After finding a null-pointer dereference when running
igt@kms_connector_force_edid (fixed by [1]), I started migrating raw
edid handles in amdgpu connectors to use opaque drm_edid and its
helpers.

However, I'm struggling to remove all drm_edid_raw() occurrences for
different reasons and, with this RFC, I'm looking for suggestions to
overcome them:
1. `dc_link` ops need a copy of edid data and size via `dc_sink`
   (basically, dc_link_add_remote_sink()). I'm unsure what a possible
   approach to clean dc_link helpers should be since it seems part of the
   shared code. Any suggestions?

2. Most of the edid data handled by `dm_helpers_parse_edid_caps()` are
   in drm_edid halpers, but there are still a few that are not managed by
   them yet. For example:
   ```
edid_caps->serial_number = edid_buf->serial;
edid_caps->manufacture_week = edid_buf->mfg_week;
edid_caps->manufacture_year = edid_buf->mfg_year;
   ```
   AFAIU I see the same pending issue in i915/pnpid_get_panel_type() -
   that still uses drm_edid_raw().

My suggestion is to keep the drm_edid_raw() around and verify if there
are no regressions or functional changes after this switch of
amdgpu_dm_connector to struct drm_edid. I added FIXME comments to all
drm_edid_raw occurrences to keep these pending issues on our radar. So
we can continue removing driver-specific code in favor of drm_edid
common code. What do you think?

This is the current status of drm_edid migration in this patchset:
- patch 1-2: remove unused variables found in this process.
- patch 3-4: migration of amdgpu_dm_connector from struct edid to struct
  drm_edid and its helpers.
- patch 5-6: remove duplicated code for parsing vrr caps. WIP: require
  more validation.

Additionally, it needs extensive testing and validation of a large
variety of display caps and I don't have the required setup for it
(perhaps you can test it in your CI to point issues?). I don't see how
to reduce the scope of changes to mitigate the noise/disruption, but any
suggestions are welcome.

[1] https://lore.kernel.org/amd-gfx/20240216122401.216860-1-m...@igalia.com/

Thanks,

Melissa

v1: https://lore.kernel.org/amd-gfx/20240126163429.56714-1-m...@igalia.com/
- use const to fix compilation warnings (Alex Hung)
- remove unused variables
- remove driver-specific parser for connector info in favor of drm_edid
  common code

v2: https://lore.kernel.org/amd-gfx/20240327165828.288792-1-m...@igalia.com/
- fix general protection fault on mst

Melissa Wen (6):
  drm/amd/display: remove unused pixel_clock_mhz from
amdgpu_dm_connector
  drm/amd/display: clean unused variables for hdmi freesync parser
  drm/amd/display: switch amdgpu_dm_connector to use struct drm_edid
  drm/amd/display: switch to setting physical address directly
  drm/amd/display: always call connector_update when parsing
freesync_caps
  drm/amd/display: remove redundant freesync parser for DP

 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 187 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   5 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |   8 +-
 .../display/amdgpu_dm/amdgpu_dm_mst_types.c   |  24 +--
 4 files changed, 69 insertions(+), 155 deletions(-)

-- 
2.43.0



[RFC PATCH v2 6/6] drm/amd/display: remove redundant freesync parser for DP

2024-03-27 Thread Melissa Wen
When updating connector under drm_edid infrastructure, many calculations
and validations are already done and become redundant inside AMD driver.
Remove those driver-specific code in favor of the DRM common code.

Signed-off-by: Melissa Wen 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 86 +--
 1 file changed, 4 insertions(+), 82 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index b3c396d626e9..7e0f93de27e6 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -10994,24 +10994,6 @@ static int amdgpu_dm_atomic_check(struct drm_device 
*dev,
return ret;
 }
 
-static bool is_dp_capable_without_timing_msa(struct dc *dc,
-struct amdgpu_dm_connector 
*amdgpu_dm_connector)
-{
-   u8 dpcd_data;
-   bool capable = false;
-
-   if (amdgpu_dm_connector->dc_link &&
-   dm_helpers_dp_read_dpcd(
-   NULL,
-   amdgpu_dm_connector->dc_link,
-   DP_DOWN_STREAM_PORT_COUNT,
-   _data,
-   sizeof(dpcd_data))) {
-   capable = (dpcd_data & DP_MSA_TIMING_PAR_IGNORED) ? true:false;
-   }
-
-   return capable;
-}
 
 static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm,
unsigned int offset,
@@ -11225,9 +11207,6 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
const struct drm_edid *drm_edid)
 {
int i = 0;
-   const struct detailed_timing *timing;
-   const struct detailed_non_pixel *data;
-   const struct detailed_data_monitor_range *range;
struct amdgpu_dm_connector *amdgpu_dm_connector =
to_amdgpu_dm_connector(connector);
struct dm_connector_state *dm_con_state = NULL;
@@ -11254,8 +11233,6 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
 
amdgpu_dm_connector->min_vfreq = 0;
amdgpu_dm_connector->max_vfreq = 0;
-   connector->display_info.monitor_range.min_vfreq = 0;
-   connector->display_info.monitor_range.max_vfreq = 0;
freesync_capable = false;
 
goto update;
@@ -11269,65 +11246,11 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw()
if (edid && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
 sink->sink_signal == SIGNAL_TYPE_EDP)) {
-   bool edid_check_required = false;
+   amdgpu_dm_connector->min_vfreq = 
connector->display_info.monitor_range.min_vfreq;
+   amdgpu_dm_connector->max_vfreq = 
connector->display_info.monitor_range.max_vfreq;
+   if (amdgpu_dm_connector->max_vfreq - 
amdgpu_dm_connector->min_vfreq > 10)
+   freesync_capable = true;
 
-   if (is_dp_capable_without_timing_msa(adev->dm.dc,
-amdgpu_dm_connector)) {
-   if (edid->features & DRM_EDID_FEATURE_CONTINUOUS_FREQ) {
-   freesync_capable = true;
-   amdgpu_dm_connector->min_vfreq = 
connector->display_info.monitor_range.min_vfreq;
-   amdgpu_dm_connector->max_vfreq = 
connector->display_info.monitor_range.max_vfreq;
-   } else {
-   edid_check_required = edid->version > 1 ||
- (edid->version == 1 &&
-  edid->revision > 1);
-   }
-   }
-
-   if (edid_check_required) {
-   for (i = 0; i < 4; i++) {
-
-   timing  = >detailed_timings[i];
-   data= >data.other_data;
-   range   = >data.range;
-   /*
-* Check if monitor has continuous frequency 
mode
-*/
-   if (data->type != EDID_DETAIL_MONITOR_RANGE)
-   continue;
-   /*
-* Check for flag range limits only. If flag == 
1 then
-* no additional timing information provided.
-* Default GTF, GTF Secondary curve and CVT are 
not
-* supported
- 

[RFC PATCH v2 5/6] drm/amd/display: always call connector_update when parsing freesync_caps

2024-03-27 Thread Melissa Wen
Update connector caps with drm_edid data before parsing info for
freesync.

Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index edc5418db5be..b3c396d626e9 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3292,13 +3292,11 @@ void amdgpu_dm_update_connector_after_detect(
"failed to create 
aconnector->requested_timing\n");
}
 
-   drm_edid_connector_update(connector, aconnector->edid);
amdgpu_dm_update_freesync_caps(connector, aconnector->edid);
update_connector_ext_caps(aconnector);
} else {
drm_dp_cec_unset_edid(>dm_dp_aux.aux);
amdgpu_dm_update_freesync_caps(connector, NULL);
-   drm_edid_connector_update(connector, NULL);
aconnector->num_modes = 0;
dc_sink_release(aconnector->dc_sink);
aconnector->dc_sink = NULL;
@@ -11249,6 +11247,8 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
amdgpu_dm_connector->dc_sink :
amdgpu_dm_connector->dc_em_sink;
 
+   drm_edid_connector_update(connector, drm_edid);
+
if (!drm_edid || !sink) {
dm_con_state = to_dm_connector_state(connector->state);
 
-- 
2.43.0



[RFC PATCH v2 4/6] drm/amd/display: switch to setting physical address directly

2024-03-27 Thread Melissa Wen
Connectors have source physical address available in display
info. Use drm_dp_cec_attach() to use it instead of parsing the EDID
again.

Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index bbbf9c9d40d5..edc5418db5be 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3277,11 +3277,11 @@ void amdgpu_dm_update_connector_after_detect(
} else {
const struct edid *edid = (const struct edid 
*)sink->dc_edid.raw_edid;
aconnector->edid = drm_edid_alloc(edid, 
sink->dc_edid.length);
+   drm_edid_connector_update(connector, aconnector->edid);
 
-   /* FIXME: Get rid of drm_edid_raw() */
if (aconnector->dc_link->aux_mode)
-   drm_dp_cec_set_edid(>dm_dp_aux.aux,
-   
drm_edid_raw(aconnector->edid));
+   drm_dp_cec_attach(>dm_dp_aux.aux,
+ 
connector->display_info.source_physical_address);
}
 
if (!aconnector->timing_requested) {
-- 
2.43.0



[RFC PATCH v2 3/6] drm/amd/display: switch amdgpu_dm_connector to use struct drm_edid

2024-03-27 Thread Melissa Wen
Replace raw edid handling (struct edid) with the opaque EDID type
(struct drm_edid) on amdgpu_dm_connector for consistency. It may also
prevent mismatch of approaches in different parts of the driver code.
Working in progress. It was only exercised with IGT tests.

v2: use const to fix warnings (Alex Hung)

Signed-off-by: Melissa Wen 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 99 +--
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  4 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  8 +-
 .../display/amdgpu_dm/amdgpu_dm_mst_types.c   | 28 +++---
 4 files changed, 69 insertions(+), 70 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 280562707cd0..bbbf9c9d40d5 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3269,18 +3269,19 @@ void amdgpu_dm_update_connector_after_detect(
aconnector->dc_sink = sink;
dc_sink_retain(aconnector->dc_sink);
if (sink->dc_edid.length == 0) {
-   aconnector->edid = NULL;
+   drm_edid_free(aconnector->edid);
if (aconnector->dc_link->aux_mode) {
drm_dp_cec_unset_edid(
>dm_dp_aux.aux);
}
} else {
-   aconnector->edid =
-   (struct edid *)sink->dc_edid.raw_edid;
+   const struct edid *edid = (const struct edid 
*)sink->dc_edid.raw_edid;
+   aconnector->edid = drm_edid_alloc(edid, 
sink->dc_edid.length);
 
+   /* FIXME: Get rid of drm_edid_raw() */
if (aconnector->dc_link->aux_mode)
drm_dp_cec_set_edid(>dm_dp_aux.aux,
-   aconnector->edid);
+   
drm_edid_raw(aconnector->edid));
}
 
if (!aconnector->timing_requested) {
@@ -3291,17 +3292,17 @@ void amdgpu_dm_update_connector_after_detect(
"failed to create 
aconnector->requested_timing\n");
}
 
-   drm_connector_update_edid_property(connector, aconnector->edid);
+   drm_edid_connector_update(connector, aconnector->edid);
amdgpu_dm_update_freesync_caps(connector, aconnector->edid);
update_connector_ext_caps(aconnector);
} else {
drm_dp_cec_unset_edid(>dm_dp_aux.aux);
amdgpu_dm_update_freesync_caps(connector, NULL);
-   drm_connector_update_edid_property(connector, NULL);
+   drm_edid_connector_update(connector, NULL);
aconnector->num_modes = 0;
dc_sink_release(aconnector->dc_sink);
aconnector->dc_sink = NULL;
-   aconnector->edid = NULL;
+   drm_edid_free(aconnector->edid);
kfree(aconnector->timing_requested);
aconnector->timing_requested = NULL;
/* Set CP to DESIRED if it was ENABLED, so we can re-enable it 
again on hotplug */
@@ -6661,13 +6662,7 @@ static void amdgpu_dm_connector_funcs_force(struct 
drm_connector *connector)
struct amdgpu_dm_connector *aconnector = 
to_amdgpu_dm_connector(connector);
struct dc_link *dc_link = aconnector->dc_link;
struct dc_sink *dc_em_sink = aconnector->dc_em_sink;
-   struct edid *edid;
-   struct i2c_adapter *ddc;
-
-   if (dc_link && dc_link->aux_mode)
-   ddc = >dm_dp_aux.aux.ddc;
-   else
-   ddc = >i2c->base;
+   const struct drm_edid *drm_edid;
 
/*
 * Note: drm_get_edid gets edid in the following order:
@@ -6675,18 +6670,20 @@ static void amdgpu_dm_connector_funcs_force(struct 
drm_connector *connector)
 * 2) firmware EDID if set via edid_firmware module parameter
 * 3) regular DDC read.
 */
-   edid = drm_get_edid(connector, ddc);
-   if (!edid) {
+   drm_edid = drm_edid_read(connector);
+
+   if (!drm_edid) {
DRM_ERROR("No EDID found on connector: %s.\n", connector->name);
return;
}
-
-   aconnector->edid = edid;
-
+   aconnector->edid = drm_edid;
+   drm_edid_connector_update(connector, drm_edid);
/* Update emulated (virtual) sink's EDID */
if (dc_em_sink && dc_link) {
+   const struct edid *edid = drm_edid_raw(drm_edid); // FIXME: Get 
rid of drm_edid_raw()
+
memset(_em_sink->edid_caps, 0, sizeof(struct dc_edid_caps));
- 

[RFC PATCH v2 2/6] drm/amd/display: clean unused variables for hdmi freesync parser

2024-03-27 Thread Melissa Wen
Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 05ffe844b1fc..280562707cd0 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -11344,9 +11344,6 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
} else if (edid && sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) {
i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, _info);
if (i >= 0 && vsdb_info.freesync_supported) {
-   timing  = >detailed_timings[i];
-   data= >data.other_data;
-
amdgpu_dm_connector->min_vfreq = 
vsdb_info.min_refresh_rate_hz;
amdgpu_dm_connector->max_vfreq = 
vsdb_info.max_refresh_rate_hz;
if (amdgpu_dm_connector->max_vfreq - 
amdgpu_dm_connector->min_vfreq > 10)
-- 
2.43.0



[RFC PATCH v2 1/6] drm/amd/display: remove unused pixel_clock_mhz from amdgpu_dm_connector

2024-03-27 Thread Melissa Wen
We set pixel_clock_mhz when updating freesync caps, but it's not used
anywhere. Remove it.

Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 ---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 1 -
 2 files changed, 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index ef546932f6c9..05ffe844b1fc 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -11260,7 +11260,6 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
 
amdgpu_dm_connector->min_vfreq = 0;
amdgpu_dm_connector->max_vfreq = 0;
-   amdgpu_dm_connector->pixel_clock_mhz = 0;
connector->display_info.monitor_range.min_vfreq = 0;
connector->display_info.monitor_range.max_vfreq = 0;
freesync_capable = false;
@@ -11324,8 +11323,6 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,

connector->display_info.monitor_range.min_vfreq;
amdgpu_dm_connector->max_vfreq =

connector->display_info.monitor_range.max_vfreq;
-   amdgpu_dm_connector->pixel_clock_mhz =
-   range->pixel_clock_mhz * 10;
 
break;
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 09519b7abf67..67647bb5999b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -678,7 +678,6 @@ struct amdgpu_dm_connector {
 * value is set to zero when there is no FreeSync support.
 */
int max_vfreq ;
-   int pixel_clock_mhz;
 
/* Audio instance - protected by audio_lock. */
int audio_inst;
-- 
2.43.0



[RFC PATCH v2 0/6] switch amdgpu_dm_connector to use struct drm_edid

2024-03-27 Thread Melissa Wen
Hi,

After finding a null-pointer dereference when running
igt@kms_connector_force_edid (fixed by [1]), I started migrating raw
edid handles in amdgpu connectors to use opaque drm_edid and its
helpers.

However, I'm struggling to remove all drm_edid_raw() occurrences for
different reasons and, with this RFC, I'm looking for suggestions to
overcome them:
1. `dc_link` ops need a copy of edid data and size via `dc_sink`
   (basically, dc_link_add_remote_sink()). I'm unsure what a possible
   approach to clean dc_link helpers should be since it seems part of the
   shared code. Any suggestions?

2. Most of the edid data handled by `dm_helpers_parse_edid_caps()` are
   in drm_edid halpers, but there are still a few that are not managed by
   them yet. For example:
   ```
edid_caps->serial_number = edid_buf->serial;
edid_caps->manufacture_week = edid_buf->mfg_week;
edid_caps->manufacture_year = edid_buf->mfg_year;
   ```
   AFAIU I see the same pending issue in i915/pnpid_get_panel_type() -
   that still uses drm_edid_raw().

My suggestion is to keep the drm_edid_raw() around and verify if there
are no regressions or functional changes after this switch of
amdgpu_dm_connector to struct drm_edid. I added FIXME comments to all
drm_edid_raw occurrences to keep these pending issues on our radar. So
we can continue removing driver-specific code in favor of drm_edid
common code. What do you think?

This is the current status of drm_edid migration in this patchset:
- patch 1-2: remove unused variables found in this process.
- patch 3-4: migration of amdgpu_dm_connector from struct edid to struct
  drm_edid and its helpers.
- patch 5-6: remove duplicated code for parsing vrr caps. WIP: require
  more validation.

Additionally, it needs extensive testing and validation of a large
variety of display caps and I don't have the required setup for it
(perhaps you can test it in your CI to point issues?). I don't see how
to reduce the scope of changes to mitigate the noise/disruption, but any
suggestions are welcome.

Thanks,

Melissa

Melissa Wen (6):
  drm/amd/display: remove unused pixel_clock_mhz from
amdgpu_dm_connector
  drm/amd/display: clean unused variables for hdmi freesync parser
  drm/amd/display: switch amdgpu_dm_connector to use struct drm_edid
  drm/amd/display: switch to setting physical address directly
  drm/amd/display: always call connector_update when parsing
freesync_caps
  drm/amd/display: remove redundant freesync parser for DP

 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 187 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   5 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |   8 +-
 .../display/amdgpu_dm/amdgpu_dm_mst_types.c   |  28 +--
 4 files changed, 71 insertions(+), 157 deletions(-)

-- 
2.43.0



Re: [RFC PATCH v4 01/42] drm: Don't treat 0 as -1 in drm_fixp2int_ceil

2024-03-14 Thread Melissa Wen
On 02/26, Harry Wentland wrote:
> Unit testing this in VKMS shows that passing 0 into
> this function returns -1, which is highly counter-
> intuitive. Fix it by checking whether the input is
> >= 0 instead of > 0.
> 
> Fixes: 64566b5e767f9 ("drm: Add drm_fixp_from_fraction and drm_fixp2int_ceil")
> Signed-off-by: Harry Wentland 
> Reviewed-by: Simon Ser 
> Reviewed-by: Melissa Wen 

It was already applied upstream:
https://cgit.freedesktop.org/drm/drm-misc/commit/include?id=cf8837d7204481026335461629b84ac7f4538fa5

Thanks

Melissa
> ---
>  include/drm/drm_fixed.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/include/drm/drm_fixed.h b/include/drm/drm_fixed.h
> index 6ea339d5de08..0c9f917a4d4b 100644
> --- a/include/drm/drm_fixed.h
> +++ b/include/drm/drm_fixed.h
> @@ -95,7 +95,7 @@ static inline int drm_fixp2int_round(s64 a)
>  
>  static inline int drm_fixp2int_ceil(s64 a)
>  {
> - if (a > 0)
> + if (a >= 0)
>   return drm_fixp2int(a + DRM_FIXED_ALMOST_ONE);
>   else
>   return drm_fixp2int(a - DRM_FIXED_ALMOST_ONE);
> -- 
> 2.44.0
> 


Re: [RFC PATCH v4 02/42] drm: Add helper for conversion from signed-magnitude

2024-03-14 Thread Melissa Wen
On 02/26, Harry Wentland wrote:
> CTM values are defined as signed-magnitude values. Add
> a helper that converts from CTM signed-magnitude fixed
> point value to the twos-complement value used by
> drm_fixed.
> 
> Signed-off-by: Harry Wentland 
> ---
>  include/drm/drm_fixed.h | 18 ++
>  1 file changed, 18 insertions(+)
> 
> diff --git a/include/drm/drm_fixed.h b/include/drm/drm_fixed.h
> index 0c9f917a4d4b..cb842ba80ddd 100644
> --- a/include/drm/drm_fixed.h
> +++ b/include/drm/drm_fixed.h
> @@ -78,6 +78,24 @@ static inline u32 dfixed_div(fixed20_12 A, fixed20_12 B)
>  #define DRM_FIXED_EPSILON1LL
>  #define DRM_FIXED_ALMOST_ONE (DRM_FIXED_ONE - DRM_FIXED_EPSILON)
>  
> +/**
> + * @drm_sm2fixp
> + *
> + * Convert a 1.31.32 signed-magnitude fixed point to 32.32
> + * 2s-complement fixed point
> + *
> + * @return s64 2s-complement fixed point
> + */
> +static inline s64 drm_sm2fixp(__u64 a)
> +{
> + if ((a & (1LL << 63))) {
> + return -(a & 0x7fffll);
Hi Harry,

Can we have a #define macro for this constant? ^
Other than that, LGTM. You can add my r-b to the next version.

Thanks,

Melissa
> + } else {
> + return a;
> + }
> +
> +}
> +
>  static inline s64 drm_int2fixp(int a)
>  {
>   return ((s64)a) << DRM_FIXED_POINT;
> -- 
> 2.44.0
> 


Re: [RFC PATCH v4 07/42] drm/vkms: Avoid reading beyond LUT array

2024-03-12 Thread Melissa Wen
On 02/26, Harry Wentland wrote:
> When the floor LUT index (drm_fixp2int(lut_index) is the last
> index of the array the ceil LUT index will point to an entry
> beyond the array. Make sure we guard against it and use the
> value of the floor LUT index.
> 
> v3:
>  - Drop bits from commit description that didn't contribute
>anything of value
> 
> Fixes: db1f254f2cfaf ("drm/vkms: Add support to 1D gamma LUT")
> Signed-off-by: Harry Wentland 
> Cc: Arthur Grillo 
> Reviewed-by: Melissa Wen 

Same. Already applied upstream:
https://cgit.freedesktop.org/drm/drm-misc/commit/drivers/gpu/drm?id=2fee84030d12d9fddfa874e4562d71761a129277

I guess you are working on top of asdn branch and it's okay to me.
I'm just mentioning to avoid confusion.

Melissa

> ---
>  drivers/gpu/drm/vkms/vkms_composer.c | 14 ++
>  1 file changed, 10 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/vkms/vkms_composer.c 
> b/drivers/gpu/drm/vkms/vkms_composer.c
> index d178f2a400f6..b90e446d5954 100644
> --- a/drivers/gpu/drm/vkms/vkms_composer.c
> +++ b/drivers/gpu/drm/vkms/vkms_composer.c
> @@ -123,6 +123,8 @@ static u16 apply_lut_to_channel_value(const struct 
> vkms_color_lut *lut, u16 chan
> enum lut_channel channel)
>  {
>   s64 lut_index = get_lut_index(lut, channel_value);
> + u16 *floor_lut_value, *ceil_lut_value;
> + u16 floor_channel_value, ceil_channel_value;
>  
>   /*
>* This checks if `struct drm_color_lut` has any gap added by the 
> compiler
> @@ -130,11 +132,15 @@ static u16 apply_lut_to_channel_value(const struct 
> vkms_color_lut *lut, u16 chan
>*/
>   static_assert(sizeof(struct drm_color_lut) == sizeof(__u16) * 4);
>  
> - u16 *floor_lut_value = (__u16 *)>base[drm_fixp2int(lut_index)];
> - u16 *ceil_lut_value = (__u16 *)>base[drm_fixp2int_ceil(lut_index)];
> + floor_lut_value = (__u16 *)>base[drm_fixp2int(lut_index)];
> + if (drm_fixp2int(lut_index) == (lut->lut_length - 1))
> + /* We're at the end of the LUT array, use same value for ceil 
> and floor */
> + ceil_lut_value = floor_lut_value;
> + else
> + ceil_lut_value = (__u16 
> *)>base[drm_fixp2int_ceil(lut_index)];
>  
> - u16 floor_channel_value = floor_lut_value[channel];
> - u16 ceil_channel_value = ceil_lut_value[channel];
> + floor_channel_value = floor_lut_value[channel];
> + ceil_channel_value = ceil_lut_value[channel];
>  
>   return lerp_u16(floor_channel_value, ceil_channel_value,
>   lut_index & DRM_FIXED_DECIMAL_MASK);
> -- 
> 2.44.0
> 


Re: [RFC PATCH v4 05/42] drm/vkms: Create separate Kconfig file for VKMS

2024-03-12 Thread Melissa Wen
On 02/26, Harry Wentland wrote:
> This aligns with most other DRM drivers and will allow
> us to add new VKMS config options without polluting
> the DRM Kconfig.
> 
> v3:
>  - Change SPDX to GPL-2.0-only to match DRM KConfig
>SPDX (Simon)
> 
> Signed-off-by: Harry Wentland 
> Reviewed-by: Simon Ser 

Just to let you know this patch is already upstream. I cherry-picked it
from the last patchset version and applied to drm-misc-next:
https://cgit.freedesktop.org/drm/drm-misc/commit/drivers/gpu/drm?id=ffcc67cd79ff2e93fd0bdb837c99cbab6c59d38c

Thanks again,

Melissa

> ---
>  drivers/gpu/drm/Kconfig  | 14 +-
>  drivers/gpu/drm/vkms/Kconfig | 15 +++
>  2 files changed, 16 insertions(+), 13 deletions(-)
>  create mode 100644 drivers/gpu/drm/vkms/Kconfig
> 
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 2520db0b776e..e3ea8793cb8a 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -289,19 +289,7 @@ config DRM_VGEM
> as used by Mesa's software renderer for enhanced performance.
> If M is selected the module will be called vgem.
>  
> -config DRM_VKMS
> - tristate "Virtual KMS (EXPERIMENTAL)"
> - depends on DRM && MMU
> - select DRM_KMS_HELPER
> - select DRM_GEM_SHMEM_HELPER
> - select CRC32
> - default n
> - help
> -   Virtual Kernel Mode-Setting (VKMS) is used for testing or for
> -   running GPU in a headless machines. Choose this option to get
> -   a VKMS.
> -
> -   If M is selected the module will be called vkms.
> +source "drivers/gpu/drm/vkms/Kconfig"
>  
>  source "drivers/gpu/drm/exynos/Kconfig"
>  
> diff --git a/drivers/gpu/drm/vkms/Kconfig b/drivers/gpu/drm/vkms/Kconfig
> new file mode 100644
> index ..b9ecdebecb0b
> --- /dev/null
> +++ b/drivers/gpu/drm/vkms/Kconfig
> @@ -0,0 +1,15 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +
> +config DRM_VKMS
> + tristate "Virtual KMS (EXPERIMENTAL)"
> + depends on DRM && MMU
> + select DRM_KMS_HELPER
> + select DRM_GEM_SHMEM_HELPER
> + select CRC32
> + default n
> + help
> +   Virtual Kernel Mode-Setting (VKMS) is used for testing or for
> +   running GPU in a headless machines. Choose this option to get
> +   a VKMS.
> +
> +   If M is selected the module will be called vkms.
> -- 
> 2.44.0
> 


Re: [PATCH 25/34] drm/amd/display: Set the power_down_on_boot function pointer to null

2024-03-07 Thread Melissa Wen
On 02/28, Mario Limonciello wrote:
> On 2/28/2024 12:39, Alex Hung wrote:
> > From: Muhammad Ahmed 
> > 
> > [WHY]
> > Blackscreen hang @ PC EF25 when trying to wake up from S0i3. DCN
> > gets powered off due to dc_power_down_on_boot() being called after
> > timeout.
> > 
> > [HOW]
> > Setting the power_down_on_boot function pointer to null since we don't
> > expect the function to be called for APU.
> 
> Perhaps, should we be making the same change for other APUs?

any follow-up to Mario's question?

I wonder if this can help solve other "black screen hangs after suspend"
reported for other APUs...

Melissa

> 
> It seems a few others call dcn10_power_down_on_boot() for the callback.
> 
> > 
> > Cc: Mario Limonciello 
> > Cc: Alex Deucher 
> > Cc: sta...@vger.kernel.org
> > Reviewed-by: Nicholas Kazlauskas 
> > Acked-by: Alex Hung 
> > Signed-off-by: Muhammad Ahmed 
> > ---
> >   drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c | 2 +-
> >   1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c 
> > b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
> > index dce620d359a6..d4e0abbef28e 100644
> > --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
> > +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
> > @@ -39,7 +39,7 @@
> >   static const struct hw_sequencer_funcs dcn35_funcs = {
> > .program_gamut_remap = dcn30_program_gamut_remap,
> > .init_hw = dcn35_init_hw,
> > -   .power_down_on_boot = dcn35_power_down_on_boot,
> > +   .power_down_on_boot = NULL,
> > .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
> > .apply_ctx_for_surface = NULL,
> > .program_front_end_for_ctx = dcn20_program_front_end_for_ctx,
> 


[PATCH] drm/amd/display: check dc_link before dereferencing

2024-02-27 Thread Melissa Wen
drivers/gpu/drm/amd/amdgpu/../display/amdgpu_dm/amdgpu_dm.c:6683 
amdgpu_dm_connector_funcs_force()
warn: variable dereferenced before check 'dc_link' (see line 6663)

Fixes: 967176179215 ("drm/amd/display: fix null-pointer dereference on edid 
reading")
Reported-by: Dan Carpenter 
Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 32efce81a5a7..46dd06e8fc7e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6653,7 +6653,7 @@ static void amdgpu_dm_connector_funcs_force(struct 
drm_connector *connector)
struct edid *edid;
struct i2c_adapter *ddc;
 
-   if (dc_link->aux_mode)
+   if (dc_link && dc_link->aux_mode)
ddc = >dm_dp_aux.aux.ddc;
else
ddc = >i2c->base;
-- 
2.43.0



Re: [PATCH] drm/amd/display: fix null-pointer dereference on edid reading

2024-02-16 Thread Melissa Wen
On 02/15, Alex Deucher wrote:
> On Thu, Feb 15, 2024 at 12:35 PM Melissa Wen  wrote:
> >
> > Use i2c adapter when there isn't aux_mode in dc_link to fix a
> > null-pointer derefence that happens when running
> > igt@kms_force_connector_basic in a system with DCN2.1 and HDMI connector
> > detected as below:
> >
> > [  +0.178146] BUG: kernel NULL pointer dereference, address: 
> > 04c0
> > [  +0.10] #PF: supervisor read access in kernel mode
> > [  +0.05] #PF: error_code(0x) - not-present page
> > [  +0.04] PGD 0 P4D 0
> > [  +0.06] Oops:  [#1] PREEMPT SMP NOPTI
> > [  +0.06] CPU: 15 PID: 2368 Comm: kms_force_conne Not tainted 
> > 6.5.0-asdn+ #152
> > [  +0.05] Hardware name: HP HP ENVY x360 Convertible 13-ay1xxx/8929, 
> > BIOS F.01 07/14/2021
> > [  +0.04] RIP: 0010:i2c_transfer+0xd/0x100
> > [  +0.11] Code: ea fc ff ff 66 0f 1f 84 00 00 00 00 00 90 90 90 90 90 
> > 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 0f 1f 44 00 00 41 54 55 53 
> > <48> 8b 47 10 48 89 fb 48 83 38 00 0f 84 b3 00 00 00 83 3d 2f 80 16
> > [  +0.04] RSP: 0018:9c4f89c0fad0 EFLAGS: 00010246
> > [  +0.05] RAX:  RBX: 0005 RCX: 
> > 0080
> > [  +0.03] RDX: 0002 RSI: 9c4f89c0fb20 RDI: 
> > 04b0
> > [  +0.03] RBP: 9c4f89c0fb80 R08: 0080 R09: 
> > 8d8e0b15b980
> > [  +0.03] R10: 000380e0 R11:  R12: 
> > 0080
> > [  +0.02] R13: 0002 R14: 9c4f89c0fb0e R15: 
> > 9c4f89c0fb0f
> > [  +0.04] FS:  7f9ad2176c40() GS:8d90fe9c() 
> > knlGS:
> > [  +0.03] CS:  0010 DS:  ES:  CR0: 80050033
> > [  +0.04] CR2: 04c0 CR3: 000121bc4000 CR4: 
> > 00750ee0
> > [  +0.03] PKRU: 5554
> > [  +0.03] Call Trace:
> > [  +0.06]  
> > [  +0.06]  ? __die+0x23/0x70
> > [  +0.11]  ? page_fault_oops+0x17d/0x4c0
> > [  +0.08]  ? preempt_count_add+0x6e/0xa0
> > [  +0.08]  ? srso_alias_return_thunk+0x5/0x7f
> > [  +0.11]  ? exc_page_fault+0x7f/0x180
> > [  +0.09]  ? asm_exc_page_fault+0x26/0x30
> > [  +0.13]  ? i2c_transfer+0xd/0x100
> > [  +0.10]  drm_do_probe_ddc_edid+0xc2/0x140 [drm]
> > [  +0.67]  ? srso_alias_return_thunk+0x5/0x7f
> > [  +0.06]  ? _drm_do_get_edid+0x97/0x3c0 [drm]
> > [  +0.43]  ? __pfx_drm_do_probe_ddc_edid+0x10/0x10 [drm]
> > [  +0.42]  edid_block_read+0x3b/0xd0 [drm]
> > [  +0.43]  _drm_do_get_edid+0xb6/0x3c0 [drm]
> > [  +0.41]  ? __pfx_drm_do_probe_ddc_edid+0x10/0x10 [drm]
> > [  +0.43]  drm_edid_read_custom+0x37/0xd0 [drm]
> > [  +0.44]  amdgpu_dm_connector_mode_valid+0x129/0x1d0 [amdgpu]
> > [  +0.000153]  drm_connector_mode_valid+0x3b/0x60 [drm_kms_helper]
> > [  +0.00]  __drm_helper_update_and_validate+0xfe/0x3c0 [drm_kms_helper]
> > [  +0.00]  ? amdgpu_dm_connector_get_modes+0xb6/0x520 [amdgpu]
> > [  +0.00]  ? srso_alias_return_thunk+0x5/0x7f
> > [  +0.00]  drm_helper_probe_single_connector_modes+0x2ab/0x540 
> > [drm_kms_helper]
> > [  +0.00]  status_store+0xb2/0x1f0 [drm]
> > [  +0.00]  kernfs_fop_write_iter+0x136/0x1d0
> > [  +0.00]  vfs_write+0x24d/0x440
> > [  +0.00]  ksys_write+0x6f/0xf0
> > [  +0.00]  do_syscall_64+0x60/0xc0
> > [  +0.00]  ? srso_alias_return_thunk+0x5/0x7f
> > [  +0.00]  ? syscall_exit_to_user_mode+0x2b/0x40
> > [  +0.00]  ? srso_alias_return_thunk+0x5/0x7f
> > [  +0.00]  ? do_syscall_64+0x6c/0xc0
> > [  +0.00]  ? do_syscall_64+0x6c/0xc0
> > [  +0.00]  entry_SYSCALL_64_after_hwframe+0x6e/0xd8
> > [  +0.00] RIP: 0033:0x7f9ad46b4b00
> > [  +0.00] Code: 40 00 48 8b 15 19 b3 0d 00 f7 d8 64 89 02 48 c7 c0 ff 
> > ff ff ff eb b7 0f 1f 00 80 3d e1 3a 0e 00 00 74 17 b8 01 00 00 00 0f 05 
> > <48> 3d 00 f0 ff ff 77 58 c3 0f 1f 80 00 00 00 00 48 83 ec 28 48 89
> > [  +0.00] RSP: 002b:7ffcbd3bd6d8 EFLAGS: 0202 ORIG_RAX: 
> > 0001
> > [  +0.00] RAX: ffda RBX:  RCX: 
> > 7f9ad46b4b00
> > [  +0.00] RDX: 0002 RSI: 7f9ad48a7417 RDI: 
> > 0009
> > [  +0.00] RBP: 0002 R08: 0064 R09: 
> > 
> > [  +0.00] R10:  R11: 0202 R12: 
> > 7f9ad48a7417
> > [  +0.00] R13: 00

[PATCH v2] drm/amd/display: fix null-pointer dereference on edid reading

2024-02-16 Thread Melissa Wen
nd_pci_acp5x nls_cp437 snd_rn_pci_acp3x ucsi_acpi 
sparse_keymap ccp snd platform_profile snd_acp_config typec_ucsi irqbypass vfat 
sp5100_tco
[  +0.00]  snd_soc_acpi fat rapl pcspkr wmi_bmof roles rfkill rng_core 
snd_pci_acp3x soundcore k10temp watchdog typec battery ac amd_pmc acpi_tad 
button hid_sensor_hub hid_multitouch evdev serio_raw msr parport_pc ppdev lp 
parport fuse loop efi_pstore configfs ip_tables x_tables autofs4 ext4 crc16 
mbcache jbd2 btrfs blake2b_generic dm_crypt dm_mod efivarfs raid10 raid456 
async_raid6_recov async_memcpy async_pq async_xor async_tx libcrc32c 
crc32c_generic xor raid6_pq raid1 raid0 multipath linear md_mod amdgpu amdxcp 
i2c_algo_bit drm_ttm_helper ttm crc32_pclmul crc32c_intel drm_exec gpu_sched 
drm_suballoc_helper nvme ghash_clmulni_intel drm_buddy drm_display_helper 
sha512_ssse3 nvme_core ahci xhci_pci sha512_generic hid_generic xhci_hcd 
libahci rtsx_pci_sdmmc t10_pi i2c_hid_acpi drm_kms_helper i2c_hid mmc_core 
libata aesni_intel crc64_rocksoft_generic crypto_simd amd_sfh crc64_rocksoft 
scsi_mod usbcore cryptd crc_t10dif cec drm crct10dif_generic hid rtsx_pci 
crct10dif_pclmul scsi_common rc_core crc64 i2c_piix4
[  +0.00]  usb_common crct10dif_common video wmi
[  +0.00] CR2: 04c0
[  +0.00] ---[ end trace  ]---

Fixes: e54ed41620f ("drm/amd/display: Remove unwanted drm edid references")
Signed-off-by: Melissa Wen 
---

v2:
- remove unused variables

 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 19 +++
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index b9ac3d2f8029..c6c4d19a0377 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6650,10 +6650,15 @@ amdgpu_dm_connector_late_register(struct drm_connector 
*connector)
 static void amdgpu_dm_connector_funcs_force(struct drm_connector *connector)
 {
struct amdgpu_dm_connector *aconnector = 
to_amdgpu_dm_connector(connector);
-   struct amdgpu_connector *amdgpu_connector = 
to_amdgpu_connector(connector);
struct dc_link *dc_link = aconnector->dc_link;
struct dc_sink *dc_em_sink = aconnector->dc_em_sink;
struct edid *edid;
+   struct i2c_adapter *ddc;
+
+   if (dc_link->aux_mode)
+   ddc = >dm_dp_aux.aux.ddc;
+   else
+   ddc = >i2c->base;
 
/*
 * Note: drm_get_edid gets edid in the following order:
@@ -6661,7 +,7 @@ static void amdgpu_dm_connector_funcs_force(struct 
drm_connector *connector)
 * 2) firmware EDID if set via edid_firmware module parameter
 * 3) regular DDC read.
 */
-   edid = drm_get_edid(connector, _connector->ddc_bus->aux.ddc);
+   edid = drm_get_edid(connector, ddc);
if (!edid) {
DRM_ERROR("No EDID found on connector: %s.\n", connector->name);
return;
@@ -6702,12 +6707,18 @@ static int get_modes(struct drm_connector *connector)
 static void create_eml_sink(struct amdgpu_dm_connector *aconnector)
 {
struct drm_connector *connector = >base;
-   struct amdgpu_connector *amdgpu_connector = 
to_amdgpu_connector(>base);
+   struct dc_link *dc_link = aconnector->dc_link;
struct dc_sink_init_data init_params = {
.link = aconnector->dc_link,
.sink_signal = SIGNAL_TYPE_VIRTUAL
};
struct edid *edid;
+   struct i2c_adapter *ddc;
+
+   if (dc_link->aux_mode)
+   ddc = >dm_dp_aux.aux.ddc;
+   else
+   ddc = >i2c->base;
 
/*
 * Note: drm_get_edid gets edid in the following order:
@@ -6715,7 +6726,7 @@ static void create_eml_sink(struct amdgpu_dm_connector 
*aconnector)
 * 2) firmware EDID if set via edid_firmware module parameter
 * 3) regular DDC read.
 */
-   edid = drm_get_edid(connector, _connector->ddc_bus->aux.ddc);
+   edid = drm_get_edid(connector, ddc);
if (!edid) {
DRM_ERROR("No EDID found on connector: %s.\n", connector->name);
return;
-- 
2.43.0



[PATCH] drm/amd/display: fix null-pointer dereference on edid reading

2024-02-15 Thread Melissa Wen
nd_pci_acp5x nls_cp437 snd_rn_pci_acp3x ucsi_acpi 
sparse_keymap ccp snd platform_profile snd_acp_config typec_ucsi irqbypass vfat 
sp5100_tco
[  +0.00]  snd_soc_acpi fat rapl pcspkr wmi_bmof roles rfkill rng_core 
snd_pci_acp3x soundcore k10temp watchdog typec battery ac amd_pmc acpi_tad 
button hid_sensor_hub hid_multitouch evdev serio_raw msr parport_pc ppdev lp 
parport fuse loop efi_pstore configfs ip_tables x_tables autofs4 ext4 crc16 
mbcache jbd2 btrfs blake2b_generic dm_crypt dm_mod efivarfs raid10 raid456 
async_raid6_recov async_memcpy async_pq async_xor async_tx libcrc32c 
crc32c_generic xor raid6_pq raid1 raid0 multipath linear md_mod amdgpu amdxcp 
i2c_algo_bit drm_ttm_helper ttm crc32_pclmul crc32c_intel drm_exec gpu_sched 
drm_suballoc_helper nvme ghash_clmulni_intel drm_buddy drm_display_helper 
sha512_ssse3 nvme_core ahci xhci_pci sha512_generic hid_generic xhci_hcd 
libahci rtsx_pci_sdmmc t10_pi i2c_hid_acpi drm_kms_helper i2c_hid mmc_core 
libata aesni_intel crc64_rocksoft_generic crypto_simd amd_sfh crc64_rocksoft 
scsi_mod usbcore cryptd crc_t10dif cec drm crct10dif_generic hid rtsx_pci 
crct10dif_pclmul scsi_common rc_core crc64 i2c_piix4
[  +0.00]  usb_common crct10dif_common video wmi
[  +0.00] CR2: 04c0
[  +0.00] ---[ end trace  ]---

Fixes: e54ed41620f ("drm/amd/display: Remove unwanted drm edid references")
Signed-off-by: Melissa Wen 
---

Hi,

I'm still working on the migration from edid to drm_edid, but I found a
way to fix the issue using the current approach, so we don't need to
delay this bug fix.

BR,

Melissa

 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c   | 17 +++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index b9ac3d2f8029..9f67d9030c36 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6654,6 +6654,12 @@ static void amdgpu_dm_connector_funcs_force(struct 
drm_connector *connector)
struct dc_link *dc_link = aconnector->dc_link;
struct dc_sink *dc_em_sink = aconnector->dc_em_sink;
struct edid *edid;
+   struct i2c_adapter *ddc;
+
+   if (dc_link->aux_mode)
+   ddc = >dm_dp_aux.aux.ddc;
+   else
+   ddc = >i2c->base;
 
/*
 * Note: drm_get_edid gets edid in the following order:
@@ -6661,7 +6667,7 @@ static void amdgpu_dm_connector_funcs_force(struct 
drm_connector *connector)
 * 2) firmware EDID if set via edid_firmware module parameter
 * 3) regular DDC read.
 */
-   edid = drm_get_edid(connector, _connector->ddc_bus->aux.ddc);
+   edid = drm_get_edid(connector, ddc);
if (!edid) {
DRM_ERROR("No EDID found on connector: %s.\n", connector->name);
return;
@@ -6703,11 +6709,18 @@ static void create_eml_sink(struct amdgpu_dm_connector 
*aconnector)
 {
struct drm_connector *connector = >base;
struct amdgpu_connector *amdgpu_connector = 
to_amdgpu_connector(>base);
+   struct dc_link *dc_link = aconnector->dc_link;
struct dc_sink_init_data init_params = {
.link = aconnector->dc_link,
.sink_signal = SIGNAL_TYPE_VIRTUAL
};
struct edid *edid;
+   struct i2c_adapter *ddc;
+
+   if (dc_link->aux_mode)
+   ddc = >dm_dp_aux.aux.ddc;
+   else
+   ddc = >i2c->base;
 
/*
 * Note: drm_get_edid gets edid in the following order:
@@ -6715,7 +6728,7 @@ static void create_eml_sink(struct amdgpu_dm_connector 
*aconnector)
 * 2) firmware EDID if set via edid_firmware module parameter
 * 3) regular DDC read.
 */
-   edid = drm_get_edid(connector, _connector->ddc_bus->aux.ddc);
+   edid = drm_get_edid(connector, ddc);
if (!edid) {
DRM_ERROR("No EDID found on connector: %s.\n", connector->name);
return;
-- 
2.43.0



Re: [RFC PATCH 2/2] drm/amd/display: switch amdgpu_dm_connector to use struct drm_edid

2024-02-05 Thread Melissa Wen
On 01/26, Alex Hung wrote:
> 
> 
> On 2024-01-26 09:28, Melissa Wen wrote:
> > Replace raw edid handling (struct edid) with the opaque EDID type
> > (struct drm_edid) on amdgpu_dm_connector for consistency. It may also
> > prevent mismatch of approaches in different parts of the driver code.
> > Working in progress. There are a couple of cast warnings and it was only
> > tested with IGT.
> > 
> > Signed-off-by: Melissa Wen 
> > ---
> >   .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 63 ++-
> >   .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  4 +-
> >   .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  9 +--
> >   .../display/amdgpu_dm/amdgpu_dm_mst_types.c   | 23 +++
> >   4 files changed, 51 insertions(+), 48 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
> > b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> > index 68e71e2ea472..741081d73bb3 100644
> > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> > @@ -3277,12 +3277,12 @@ void amdgpu_dm_update_connector_after_detect(
> > >dm_dp_aux.aux);
> > }
> > } else {
> > -   aconnector->edid =
> > -   (struct edid *)sink->dc_edid.raw_edid;
> > +   const struct edid *edid = (const struct edid 
> > *)sink->dc_edid.raw_edid;
> > +   aconnector->edid = drm_edid_alloc(edid, 
> > (edid->extensions + 1) * EDID_LENGTH);
> > if (aconnector->dc_link->aux_mode)
> > drm_dp_cec_set_edid(>dm_dp_aux.aux,
> > -   aconnector->edid);
> > +   
> > drm_edid_raw(aconnector->edid));
> > }
> > if (!aconnector->timing_requested) {
> > @@ -3293,13 +3293,13 @@ void amdgpu_dm_update_connector_after_detect(
> > "failed to create 
> > aconnector->requested_timing\n");
> > }
> > -   drm_connector_update_edid_property(connector, aconnector->edid);
> > +   drm_edid_connector_update(connector, aconnector->edid);
> > amdgpu_dm_update_freesync_caps(connector, aconnector->edid);
> > update_connector_ext_caps(aconnector);
> > } else {
> > drm_dp_cec_unset_edid(>dm_dp_aux.aux);
> > amdgpu_dm_update_freesync_caps(connector, NULL);
> > -   drm_connector_update_edid_property(connector, NULL);
> > +   drm_edid_connector_update(connector, NULL);
> > aconnector->num_modes = 0;
> > dc_sink_release(aconnector->dc_sink);
> > aconnector->dc_sink = NULL;
> > @@ -6564,7 +6564,6 @@ static void amdgpu_dm_connector_funcs_force(struct 
> > drm_connector *connector)
> > struct dc_link *dc_link = aconnector->dc_link;
> > struct dc_sink *dc_em_sink = aconnector->dc_em_sink;
> > const struct drm_edid *drm_edid;
> > -   const struct edid *edid;
> > /*
> >  * Note: drm_get_edid gets edid in the following order:
> > @@ -6578,11 +6577,12 @@ static void amdgpu_dm_connector_funcs_force(struct 
> > drm_connector *connector)
> > DRM_ERROR("No EDID found on connector: %s.\n", connector->name);
> > return;
> > }
> > -   edid = drm_edid_raw(drm_edid);
> > -   aconnector->edid = edid;
> > -
> > +   aconnector->edid = drm_edid;
> > +   drm_edid_connector_update(connector, drm_edid);
> > /* Update emulated (virtual) sink's EDID */
> > if (dc_em_sink && dc_link) {
> > +   const struct edid *edid = drm_edid_raw(drm_edid);
> > +
> > memset(_em_sink->edid_caps, 0, sizeof(struct dc_edid_caps));
> > memmove(dc_em_sink->dc_edid.raw_edid, (uint8_t *)edid, 
> > (edid->extensions + 1) * EDID_LENGTH);
> > dm_helpers_parse_edid_caps(
> > @@ -6633,13 +6633,13 @@ static void create_eml_sink(struct 
> > amdgpu_dm_connector *aconnector)
> > return;
> > }
> > -   edid = drm_edid_raw(drm_edid);
> > -
> > -   if (drm_detect_hdmi_monitor(edid))
> > +   if (connector->display_info.is_hdmi)
> > init_params.sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
> > -   aconnector->edid = ed

Re: [RFC PATCH 0/2] drm/amd/display: switch amdgpu_dm_connector to

2024-02-05 Thread Melissa Wen
On 01/29, Jani Nikula wrote:
> On Fri, 26 Jan 2024, Mario Limonciello  wrote:
> > On 1/26/2024 10:28, Melissa Wen wrote:
> >> Hi,
> >> 
> >> I'm debugging a null-pointer dereference when running
> >> igt@kms_connector_force_edid and the way I found to solve the bug is to
> >> stop using raw edid handler in amdgpu_connector_funcs_force and
> >> create_eml_sink in favor of managing resouces via sruct drm_edid helpers
> >> (Patch 1). The proper solution seems to be switch amdgpu_dm_connector
> >> from struct edid to struct drm_edid and avoid the usage of different
> >> approaches in the driver (Patch 2). However, doing it implies a good
> >> amount of work and validation, therefore I decided to send this RFC
> >> first to collect opinions and check if there is any parallel work on
> >> this side. It's a working in progress.
> >> 
> >> The null-pointer error trigger by the igt@kms_connector_force_edid test
> >> was introduced by:
> >> - e54ed41620f ("drm/amd/display: Remove unwanted drm edid references")
> >> 
> >> You can check the error trace in the first patch.
> >> 
> >> This series was tested with kms_hdmi_inject and kms_force_connector. No
> >> null-pointer error, kms_hdmi_inject is successul and kms_force_connector
> >> is sucessful after the second execution - the force-edid subtest
> >> still fails in the first run (I'm still investigating).
> >> 
> >> There is also a couple of cast warnings to be addressed - I'm looking
> >> for the best replacement.
> >> 
> >> I appreciate any feedback and testing.
> >
> > So I'm actually a little bit worried by hardcoding EDID_LENGTH in this 
> > series.
> >
> > I have some other patches that I'm posting later on that let you get the 
> > EDID from _DDC BIOS method too.  My observation was that the EDID can be 
> > anywhere up to 512 bytes according to the ACPI spec.
> >
> > An earlier version of my patch was using EDID_LENGTH when fetching it 
> > and the EDID checksum failed.
> >
> > I'll CC you on the post, we probably want to get your changes and mine 
> > merged together.
> 
> One of the main points of struct drm_edid is that it tracks the
> allocation size separately.
> 
> We should simply not trust edid->extensions, because most of the time it
> originates from outside the kernel.
> 
> Using drm_edid and immediately drm_edid_raw() falls short. That function
> should only be used during migration to help. And yeah, it also means
> EDID parsing should be done in drm_edid.c, and not spread out all over
> the subsystem.

Hi Mario and Jani,

Thanks for the feedback.

I agree with you. I used the drm_edid_raw() as an intermediate step to
assess/validate this migration, but I'll work on removing this hack.

So, I understand that the transition from edid to drm_edid is the right
path, so I'll improve this work (keeping the points you raised in mind)
and send a version.

BR,

Melissa
> 
> 
> BR,
> Jani.
> 
> 
> >
> >> 
> >> Melissa
> >> 
> >> Melissa Wen (2):
> >>drm/amd/display: fix null-pointer dereference on edid reading
> >>drm/amd/display: switch amdgpu_dm_connector to use struct drm_edid
> >> 
> >>   .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 78 ++-
> >>   .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  4 +-
> >>   .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  9 ++-
> >>   .../display/amdgpu_dm/amdgpu_dm_mst_types.c   | 23 +++---
> >>   4 files changed, 60 insertions(+), 54 deletions(-)
> >> 
> >
> 
> -- 
> Jani Nikula, Intel


[RFC PATCH 2/2] drm/amd/display: switch amdgpu_dm_connector to use struct drm_edid

2024-01-26 Thread Melissa Wen
Replace raw edid handling (struct edid) with the opaque EDID type
(struct drm_edid) on amdgpu_dm_connector for consistency. It may also
prevent mismatch of approaches in different parts of the driver code.
Working in progress. There are a couple of cast warnings and it was only
tested with IGT.

Signed-off-by: Melissa Wen 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 63 ++-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  4 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  9 +--
 .../display/amdgpu_dm/amdgpu_dm_mst_types.c   | 23 +++
 4 files changed, 51 insertions(+), 48 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 68e71e2ea472..741081d73bb3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3277,12 +3277,12 @@ void amdgpu_dm_update_connector_after_detect(
>dm_dp_aux.aux);
}
} else {
-   aconnector->edid =
-   (struct edid *)sink->dc_edid.raw_edid;
+   const struct edid *edid = (const struct edid 
*)sink->dc_edid.raw_edid;
+   aconnector->edid = drm_edid_alloc(edid, 
(edid->extensions + 1) * EDID_LENGTH);
 
if (aconnector->dc_link->aux_mode)
drm_dp_cec_set_edid(>dm_dp_aux.aux,
-   aconnector->edid);
+   
drm_edid_raw(aconnector->edid));
}
 
if (!aconnector->timing_requested) {
@@ -3293,13 +3293,13 @@ void amdgpu_dm_update_connector_after_detect(
"failed to create 
aconnector->requested_timing\n");
}
 
-   drm_connector_update_edid_property(connector, aconnector->edid);
+   drm_edid_connector_update(connector, aconnector->edid);
amdgpu_dm_update_freesync_caps(connector, aconnector->edid);
update_connector_ext_caps(aconnector);
} else {
drm_dp_cec_unset_edid(>dm_dp_aux.aux);
amdgpu_dm_update_freesync_caps(connector, NULL);
-   drm_connector_update_edid_property(connector, NULL);
+   drm_edid_connector_update(connector, NULL);
aconnector->num_modes = 0;
dc_sink_release(aconnector->dc_sink);
aconnector->dc_sink = NULL;
@@ -6564,7 +6564,6 @@ static void amdgpu_dm_connector_funcs_force(struct 
drm_connector *connector)
struct dc_link *dc_link = aconnector->dc_link;
struct dc_sink *dc_em_sink = aconnector->dc_em_sink;
const struct drm_edid *drm_edid;
-   const struct edid *edid;
 
/*
 * Note: drm_get_edid gets edid in the following order:
@@ -6578,11 +6577,12 @@ static void amdgpu_dm_connector_funcs_force(struct 
drm_connector *connector)
DRM_ERROR("No EDID found on connector: %s.\n", connector->name);
return;
}
-   edid = drm_edid_raw(drm_edid);
-   aconnector->edid = edid;
-
+   aconnector->edid = drm_edid;
+   drm_edid_connector_update(connector, drm_edid);
/* Update emulated (virtual) sink's EDID */
if (dc_em_sink && dc_link) {
+   const struct edid *edid = drm_edid_raw(drm_edid);
+
memset(_em_sink->edid_caps, 0, sizeof(struct dc_edid_caps));
memmove(dc_em_sink->dc_edid.raw_edid, (uint8_t *)edid, 
(edid->extensions + 1) * EDID_LENGTH);
dm_helpers_parse_edid_caps(
@@ -6633,13 +6633,13 @@ static void create_eml_sink(struct amdgpu_dm_connector 
*aconnector)
return;
}
 
-   edid = drm_edid_raw(drm_edid);
-
-   if (drm_detect_hdmi_monitor(edid))
+   if (connector->display_info.is_hdmi)
init_params.sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
 
-   aconnector->edid = edid;
+   aconnector->edid = drm_edid;
+   drm_edid_connector_update(connector, drm_edid);
 
+   edid = drm_edid_raw(drm_edid);
aconnector->dc_em_sink = dc_link_add_remote_sink(
aconnector->dc_link,
(uint8_t *)edid,
@@ -7322,16 +7322,16 @@ static void amdgpu_set_panel_orientation(struct 
drm_connector *connector)
 }
 
 static void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector,
- struct edid *edid)
+ const struct drm_edid *drm_edid)
 {
struct amdgpu_dm_connector *amdgpu_dm_connector =
to_amdgpu_dm_connector(connector);
 
-   if (edid) {
+   if (drm_edid

[RFC PATCH 0/2] drm/amd/display: switch amdgpu_dm_connector to

2024-01-26 Thread Melissa Wen
Hi,

I'm debugging a null-pointer dereference when running
igt@kms_connector_force_edid and the way I found to solve the bug is to
stop using raw edid handler in amdgpu_connector_funcs_force and
create_eml_sink in favor of managing resouces via sruct drm_edid helpers
(Patch 1). The proper solution seems to be switch amdgpu_dm_connector
from struct edid to struct drm_edid and avoid the usage of different
approaches in the driver (Patch 2). However, doing it implies a good
amount of work and validation, therefore I decided to send this RFC
first to collect opinions and check if there is any parallel work on
this side. It's a working in progress.

The null-pointer error trigger by the igt@kms_connector_force_edid test
was introduced by:
- e54ed41620f ("drm/amd/display: Remove unwanted drm edid references")

You can check the error trace in the first patch.

This series was tested with kms_hdmi_inject and kms_force_connector. No
null-pointer error, kms_hdmi_inject is successul and kms_force_connector
is sucessful after the second execution - the force-edid subtest
still fails in the first run (I'm still investigating).

There is also a couple of cast warnings to be addressed - I'm looking
for the best replacement. 

I appreciate any feedback and testing.

Melissa

Melissa Wen (2):
  drm/amd/display: fix null-pointer dereference on edid reading
  drm/amd/display: switch amdgpu_dm_connector to use struct drm_edid

 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 78 ++-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  4 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  9 ++-
 .../display/amdgpu_dm/amdgpu_dm_mst_types.c   | 23 +++---
 4 files changed, 60 insertions(+), 54 deletions(-)

-- 
2.43.0



[RFC PATCH 1/2] drm/amd/display: fix null-pointer dereference on edid reading

2024-01-26 Thread Melissa Wen
3x ucsi_acpi 
sparse_keymap ccp snd platform_profile snd_acp_config typec_ucsi irqbypass vfat 
sp5100_tco
[  +0.00]  snd_soc_acpi fat rapl pcspkr wmi_bmof roles rfkill rng_core 
snd_pci_acp3x soundcore k10temp watchdog typec battery ac amd_pmc acpi_tad 
button hid_sensor_hub hid_multitouch evdev serio_raw msr parport_pc ppdev lp 
parport fuse loop efi_pstore configfs ip_tables x_tables autofs4 ext4 crc16 
mbcache jbd2 btrfs blake2b_generic dm_crypt dm_mod efivarfs raid10 raid456 
async_raid6_recov async_memcpy async_pq async_xor async_tx libcrc32c 
crc32c_generic xor raid6_pq raid1 raid0 multipath linear md_mod amdgpu amdxcp 
i2c_algo_bit drm_ttm_helper ttm crc32_pclmul crc32c_intel drm_exec gpu_sched 
drm_suballoc_helper nvme ghash_clmulni_intel drm_buddy drm_display_helper 
sha512_ssse3 nvme_core ahci xhci_pci sha512_generic hid_generic xhci_hcd 
libahci rtsx_pci_sdmmc t10_pi i2c_hid_acpi drm_kms_helper i2c_hid mmc_core 
libata aesni_intel crc64_rocksoft_generic crypto_simd amd_sfh crc64_rocksoft 
scsi_mod usbcore cryptd crc_t10dif cec drm crct10dif_generic hid rtsx_pci 
crct10dif_pclmul scsi_common rc_core crc64 i2c_piix4
[  +0.00]  usb_common crct10dif_common video wmi
[  +0.00] CR2: 04c0
[  +0.00] ---[ end trace  ]---

Fixes: e54ed41620f ("drm/amd/display: Remove unwanted drm edid references")
Signed-off-by: Melissa Wen 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 23 +++
 1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index cd98b3565178..68e71e2ea472 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6561,10 +6561,10 @@ amdgpu_dm_connector_late_register(struct drm_connector 
*connector)
 static void amdgpu_dm_connector_funcs_force(struct drm_connector *connector)
 {
struct amdgpu_dm_connector *aconnector = 
to_amdgpu_dm_connector(connector);
-   struct amdgpu_connector *amdgpu_connector = 
to_amdgpu_connector(connector);
struct dc_link *dc_link = aconnector->dc_link;
struct dc_sink *dc_em_sink = aconnector->dc_em_sink;
-   struct edid *edid;
+   const struct drm_edid *drm_edid;
+   const struct edid *edid;
 
/*
 * Note: drm_get_edid gets edid in the following order:
@@ -6572,18 +6572,19 @@ static void amdgpu_dm_connector_funcs_force(struct 
drm_connector *connector)
 * 2) firmware EDID if set via edid_firmware module parameter
 * 3) regular DDC read.
 */
-   edid = drm_get_edid(connector, _connector->ddc_bus->aux.ddc);
-   if (!edid) {
+   drm_edid = drm_edid_read(connector);
+
+   if (!drm_edid) {
DRM_ERROR("No EDID found on connector: %s.\n", connector->name);
return;
}
-
+   edid = drm_edid_raw(drm_edid);
aconnector->edid = edid;
 
/* Update emulated (virtual) sink's EDID */
if (dc_em_sink && dc_link) {
memset(_em_sink->edid_caps, 0, sizeof(struct dc_edid_caps));
-   memmove(dc_em_sink->dc_edid.raw_edid, edid, (edid->extensions + 
1) * EDID_LENGTH);
+   memmove(dc_em_sink->dc_edid.raw_edid, (uint8_t *)edid, 
(edid->extensions + 1) * EDID_LENGTH);
dm_helpers_parse_edid_caps(
dc_link,
_em_sink->dc_edid,
@@ -6613,12 +6614,12 @@ static int get_modes(struct drm_connector *connector)
 static void create_eml_sink(struct amdgpu_dm_connector *aconnector)
 {
struct drm_connector *connector = >base;
-   struct amdgpu_connector *amdgpu_connector = 
to_amdgpu_connector(>base);
struct dc_sink_init_data init_params = {
.link = aconnector->dc_link,
.sink_signal = SIGNAL_TYPE_VIRTUAL
};
-   struct edid *edid;
+   const struct drm_edid *drm_edid;
+   const struct edid *edid;
 
/*
 * Note: drm_get_edid gets edid in the following order:
@@ -6626,12 +6627,14 @@ static void create_eml_sink(struct amdgpu_dm_connector 
*aconnector)
 * 2) firmware EDID if set via edid_firmware module parameter
 * 3) regular DDC read.
 */
-   edid = drm_get_edid(connector, _connector->ddc_bus->aux.ddc);
-   if (!edid) {
+   drm_edid = drm_edid_read(connector);
+   if (!drm_edid) {
DRM_ERROR("No EDID found on connector: %s.\n", connector->name);
return;
}
 
+   edid = drm_edid_raw(drm_edid);
+
if (drm_detect_hdmi_monitor(edid))
init_params.sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
 
-- 
2.43.0



Re: [PATCH 1/1] Revert "drm/amd/display: fix bandwidth validation failure on DCN 2.1"

2024-01-07 Thread Melissa Wen
On 01/06, LIPSKI, IVAN wrote:
> [AMD Official Use Only - General]
> 
> @Siqueira, Rodrigo<mailto:rodrigo.sique...@amd.com>
> 
> From: LIPSKI, IVAN 
> Sent: January 5, 2024 7:40 PM
> To: amd-gfx@lists.freedesktop.org 
> Cc: rodrigo.siqui...@amd.com ; Choi, Nicholas 
> ; Deucher, Alexander ; 
> Koenig, Christian ; Wentland, Harry 
> ; LIPSKI, IVAN ; Melissa Wen 
> ; Mahfooz, Hamza 
> Subject: [PATCH 1/1] Revert "drm/amd/display: fix bandwidth validation 
> failure on DCN 2.1"
> 
> From: Ivan Lipski 
> 
> This commit causes dmesg-warn on several IGT tests on DCN 3.1.6:
> *ERROR* link_enc_cfg_validate: Invalid link encoder assignments - 0x1c
> 
> Affected IGT tests include:
> amdgpu/[amd_assr|amd_plane|amd_hotplug]
> kms_atomic
> kms_color
> kms_flip
> kms_properties
> kms_universal_plane
> 
> and some other tests
> 
> This reverts commit b7ebd39e2922f642c7ee63ade4a4a5a1ef675d84.

I'm not opposed to reverting this in the short term, but I don't see the
connection between doing a full validation and link encoder assignment
errors. It seems more like the change unveiled an underlying issue
rather than causing the error. I don't see those errors on DCN 2.1 and
3.0.1.

Unfortunately, I don't have a DCN 3.1.6 for debugging :( It'd deserve
further investigation.

Melissa

> 
> Cc: Melissa Wen 
> Cc: Hamza Mahfooz 
> 
> Signed-off-by: Ivan Lipski 
> 
> ---
>  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> index d77fc79f3542..111c6f51f0ae 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -10752,7 +10752,7 @@ static int amdgpu_dm_atomic_check(struct drm_device 
> *dev,
>  DRM_DEBUG_DRIVER("drm_dp_mst_atomic_check() 
> failed\n");
>  goto fail;
>  }
> -   status = dc_validate_global_state(dc, dm_state->context, 
> false);
> +   status = dc_validate_global_state(dc, dm_state->context, 
> true);
>  if (status != DC_OK) {
>  DRM_DEBUG_DRIVER("DC global validation failure: %s 
> (%d)",
> dc_status_to_str(status), status);
> --
> 2.34.1
> 


[PATCH] drm/amd/display: cleanup inconsistent indenting in amdgpu_dm_color

2024-01-05 Thread Melissa Wen
smatch warnings:
amdgpu_dm_update_plane_color_mgmt() warn: inconsistent indenting

Reported-by: kernel test robot 
Closes: 
https://lore.kernel.org/oe-kbuild-all/202401051643.ppdbmg1u-...@intel.com/
Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 9b527bffe11a..c87b64e464ed 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -1239,7 +1239,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct 
dm_crtc_state *crtc,
if (has_crtc_cm_degamma && ret != -EINVAL) {
drm_dbg_kms(crtc->base.crtc->dev,
"doesn't support plane and CRTC degamma at the same 
time\n");
-   return -EINVAL;
+   return -EINVAL;
}
 
/* If we are here, it means we don't have plane degamma settings, check
-- 
2.43.0



[RFC PATCH] drm/amd/display: fix bandwidth validation failure on DCN 2.1

2023-12-29 Thread Melissa Wen
IGT `amdgpu/amd_color/crtc-lut-accuracy` fails right at the beginning of
the test execution, during atomic check, because DC rejects the
bandwidth state for a fb sizing 64x64. The test was previously working
with the deprecated dc_commit_state(). Now using
dc_validate_with_context() approach, the atomic check needs to perform a
full state validation. Therefore, set fast_validation to false in the
dc_validate_global_state call for atomic check.

Fixes: b8272241ff9d ("drm/amd/display: Drop dc_commit_state in favor of 
dc_commit_streams")
Signed-off-by: Melissa Wen 
---

Hi,

It's a long story. I was inspecting this bug report:
- https://gitlab.freedesktop.org/drm/amd/-/issues/2016
and noticed the IGT test `igt@amdgpu/amd_color@crtc-lut-accuracy`
mentioned there wasn't even being executed on a laptop with DCN 2.1
(HP HP ENVY x360 Convertible 13-ay1xxx/8929). The test fails right at
the beginning due to an atomic check rejection, as below:

Starting subtest: crtc-lut-accuracy
(amd_color:14772) igt_kms-CRITICAL: Test assertion failure function 
igt_display_commit_atomic, file ../lib/igt_kms.c:4530:
(amd_color:14772) igt_kms-CRITICAL: Failed assertion: ret == 0
(amd_color:14772) igt_kms-CRITICAL: Last errno: 22, Invalid argument
(amd_color:14772) igt_kms-CRITICAL: error: -22 != 0
Stack trace:
  #0 ../lib/igt_core.c:1989 __igt_fail_assert()
  #1 [igt_display_commit_atomic+0x44]
  #2 ../tests/amdgpu/amd_color.c:159 __igt_uniquereal_main395()
  #3 ../tests/amdgpu/amd_color.c:395 main()
  #4 ../sysdeps/nptl/libc_start_call_main.h:74 __libc_start_call_main()
  #5 ../csu/libc-start.c:128 __libc_start_main@@GLIBC_2.34()
  #6 [_start+0x21]
Subtest crtc-lut-accuracy failed.

Checking dmesg, we can see that a bandwidth validation failure causes
the atomic check rejection:

[  711.147663] amdgpu :04:00.0: [drm] Mode Validation Warning: Unknown 
Status failed validation.
[  711.147667] [drm:amdgpu_dm_atomic_check [amdgpu]] DC global validation 
failure: Bandwidth validation failure (BW and Watermark) (13)
[  711.147772] [drm:amdgpu_irq_dispatch [amdgpu]] Unregistered interrupt 
src_id: 243 of client_id:8
[  711.148033] [drm:amdgpu_dm_atomic_check [amdgpu]] Atomic check failed with 
err: -22

I also noticed that the atomic check doesn't fail if I change the fb
width and height used in the test from 64 to 66, and I can get the test
execution back (and with success). However, I recall that all test cases
of IGT `amd_color` were working in the past, so I bisected and found the
first bad commit:

b8272241ff9d drm/amd/display: Drop dc_commit_state in favor of dc_commit_streams

Bringing the `dc_commit_state` machinery back also prevents the
bandwidth validation failure, but the commit above says
dc_commit_streams validation is more complete than dc_commit_state, so I
discarded this approach.

After some debugging and code inspection, I found out that avoiding fast
validation on dc_validate_global_state during atomic check solves the
issue, but I'm not sure if this change may affect performance. I
compared exec time of some IGT tests and didn't see any differences, but
I recognize it doesn't provide enough evidence.

What do you think about this change? Should I examine other things? Do
you see any potential issue that I should investigate? Could you
recommend a better approach to assess any side-effect of not enabling
fast validation in the atomic check?

Please, let me know your thoughts.

Happy New Year!

Melissa

 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 2845c884398e..4f51a7ad7a3c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -10745,7 +10745,7 @@ static int amdgpu_dm_atomic_check(struct drm_device 
*dev,
DRM_DEBUG_DRIVER("drm_dp_mst_atomic_check() failed\n");
goto fail;
}
-   status = dc_validate_global_state(dc, dm_state->context, true);
+   status = dc_validate_global_state(dc, dm_state->context, false);
if (status != DC_OK) {
DRM_DEBUG_DRIVER("DC global validation failure: %s 
(%d)",
   dc_status_to_str(status), status);
-- 
2.43.0



[PATCH] drm/amd/display: fix documentation for dm_crtc_additional_color_mgmt()

2023-12-14 Thread Melissa Wen
warning: expecting prototype for drm_crtc_additional_color_mgmt().
Prototype was for dm_crtc_additional_color_mgmt() instead

Reported-by: kernel test robot 
Closes: 
https://lore.kernel.org/oe-kbuild-all/202312141801.o9ebcxt9-...@intel.com/
Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
index 8b3aa674741d..4439e5a27362 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
@@ -292,7 +292,7 @@ static int amdgpu_dm_crtc_late_register(struct drm_crtc 
*crtc)
 
 #ifdef AMD_PRIVATE_COLOR
 /**
- * drm_crtc_additional_color_mgmt - enable additional color properties
+ * dm_crtc_additional_color_mgmt - enable additional color properties
  * @crtc: DRM CRTC
  *
  * This function lets the driver enable post-blending CRTC regamma transfer
-- 
2.42.0



Re: [PATCH] drm/amd/display: fix documentation for amdgpu_dm_verify_lut3d_size()

2023-12-14 Thread Melissa Wen
On 12/14, Alex Deucher wrote:
> It takes the plane state rather than the crtc state.
> 
> Fixes: aba8b76baabd ("drm/amd/display: add plane shaper LUT support")
> Reported-by: Stephen Rothwell 
> Signed-off-by: Alex Deucher 
> Cc: Melissa Wen 
> Cc: harry.wentl...@amd.com
> ---
>  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
> index 96aecc1a71a3..c6ed0d854b01 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
> @@ -796,7 +796,7 @@ static int amdgpu_dm_atomic_blend_lut(const struct 
> drm_color_lut *blend_lut,
>   * amdgpu_dm_verify_lut3d_size - verifies if 3D LUT is supported and if user
>   * shaper and 3D LUTs match the hw supported size
>   * @adev: amdgpu device
> - * @crtc_state: the DRM CRTC state
> + * @plane_state: the DRM plane state

Reviewed-by: Melissa Wen 

>   *
>   * Verifies if pre-blending (DPP) 3D LUT is supported by the HW (DCN 2.0 or
>   * newer) and if the user shaper and 3D LUTs match the supported size.
> -- 
> 2.42.0
> 


[PATCH v3 6/9] drm/amd/display: create DCN3-specific log for MPC state

2023-11-28 Thread Melissa Wen
Logging DCN3 MPC state was following DCN1 implementation that doesn't
consider new DCN3 MPC color blocks. Create new elements according to
DCN3 MPC color caps and a new DCN3-specific function for reading MPC
data.

v3:
- remove gamut remap reg reading in favor of fixed31_32 matrix data

Signed-off-by: Melissa Wen 
---
 .../gpu/drm/amd/display/dc/dcn30/dcn30_mpc.c  | 48 ++-
 drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h   |  7 +++
 2 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.c 
b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.c
index a6a4c3413f89..bf3386cd444d 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.c
@@ -1440,8 +1440,54 @@ static void mpc3_set_mpc_mem_lp_mode(struct mpc *mpc)
}
 }
 
+static void mpc3_read_mpcc_state(
+   struct mpc *mpc,
+   int mpcc_inst,
+   struct mpcc_state *s)
+{
+   struct dcn30_mpc *mpc30 = TO_DCN30_MPC(mpc);
+   uint32_t rmu_status = 0xf;
+
+   REG_GET(MPCC_OPP_ID[mpcc_inst], MPCC_OPP_ID, >opp_id);
+   REG_GET(MPCC_TOP_SEL[mpcc_inst], MPCC_TOP_SEL, >dpp_id);
+   REG_GET(MPCC_BOT_SEL[mpcc_inst], MPCC_BOT_SEL, >bot_mpcc_id);
+   REG_GET_4(MPCC_CONTROL[mpcc_inst], MPCC_MODE, >mode,
+   MPCC_ALPHA_BLND_MODE, >alpha_mode,
+   MPCC_ALPHA_MULTIPLIED_MODE, >pre_multiplied_alpha,
+   MPCC_BLND_ACTIVE_OVERLAP_ONLY, >overlap_only);
+   REG_GET_2(MPCC_STATUS[mpcc_inst], MPCC_IDLE, >idle,
+   MPCC_BUSY, >busy);
+
+   /* Color blocks state */
+   REG_GET(MPC_RMU_CONTROL, MPC_RMU0_MUX_STATUS, _status);
+
+   if (rmu_status == mpcc_inst) {
+   REG_GET(SHAPER_CONTROL[0],
+   MPC_RMU_SHAPER_LUT_MODE_CURRENT, >shaper_lut_mode);
+   REG_GET(RMU_3DLUT_MODE[0],
+   MPC_RMU_3DLUT_MODE_CURRENT,  >lut3d_mode);
+   REG_GET(RMU_3DLUT_READ_WRITE_CONTROL[0],
+   MPC_RMU_3DLUT_30BIT_EN, >lut3d_bit_depth);
+   REG_GET(RMU_3DLUT_MODE[0],
+   MPC_RMU_3DLUT_SIZE, >lut3d_size);
+   } else {
+   REG_GET(SHAPER_CONTROL[1],
+   MPC_RMU_SHAPER_LUT_MODE_CURRENT, >shaper_lut_mode);
+   REG_GET(RMU_3DLUT_MODE[1],
+   MPC_RMU_3DLUT_MODE_CURRENT,  >lut3d_mode);
+   REG_GET(RMU_3DLUT_READ_WRITE_CONTROL[1],
+   MPC_RMU_3DLUT_30BIT_EN, >lut3d_bit_depth);
+   REG_GET(RMU_3DLUT_MODE[1],
+   MPC_RMU_3DLUT_SIZE, >lut3d_size);
+   }
+
+REG_GET_2(MPCC_OGAM_CONTROL[mpcc_inst],
+ MPCC_OGAM_MODE_CURRENT, >rgam_mode,
+ MPCC_OGAM_SELECT_CURRENT, >rgam_lut);
+}
+
 static const struct mpc_funcs dcn30_mpc_funcs = {
-   .read_mpcc_state = mpc1_read_mpcc_state,
+   .read_mpcc_state = mpc3_read_mpcc_state,
.insert_plane = mpc1_insert_plane,
.remove_mpcc = mpc1_remove_mpcc,
.mpc_init = mpc1_mpc_init,
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h 
b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
index 61a2406dcc53..a11e40fddc44 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
@@ -199,6 +199,13 @@ struct mpcc_state {
uint32_t overlap_only;
uint32_t idle;
uint32_t busy;
+   uint32_t shaper_lut_mode;
+   uint32_t lut3d_mode;
+   uint32_t lut3d_bit_depth;
+   uint32_t lut3d_size;
+   uint32_t rgam_mode;
+   uint32_t rgam_lut;
+   struct mpc_grph_gamut_adjustment gamut_remap;
 };
 
 /**
-- 
2.42.0



[PATCH v3 9/9] drm/amd/display: hook up DCN20 color blocks data to DTN log

2023-11-28 Thread Melissa Wen
Color caps changed between HW versions, which caused the DCN10 color
state sections in the DTN log to no longer match DCN2+ state. Create a
color state log specific to DCN2.0 and hook it up to DCN2 family
drivers. Instead of reading gamut remap reg values, display gamut remap
matrix data in fixed 31.32.

Signed-off-by: Melissa Wen 
---
 .../gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c  |  30 ++---
 .../gpu/drm/amd/display/dc/dcn20/dcn20_init.c |   1 +
 .../gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c  |  24 +++-
 .../gpu/drm/amd/display/dc/dcn21/dcn21_init.c |   1 +
 .../amd/display/dc/hwss/dcn20/dcn20_hwseq.c   | 106 ++
 .../amd/display/dc/hwss/dcn20/dcn20_hwseq.h   |   2 +
 6 files changed, 149 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c 
b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c
index dedc2dcf2691..1516c0a48726 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c
@@ -55,21 +55,23 @@ void dpp20_read_state(struct dpp *dpp_base,
 
REG_GET(DPP_CONTROL,
DPP_CLOCK_ENABLE, >is_enabled);
+
+   // Degamma LUT (RAM)
REG_GET(CM_DGAM_CONTROL,
-   CM_DGAM_LUT_MODE, >dgam_lut_mode);
-   // BGAM has no ROM, and definition is different, can't reuse same dump
-   //REG_GET(CM_BLNDGAM_CONTROL,
-   //  CM_BLNDGAM_LUT_MODE, >rgam_lut_mode);
-   REG_GET(CM_GAMUT_REMAP_CONTROL,
-   CM_GAMUT_REMAP_MODE, >gamut_remap_mode);
-   if (s->gamut_remap_mode) {
-   s->gamut_remap_c11_c12 = REG_READ(CM_GAMUT_REMAP_C11_C12);
-   s->gamut_remap_c13_c14 = REG_READ(CM_GAMUT_REMAP_C13_C14);
-   s->gamut_remap_c21_c22 = REG_READ(CM_GAMUT_REMAP_C21_C22);
-   s->gamut_remap_c23_c24 = REG_READ(CM_GAMUT_REMAP_C23_C24);
-   s->gamut_remap_c31_c32 = REG_READ(CM_GAMUT_REMAP_C31_C32);
-   s->gamut_remap_c33_c34 = REG_READ(CM_GAMUT_REMAP_C33_C34);
-   }
+   CM_DGAM_LUT_MODE, >dgam_lut_mode);
+
+   // Shaper LUT (RAM), 3D LUT (mode, bit-depth, size)
+   REG_GET(CM_SHAPER_CONTROL,
+   CM_SHAPER_LUT_MODE, >shaper_lut_mode);
+   REG_GET_2(CM_3DLUT_READ_WRITE_CONTROL,
+ CM_3DLUT_CONFIG_STATUS, >lut3d_mode,
+ CM_3DLUT_30BIT_EN, >lut3d_bit_depth);
+   REG_GET(CM_3DLUT_MODE,
+   CM_3DLUT_SIZE, >lut3d_size);
+
+   // Blend/Out Gamma (RAM)
+   REG_GET(CM_BLNDGAM_LUT_WRITE_EN_MASK,
+   CM_BLNDGAM_CONFIG_STATUS, >rgam_lut_mode);
 }
 
 void dpp2_power_on_obuf(
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c 
b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c
index 884e3e323338..ef6488165b8f 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c
@@ -67,6 +67,7 @@ static const struct hw_sequencer_funcs dcn20_funcs = {
.setup_stereo = dcn10_setup_stereo,
.set_avmute = dce110_set_avmute,
.log_hw_state = dcn10_log_hw_state,
+   .log_color_state = dcn20_log_color_state,
.get_hw_state = dcn10_get_hw_state,
.clear_status_bits = dcn10_clear_status_bits,
.wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c 
b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c
index 5da6e44f284a..16b5ff208d14 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c
@@ -542,8 +542,30 @@ static struct mpcc *mpc2_get_mpcc_for_dpp(struct mpc_tree 
*tree, int dpp_id)
return NULL;
 }
 
+static void mpc2_read_mpcc_state(
+   struct mpc *mpc,
+   int mpcc_inst,
+   struct mpcc_state *s)
+{
+   struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc);
+
+   REG_GET(MPCC_OPP_ID[mpcc_inst], MPCC_OPP_ID, >opp_id);
+   REG_GET(MPCC_TOP_SEL[mpcc_inst], MPCC_TOP_SEL, >dpp_id);
+   REG_GET(MPCC_BOT_SEL[mpcc_inst], MPCC_BOT_SEL, >bot_mpcc_id);
+   REG_GET_4(MPCC_CONTROL[mpcc_inst], MPCC_MODE, >mode,
+   MPCC_ALPHA_BLND_MODE, >alpha_mode,
+   MPCC_ALPHA_MULTIPLIED_MODE, >pre_multiplied_alpha,
+   MPCC_BLND_ACTIVE_OVERLAP_ONLY, >overlap_only);
+   REG_GET_2(MPCC_STATUS[mpcc_inst], MPCC_IDLE, >idle,
+   MPCC_BUSY, >busy);
+
+   /* Gamma block state */
+   REG_GET(MPCC_OGAM_LUT_RAM_CONTROL[mpcc_inst],
+   MPCC_OGAM_CONFIG_STATUS, >rgam_mode);
+}
+
 static const struct mpc_funcs dcn20_mpc_funcs = {
-   .read_mpcc_state = mpc1_read_mpcc_state,
+   .read_mpcc_state = mpc2_read_mpcc_state,
.insert_plane = mpc1_insert_plane,
.remove_mpcc = mpc1_remove_mpcc,
.mpc_init = mpc1_mp

[PATCH v3 8/9] drm/amd/display: add DPP and MPC color caps to DTN log

2023-11-28 Thread Melissa Wen
Add color caps information for DPP and MPC block to show HW color caps.

Signed-off-by: Melissa Wen 
---
 .../amd/display/dc/hwss/dcn10/dcn10_hwseq.c   | 23 +++
 .../amd/display/dc/hwss/dcn30/dcn30_hwseq.c   | 23 +++
 2 files changed, 46 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c 
b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
index f7d9bcdbc6c6..d3cab6fb270b 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
@@ -346,6 +346,24 @@ static void dcn10_log_color_state(struct dc *dc,
DTN_INFO("\n");
}
DTN_INFO("\n");
+   DTN_INFO("DPP Color Caps: input_lut_shared:%d  icsc:%d"
+"  dgam_ram:%d  dgam_rom: 
srgb:%d,bt2020:%d,gamma2_2:%d,pq:%d,hlg:%d"
+"  post_csc:%d  gamcor:%d  dgam_rom_for_yuv:%d  3d_lut:%d"
+"  blnd_lut:%d  oscs:%d\n\n",
+dc->caps.color.dpp.input_lut_shared,
+dc->caps.color.dpp.icsc,
+dc->caps.color.dpp.dgam_ram,
+dc->caps.color.dpp.dgam_rom_caps.srgb,
+dc->caps.color.dpp.dgam_rom_caps.bt2020,
+dc->caps.color.dpp.dgam_rom_caps.gamma2_2,
+dc->caps.color.dpp.dgam_rom_caps.pq,
+dc->caps.color.dpp.dgam_rom_caps.hlg,
+dc->caps.color.dpp.post_csc,
+dc->caps.color.dpp.gamma_corr,
+dc->caps.color.dpp.dgam_rom_for_yuv,
+dc->caps.color.dpp.hw_3d_lut,
+dc->caps.color.dpp.ogam_ram,
+dc->caps.color.dpp.ocsc);
 
DTN_INFO("MPCC:  OPP  DPP  MPCCBOT  MODE  ALPHA_MODE  PREMULT  
OVERLAP_ONLY  IDLE\n");
for (i = 0; i < pool->pipe_count; i++) {
@@ -359,6 +377,11 @@ static void dcn10_log_color_state(struct dc *dc,
s.idle);
}
DTN_INFO("\n");
+   DTN_INFO("MPC Color Caps: gamut_remap:%d, 3dlut:%d, ogam_ram:%d, 
ocsc:%d\n\n",
+dc->caps.color.mpc.gamut_remap,
+dc->caps.color.mpc.num_3dluts,
+dc->caps.color.mpc.ogam_ram,
+dc->caps.color.mpc.ocsc);
 }
 
 void dcn10_log_hw_state(struct dc *dc,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c 
b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
index 1e07f0a6be1f..3b38af592101 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
@@ -140,6 +140,24 @@ void dcn30_log_color_state(struct dc *dc,
DTN_INFO("\n");
}
DTN_INFO("\n");
+   DTN_INFO("DPP Color Caps: input_lut_shared:%d  icsc:%d"
+"  dgam_ram:%d  dgam_rom: 
srgb:%d,bt2020:%d,gamma2_2:%d,pq:%d,hlg:%d"
+"  post_csc:%d  gamcor:%d  dgam_rom_for_yuv:%d  3d_lut:%d"
+"  blnd_lut:%d  oscs:%d\n\n",
+dc->caps.color.dpp.input_lut_shared,
+dc->caps.color.dpp.icsc,
+dc->caps.color.dpp.dgam_ram,
+dc->caps.color.dpp.dgam_rom_caps.srgb,
+dc->caps.color.dpp.dgam_rom_caps.bt2020,
+dc->caps.color.dpp.dgam_rom_caps.gamma2_2,
+dc->caps.color.dpp.dgam_rom_caps.pq,
+dc->caps.color.dpp.dgam_rom_caps.hlg,
+dc->caps.color.dpp.post_csc,
+dc->caps.color.dpp.gamma_corr,
+dc->caps.color.dpp.dgam_rom_for_yuv,
+dc->caps.color.dpp.hw_3d_lut,
+dc->caps.color.dpp.ogam_ram,
+dc->caps.color.dpp.ocsc);
 
DTN_INFO("MPCC:  OPP  DPP  MPCCBOT  MODE  ALPHA_MODE  PREMULT  
OVERLAP_ONLY  IDLE"
 "  SHAPER mode  3DLUT mode  3DLUT bit-depth  3DLUT size  OGAM 
mode  OGAM LUT"
@@ -193,6 +211,11 @@ void dcn30_log_color_state(struct dc *dc,
 
}
DTN_INFO("\n");
+   DTN_INFO("MPC Color Caps: gamut_remap:%d, 3dlut:%d, ogam_ram:%d, 
ocsc:%d\n\n",
+dc->caps.color.mpc.gamut_remap,
+dc->caps.color.mpc.num_3dluts,
+dc->caps.color.mpc.ogam_ram,
+dc->caps.color.mpc.ocsc);
 }
 
 bool dcn30_set_blend_lut(
-- 
2.42.0



[PATCH v3 7/9] drm/amd/display: hook up DCN30 color blocks data to DTN log

2023-11-28 Thread Melissa Wen
Color caps changed between HW versions, which caused the DCN10 color
state sections in the DTN log to no longer match DCN3+ state. Create a
color state log specific to DCN3.0 and hook it up to DCN3.0+ and DCN3.1+
drivers.

rfc-v2:
- detail RAM mode for gamcor and blnd gamma blocks
- add MPC gamut remap matrix log

v3:
- read MPC gamut remap matrix in fixed 31.32 format
- extend to DCN3.0+ and DCN3.1+ drivers (Harry)

Signed-off-by: Melissa Wen 
---
 .../gpu/drm/amd/display/dc/dcn30/dcn30_init.c |   1 +
 .../drm/amd/display/dc/dcn301/dcn301_init.c   |   1 +
 .../gpu/drm/amd/display/dc/dcn31/dcn31_init.c |   1 +
 .../drm/amd/display/dc/dcn314/dcn314_init.c   |   1 +
 .../amd/display/dc/hwss/dcn10/dcn10_hwseq.c   |   5 +-
 .../amd/display/dc/hwss/dcn30/dcn30_hwseq.c   | 126 ++
 .../amd/display/dc/hwss/dcn30/dcn30_hwseq.h   |   3 +
 .../drm/amd/display/dc/hwss/hw_sequencer.h|   2 +
 8 files changed, 139 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c 
b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c
index 9894caedffed..4064e6b7f599 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c
@@ -68,6 +68,7 @@ static const struct hw_sequencer_funcs dcn30_funcs = {
.setup_stereo = dcn10_setup_stereo,
.set_avmute = dcn30_set_avmute,
.log_hw_state = dcn10_log_hw_state,
+   .log_color_state = dcn30_log_color_state,
.get_hw_state = dcn10_get_hw_state,
.clear_status_bits = dcn10_clear_status_bits,
.wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c 
b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c
index 6477009ce065..1a9122252702 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c
@@ -72,6 +72,7 @@ static const struct hw_sequencer_funcs dcn301_funcs = {
.setup_stereo = dcn10_setup_stereo,
.set_avmute = dcn30_set_avmute,
.log_hw_state = dcn10_log_hw_state,
+   .log_color_state = dcn30_log_color_state,
.get_hw_state = dcn10_get_hw_state,
.clear_status_bits = dcn10_clear_status_bits,
.wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c 
b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c
index 669f524bd064..61577a3678a0 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c
@@ -71,6 +71,7 @@ static const struct hw_sequencer_funcs dcn31_funcs = {
.setup_stereo = dcn10_setup_stereo,
.set_avmute = dcn30_set_avmute,
.log_hw_state = dcn10_log_hw_state,
+   .log_color_state = dcn30_log_color_state,
.get_hw_state = dcn10_get_hw_state,
.clear_status_bits = dcn10_clear_status_bits,
.wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c 
b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c
index ccb7e317e86a..094b912832c1 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c
@@ -73,6 +73,7 @@ static const struct hw_sequencer_funcs dcn314_funcs = {
.setup_stereo = dcn10_setup_stereo,
.set_avmute = dcn30_set_avmute,
.log_hw_state = dcn10_log_hw_state,
+   .log_color_state = dcn30_log_color_state,
.get_hw_state = dcn10_get_hw_state,
.clear_status_bits = dcn10_clear_status_bits,
.wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c 
b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
index f0a9f8818909..f7d9bcdbc6c6 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
@@ -374,7 +374,10 @@ void dcn10_log_hw_state(struct dc *dc,
 
dcn10_log_hubp_states(dc, log_ctx);
 
-   dcn10_log_color_state(dc, log_ctx);
+   if (dc->hwss.log_color_state)
+   dc->hwss.log_color_state(dc, log_ctx);
+   else
+   dcn10_log_color_state(dc, log_ctx);
 
DTN_INFO("OTG:  v_bs  v_be  v_ss  v_se  vpol  vmax  vmin  vmax_sel  
vmin_sel  h_bs  h_be  h_ss  h_se  hpol  htot  vtot  underflow blank_en\n");
 
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c 
b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
index d71faf2ecd41..1e07f0a6be1f 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
@@ -69,6 +69,132 @@
 #define FN(reg_name, field_name) \
hws->shifts->field_name, hws->masks->field_name
 
+void dcn30_log_color_state(struct dc *dc,
+  struc

[PATCH v3 3/9] drm/amd/display: read gamut remap matrix in fixed-point 31.32 format

2023-11-28 Thread Melissa Wen
Instead of read gamut remap data from hw values, convert HW register
values (S2D13) into a fixed-point 31.32 matrix for color state log.
Change DCN10 log to print data in the format of the gamut remap matrix.

Signed-off-by: Melissa Wen 
---
 .../amd/display/dc/hwss/dcn10/dcn10_hwseq.c   | 38 +--
 drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h   |  3 ++
 2 files changed, 29 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c 
b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
index 9b801488eb9d..f0a9f8818909 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
@@ -289,20 +289,26 @@ static void dcn10_log_color_state(struct dc *dc,
struct resource_pool *pool = dc->res_pool;
int i;
 
-   DTN_INFO("DPP:IGAM format  IGAM modeDGAM modeRGAM mode"
-   "  GAMUT mode  C11 C12   C13 C14   C21 C22   C23 C24   "
-   "C31 C32   C33 C34\n");
+   DTN_INFO("DPP:IGAM formatIGAM modeDGAM modeRGAM mode"
+"  GAMUT adjust  "
+"C11C12C13C14"
+"C21C22C23C24"
+"C31C32C33C34\n");
for (i = 0; i < pool->pipe_count; i++) {
struct dpp *dpp = pool->dpps[i];
struct dcn_dpp_state s = {0};
 
dpp->funcs->dpp_read_state(dpp, );
+   dpp->funcs->dpp_get_gamut_remap(dpp, _remap);
 
if (!s.is_enabled)
continue;
 
-   DTN_INFO("[%2d]:  %11xh  %-11s  %-11s  %-11s"
-   "%8x%08xh %08xh %08xh %08xh %08xh %08xh",
+   DTN_INFO("[%2d]:  %11xh  %11s%9s%9s"
+"  %12s  "
+"%010lld %010lld %010lld %010lld "
+"%010lld %010lld %010lld %010lld "
+"%010lld %010lld %010lld %010lld",
dpp->inst,
s.igam_input_format,
(s.igam_lut_mode == 0) ? "BypassFixed" :
@@ -322,13 +328,21 @@ static void dcn10_log_color_state(struct dc *dc,
((s.rgam_lut_mode == 3) ? "RAM" :
((s.rgam_lut_mode == 4) ? "RAM" :
 "Unknown",
-   s.gamut_remap_mode,
-   s.gamut_remap_c11_c12,
-   s.gamut_remap_c13_c14,
-   s.gamut_remap_c21_c22,
-   s.gamut_remap_c23_c24,
-   s.gamut_remap_c31_c32,
-   s.gamut_remap_c33_c34);
+   (s.gamut_remap.gamut_adjust_type == 0) ? 
"Bypass" :
+   ((s.gamut_remap.gamut_adjust_type == 1) 
? "HW" :
+   
  "SW"),
+   s.gamut_remap.temperature_matrix[0].value,
+   s.gamut_remap.temperature_matrix[1].value,
+   s.gamut_remap.temperature_matrix[2].value,
+   s.gamut_remap.temperature_matrix[3].value,
+   s.gamut_remap.temperature_matrix[4].value,
+   s.gamut_remap.temperature_matrix[5].value,
+   s.gamut_remap.temperature_matrix[6].value,
+   s.gamut_remap.temperature_matrix[7].value,
+   s.gamut_remap.temperature_matrix[8].value,
+   s.gamut_remap.temperature_matrix[9].value,
+   s.gamut_remap.temperature_matrix[10].value,
+   s.gamut_remap.temperature_matrix[11].value);
DTN_INFO("\n");
}
DTN_INFO("\n");
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h 
b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
index 597ebdb4da4c..b6acfd86642a 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
@@ -141,6 +141,7 @@ struct dcn_dpp_state {
uint32_t igam_input_format;
uint32_t dgam_lut_mode;
uint32_t rgam_lut_mode;
+   // gamut_remap data for dcn10_get_cm_states()
uint32_t gamut_remap_mode;
uint32_t gamut_remap_c11_c1

[PATCH v3 5/9] drm/amd/display: add get_gamut_remap helper for MPC3

2023-11-28 Thread Melissa Wen
We want to be able to read the MPC's gamut remap matrix similar to
what we do with .dpp_get_gamut_remap functions. On the other hand, we
don't need a hook here because only DCN3+ has the MPC gamut remap
block, being absent in previous families.

Signed-off-by: Melissa Wen 
---
 .../gpu/drm/amd/display/dc/dcn30/dcn30_mpc.c  | 58 +++
 .../gpu/drm/amd/display/dc/dcn30/dcn30_mpc.h  |  4 ++
 2 files changed, 62 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.c 
b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.c
index d1500b223858..a6a4c3413f89 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.c
@@ -1129,6 +1129,64 @@ void mpc3_set_gamut_remap(
}
 }
 
+static void read_gamut_remap(struct dcn30_mpc *mpc30,
+int mpcc_id,
+uint16_t *regval,
+uint32_t *select)
+{
+   struct color_matrices_reg gam_regs;
+
+   //current coefficient set in use
+   REG_GET(MPCC_GAMUT_REMAP_MODE[mpcc_id], MPCC_GAMUT_REMAP_MODE_CURRENT, 
select);
+
+   gam_regs.shifts.csc_c11 = mpc30->mpc_shift->MPCC_GAMUT_REMAP_C11_A;
+   gam_regs.masks.csc_c11  = mpc30->mpc_mask->MPCC_GAMUT_REMAP_C11_A;
+   gam_regs.shifts.csc_c12 = mpc30->mpc_shift->MPCC_GAMUT_REMAP_C12_A;
+   gam_regs.masks.csc_c12 = mpc30->mpc_mask->MPCC_GAMUT_REMAP_C12_A;
+
+   if (*select == GAMUT_REMAP_COEFF) {
+   gam_regs.csc_c11_c12 = REG(MPC_GAMUT_REMAP_C11_C12_A[mpcc_id]);
+   gam_regs.csc_c33_c34 = REG(MPC_GAMUT_REMAP_C33_C34_A[mpcc_id]);
+
+   cm_helper_read_color_matrices(
+   mpc30->base.ctx,
+   regval,
+   _regs);
+
+   } else  if (*select == GAMUT_REMAP_COMA_COEFF) {
+
+   gam_regs.csc_c11_c12 = REG(MPC_GAMUT_REMAP_C11_C12_B[mpcc_id]);
+   gam_regs.csc_c33_c34 = REG(MPC_GAMUT_REMAP_C33_C34_B[mpcc_id]);
+
+   cm_helper_read_color_matrices(
+   mpc30->base.ctx,
+   regval,
+   _regs);
+
+   }
+
+}
+
+void mpc3_get_gamut_remap(struct mpc *mpc,
+ int mpcc_id,
+ struct mpc_grph_gamut_adjustment *adjust)
+{
+   struct dcn30_mpc *mpc30 = TO_DCN30_MPC(mpc);
+   uint16_t arr_reg_val[12];
+   int select;
+
+   read_gamut_remap(mpc30, mpcc_id, arr_reg_val, );
+
+   if (select == GAMUT_REMAP_BYPASS) {
+   adjust->gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
+   return;
+   }
+
+   adjust->gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
+   convert_hw_matrix(adjust->temperature_matrix,
+ arr_reg_val, ARRAY_SIZE(arr_reg_val));
+}
+
 bool mpc3_program_3dlut(
struct mpc *mpc,
const struct tetrahedral_params *params,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.h 
b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.h
index 5198f2167c7c..9cb96ae95a2f 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.h
@@ -1056,6 +1056,10 @@ void mpc3_set_gamut_remap(
int mpcc_id,
const struct mpc_grph_gamut_adjustment *adjust);
 
+void mpc3_get_gamut_remap(struct mpc *mpc,
+ int mpcc_id,
+ struct mpc_grph_gamut_adjustment *adjust);
+
 void mpc3_set_rmu_mux(
struct mpc *mpc,
int rmu_idx,
-- 
2.42.0



[PATCH v3 2/9] drm/amd/display: Add dpp_get_gamut_remap functions

2023-11-28 Thread Melissa Wen
From: Harry Wentland 

We want to be able to read the DPP's gamut remap matrix.

v2:
- code-style and doc comments clean-up (Melissa)

Signed-off-by: Harry Wentland 
Signed-off-by: Melissa Wen 
---
 .../drm/amd/display/dc/basics/conversion.c| 34 +
 .../drm/amd/display/dc/basics/conversion.h|  4 ++
 .../amd/display/dc/dcn10/dcn10_cm_common.c| 20 ++
 .../amd/display/dc/dcn10/dcn10_cm_common.h|  4 +-
 .../gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c  |  3 +-
 .../gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h  |  3 +
 .../drm/amd/display/dc/dcn10/dcn10_dpp_cm.c   | 70 ++-
 .../gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c  |  1 +
 .../gpu/drm/amd/display/dc/dcn20/dcn20_dpp.h  |  3 +
 .../drm/amd/display/dc/dcn20/dcn20_dpp_cm.c   | 55 +++
 .../drm/amd/display/dc/dcn201/dcn201_dpp.c|  1 +
 .../gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c  |  1 +
 .../gpu/drm/amd/display/dc/dcn30/dcn30_dpp.h  |  2 +
 .../drm/amd/display/dc/dcn30/dcn30_dpp_cm.c   | 54 ++
 .../gpu/drm/amd/display/dc/dcn32/dcn32_dpp.c  |  1 +
 drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h   |  3 +
 16 files changed, 256 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/basics/conversion.c 
b/drivers/gpu/drm/amd/display/dc/basics/conversion.c
index e295a839ab47..f0065a51beb9 100644
--- a/drivers/gpu/drm/amd/display/dc/basics/conversion.c
+++ b/drivers/gpu/drm/amd/display/dc/basics/conversion.c
@@ -101,6 +101,40 @@ void convert_float_matrix(
}
 }
 
+static struct fixed31_32 int_frac_to_fixed_point(uint16_t arg,
+uint8_t integer_bits,
+uint8_t fractional_bits)
+{
+   struct fixed31_32 result;
+   uint16_t sign_mask = 1 << (fractional_bits + integer_bits);
+   uint16_t value_mask = sign_mask - 1;
+
+   result.value = (long long)(arg & value_mask) <<
+  (FIXED31_32_BITS_PER_FRACTIONAL_PART - fractional_bits);
+
+   if (arg & sign_mask)
+   result = dc_fixpt_neg(result);
+
+   return result;
+}
+
+/**
+ * convert_hw_matrix - converts HW values into fixed31_32 matrix.
+ * @matrix: fixed point 31.32 matrix
+ * @reg: array of register values
+ * @buffer_size: size of the array of register values
+ *
+ * Converts HW register spec defined format S2D13 into a fixed-point 31.32
+ * matrix.
+ */
+void convert_hw_matrix(struct fixed31_32 *matrix,
+  uint16_t *reg,
+  uint32_t buffer_size)
+{
+   for (int i = 0; i < buffer_size; ++i)
+   matrix[i] = int_frac_to_fixed_point(reg[i], 2, 13);
+}
+
 static uint32_t find_gcd(uint32_t a, uint32_t b)
 {
uint32_t remainder = 0;
diff --git a/drivers/gpu/drm/amd/display/dc/basics/conversion.h 
b/drivers/gpu/drm/amd/display/dc/basics/conversion.h
index 81da4e6f7a1a..a433cef78496 100644
--- a/drivers/gpu/drm/amd/display/dc/basics/conversion.h
+++ b/drivers/gpu/drm/amd/display/dc/basics/conversion.h
@@ -41,6 +41,10 @@ void convert_float_matrix(
 void reduce_fraction(uint32_t num, uint32_t den,
uint32_t *out_num, uint32_t *out_den);
 
+void convert_hw_matrix(struct fixed31_32 *matrix,
+  uint16_t *reg,
+  uint32_t buffer_size);
+
 static inline unsigned int log_2(unsigned int num)
 {
return ilog2(num);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c 
b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c
index 3538973bd0c6..b7e57aa27361 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c
@@ -62,6 +62,26 @@ void cm_helper_program_color_matrices(
 
 }
 
+void cm_helper_read_color_matrices(struct dc_context *ctx,
+  uint16_t *regval,
+  const struct color_matrices_reg *reg)
+{
+   uint32_t cur_csc_reg, regval0, regval1;
+   unsigned int i = 0;
+
+   for (cur_csc_reg = reg->csc_c11_c12;
+cur_csc_reg <= reg->csc_c33_c34; cur_csc_reg++) {
+   REG_GET_2(cur_csc_reg,
+   csc_c11, ,
+   csc_c12, );
+
+   regval[2 * i] = regval0;
+   regval[(2 * i) + 1] = regval1;
+
+   i++;
+   }
+}
+
 void cm_helper_program_xfer_func(
struct dc_context *ctx,
const struct pwl_params *params,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h 
b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h
index 0a68b63d6126..decc50b1ac53 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h
@@ -114,5 +114,7 @@ bool cm_helper_translate_curve_to_degamma_hw_format(
const struct dc_transfer_func *output_tf,
 

[PATCH v3 4/9] drm/amd/display: fill up DCN3 DPP color state

2023-11-28 Thread Melissa Wen
DCN3 DPP color state was uncollected and some state elements from DCN1
doesn't fit DCN3. Create new elements according to DCN3 color caps and
fill them up for DTN log output.

rfc-v2:
- fix reading of gamcor and blnd gamma states
- remove gamut remap register in favor of gamut remap matrix reading

Signed-off-by: Melissa Wen 
---
 .../gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c  | 37 ++-
 drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h   |  8 
 2 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c 
b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c
index 7c18f31bb56c..a3a769aad042 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c
@@ -44,12 +44,45 @@
 void dpp30_read_state(struct dpp *dpp_base, struct dcn_dpp_state *s)
 {
struct dcn3_dpp *dpp = TO_DCN30_DPP(dpp_base);
+   uint32_t gamcor_lut_mode, rgam_lut_mode;
 
REG_GET(DPP_CONTROL,
-   DPP_CLOCK_ENABLE, >is_enabled);
+   DPP_CLOCK_ENABLE, >is_enabled);
 
-   // TODO: Implement for DCN3
+   // Pre-degamma (ROM)
+   REG_GET_2(PRE_DEGAM,
+ PRE_DEGAM_MODE, >pre_dgam_mode,
+ PRE_DEGAM_SELECT, >pre_dgam_select);
+
+   // Gamma Correction (RAM)
+   REG_GET(CM_GAMCOR_CONTROL,
+   CM_GAMCOR_MODE_CURRENT, >gamcor_mode);
+   if (s->gamcor_mode) {
+   REG_GET(CM_GAMCOR_CONTROL, CM_GAMCOR_SELECT_CURRENT, 
_lut_mode);
+   if (!gamcor_lut_mode)
+   s->gamcor_mode = LUT_RAM_A; // Otherwise, LUT_RAM_B
+   }
+
+   // Shaper LUT (RAM), 3D LUT (mode, bit-depth, size)
+   REG_GET(CM_SHAPER_CONTROL,
+   CM_SHAPER_LUT_MODE, >shaper_lut_mode);
+   REG_GET(CM_3DLUT_MODE,
+   CM_3DLUT_MODE_CURRENT, >lut3d_mode);
+   REG_GET(CM_3DLUT_READ_WRITE_CONTROL,
+   CM_3DLUT_30BIT_EN, >lut3d_bit_depth);
+   REG_GET(CM_3DLUT_MODE,
+   CM_3DLUT_SIZE, >lut3d_size);
+
+   // Blend/Out Gamma (RAM)
+   REG_GET(CM_BLNDGAM_CONTROL,
+   CM_BLNDGAM_MODE_CURRENT, >rgam_lut_mode);
+   if (s->rgam_lut_mode){
+   REG_GET(CM_BLNDGAM_CONTROL, CM_BLNDGAM_SELECT_CURRENT, 
_lut_mode);
+   if (!rgam_lut_mode)
+   s->rgam_lut_mode = LUT_RAM_A; // Otherwise, LUT_RAM_B
+   }
 }
+
 /*program post scaler scs block in dpp CM*/
 void dpp3_program_post_csc(
struct dpp *dpp_base,
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h 
b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
index b6acfd86642a..4e604bf24f51 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
@@ -151,6 +151,14 @@ struct dcn_dpp_state {
uint32_t gamut_remap_c33_c34;
// gamut_remap data for dcn*_log_color_state()
struct dpp_grph_csc_adjustment gamut_remap;
+   uint32_t shaper_lut_mode;
+   uint32_t lut3d_mode;
+   uint32_t lut3d_bit_depth;
+   uint32_t lut3d_size;
+   uint32_t blnd_lut_mode;
+   uint32_t pre_dgam_mode;
+   uint32_t pre_dgam_select;
+   uint32_t gamcor_mode;
 };
 
 struct CM_bias_params {
-- 
2.42.0



[PATCH v3 1/9] drm/amd/display: decouple color state from hw state log

2023-11-28 Thread Melissa Wen
Prepare to hook up color state log according to the DCN version.

v3:
- put functions in single line (Siqueira)

Signed-off-by: Melissa Wen 
---
 .../amd/display/dc/hwss/dcn10/dcn10_hwseq.c   | 26 +--
 1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c 
b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
index 2b8b8366538e..9b801488eb9d 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
@@ -282,19 +282,13 @@ static void dcn10_log_hubp_states(struct dc *dc, void 
*log_ctx)
DTN_INFO("\n");
 }
 
-void dcn10_log_hw_state(struct dc *dc,
-   struct dc_log_buffer_ctx *log_ctx)
+static void dcn10_log_color_state(struct dc *dc,
+ struct dc_log_buffer_ctx *log_ctx)
 {
struct dc_context *dc_ctx = dc->ctx;
struct resource_pool *pool = dc->res_pool;
int i;
 
-   DTN_INFO_BEGIN();
-
-   dcn10_log_hubbub_state(dc, log_ctx);
-
-   dcn10_log_hubp_states(dc, log_ctx);
-
DTN_INFO("DPP:IGAM format  IGAM modeDGAM modeRGAM mode"
"  GAMUT mode  C11 C12   C13 C14   C21 C22   C23 C24   "
"C31 C32   C33 C34\n");
@@ -351,6 +345,22 @@ void dcn10_log_hw_state(struct dc *dc,
s.idle);
}
DTN_INFO("\n");
+}
+
+void dcn10_log_hw_state(struct dc *dc,
+   struct dc_log_buffer_ctx *log_ctx)
+{
+   struct dc_context *dc_ctx = dc->ctx;
+   struct resource_pool *pool = dc->res_pool;
+   int i;
+
+   DTN_INFO_BEGIN();
+
+   dcn10_log_hubbub_state(dc, log_ctx);
+
+   dcn10_log_hubp_states(dc, log_ctx);
+
+   dcn10_log_color_state(dc, log_ctx);
 
DTN_INFO("OTG:  v_bs  v_be  v_ss  v_se  vpol  vmax  vmin  vmax_sel  
vmin_sel  h_bs  h_be  h_ss  h_se  hpol  htot  vtot  underflow blank_en\n");
 
-- 
2.42.0



[PATCH v3 0/9] drm/amd/display: improve DTN color state log

2023-11-28 Thread Melissa Wen
/20231116195812.906115-1-m...@igalia.com/
[3] 
https://github.com/ValveSoftware/gamescope/blob/master/src/docs/Steam%20Deck%20Display%20Pipeline.png


Harry Wentland (1):
  drm/amd/display: Add dpp_get_gamut_remap functions

Melissa Wen (8):
  drm/amd/display: decouple color state from hw state log
  drm/amd/display: read gamut remap matrix in fixed-point 31.32 format
  drm/amd/display: fill up DCN3 DPP color state
  drm/amd/display: add get_gamut_remap helper for MPC3
  drm/amd/display: create DCN3-specific log for MPC state
  drm/amd/display: hook up DCN30 color blocks data to DTN log
  drm/amd/display: add DPP and MPC color caps to DTN log
  drm/amd/display: hook up DCN20 color blocks data to DTN log

 .../drm/amd/display/dc/basics/conversion.c|  34 
 .../drm/amd/display/dc/basics/conversion.h|   4 +
 .../amd/display/dc/dcn10/dcn10_cm_common.c|  20 +++
 .../amd/display/dc/dcn10/dcn10_cm_common.h|   4 +-
 .../gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c  |   3 +-
 .../gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h  |   3 +
 .../drm/amd/display/dc/dcn10/dcn10_dpp_cm.c   |  70 +++-
 .../gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c  |  31 ++--
 .../gpu/drm/amd/display/dc/dcn20/dcn20_dpp.h  |   3 +
 .../drm/amd/display/dc/dcn20/dcn20_dpp_cm.c   |  55 +++
 .../gpu/drm/amd/display/dc/dcn20/dcn20_init.c |   1 +
 .../gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c  |  24 ++-
 .../drm/amd/display/dc/dcn201/dcn201_dpp.c|   1 +
 .../gpu/drm/amd/display/dc/dcn21/dcn21_init.c |   1 +
 .../gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c  |  38 -
 .../gpu/drm/amd/display/dc/dcn30/dcn30_dpp.h  |   2 +
 .../drm/amd/display/dc/dcn30/dcn30_dpp_cm.c   |  54 +++
 .../gpu/drm/amd/display/dc/dcn30/dcn30_init.c |   1 +
 .../gpu/drm/amd/display/dc/dcn30/dcn30_mpc.c  | 106 -
 .../gpu/drm/amd/display/dc/dcn30/dcn30_mpc.h  |   4 +
 .../drm/amd/display/dc/dcn301/dcn301_init.c   |   1 +
 .../gpu/drm/amd/display/dc/dcn31/dcn31_init.c |   1 +
 .../drm/amd/display/dc/dcn314/dcn314_init.c   |   1 +
 .../gpu/drm/amd/display/dc/dcn32/dcn32_dpp.c  |   1 +
 .../amd/display/dc/hwss/dcn10/dcn10_hwseq.c   |  90 ---
 .../amd/display/dc/hwss/dcn20/dcn20_hwseq.c   | 106 +
 .../amd/display/dc/hwss/dcn20/dcn20_hwseq.h   |   2 +
 .../amd/display/dc/hwss/dcn30/dcn30_hwseq.c   | 149 ++
 .../amd/display/dc/hwss/dcn30/dcn30_hwseq.h   |   3 +
 .../drm/amd/display/dc/hwss/hw_sequencer.h|   2 +
 drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h   |  14 ++
 drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h   |   7 +
 32 files changed, 795 insertions(+), 41 deletions(-)

-- 
2.42.0



[PATCH v5 31/32] drm/amd/display: add plane CTM support

2023-11-16 Thread Melissa Wen
Map the plane CTM driver-specific property to DC plane, instead of DC
stream. The remaining steps to program DPP block are already implemented
on DC shared-code.

v3:
- fix comment about plane and CRTC CTMs priorities (Harry)

Reviewed-by: Harry Wentland 
Signed-off-by: Melissa Wen 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  1 +
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 26 +++
 2 files changed, 27 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index ef39255bb37e..e5f1086da09f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -9686,6 +9686,7 @@ static bool should_reset_plane(struct drm_atomic_state 
*state,
if (dm_old_other_state->degamma_tf != 
dm_new_other_state->degamma_tf ||
dm_old_other_state->degamma_lut != 
dm_new_other_state->degamma_lut ||
dm_old_other_state->hdr_mult != 
dm_new_other_state->hdr_mult ||
+   dm_old_other_state->ctm != dm_new_other_state->ctm ||
dm_old_other_state->shaper_lut != 
dm_new_other_state->shaper_lut ||
dm_old_other_state->shaper_tf != 
dm_new_other_state->shaper_tf ||
dm_old_other_state->lut3d != dm_new_other_state->lut3d ||
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 3eed47736b26..d52cea13 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -1172,6 +1172,8 @@ int amdgpu_dm_update_plane_color_mgmt(struct 
dm_crtc_state *crtc,
  struct dc_plane_state *dc_plane_state)
 {
struct amdgpu_device *adev = drm_to_adev(crtc->base.state->dev);
+   struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
+   struct drm_color_ctm *ctm = NULL;
struct dc_color_caps *color_caps = NULL;
bool has_crtc_cm_degamma;
int ret;
@@ -1224,5 +1226,29 @@ int amdgpu_dm_update_plane_color_mgmt(struct 
dm_crtc_state *crtc,
return ret;
}
 
+   /* Setup CRTC CTM. */
+   if (dm_plane_state->ctm) {
+   ctm = (struct drm_color_ctm *)dm_plane_state->ctm->data;
+   /*
+* DCN2 and older don't support both pre-blending and
+* post-blending gamut remap. For this HW family, if we have
+* the plane and CRTC CTMs simultaneously, CRTC CTM takes
+* priority, and we discard plane CTM, as implemented in
+* dcn10_program_gamut_remap(). However, DCN3+ has DPP
+* (pre-blending) and MPC (post-blending) `gamut remap` blocks;
+* therefore, we can program plane and CRTC CTMs together by
+* mapping CRTC CTM to MPC and keeping plane CTM setup at DPP,
+* as it's done by dcn30_program_gamut_remap().
+*/
+   __drm_ctm_to_dc_matrix(ctm, 
dc_plane_state->gamut_remap_matrix.matrix);
+
+   dc_plane_state->gamut_remap_matrix.enable_remap = true;
+   dc_plane_state->input_csc_color_matrix.enable_adjustment = 
false;
+   } else {
+   /* Bypass CTM. */
+   dc_plane_state->gamut_remap_matrix.enable_remap = false;
+   dc_plane_state->input_csc_color_matrix.enable_adjustment = 
false;
+   }
+
return amdgpu_dm_plane_set_color_properties(plane_state, 
dc_plane_state);
 }
-- 
2.40.1



[PATCH v5 28/32] drm/amd/display: allow newer DC hardware to use degamma ROM for PQ/HLG

2023-11-16 Thread Melissa Wen
From: Joshua Ashton 

Need to funnel the color caps through to these functions so it can check
that the hardware is capable.

v2:
- remove redundant color caps assignment on plane degamma map (Harry)
- pass color caps to degamma params

v3:
- remove unused color_caps parameter from set_color_properties (Harry)

Reviewed-by: Harry Wentland 
Signed-off-by: Joshua Ashton 
Signed-off-by: Melissa Wen 
---
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 29 ---
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 27ddc6576719..3a1ca13eaee4 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -565,6 +565,7 @@ static int amdgpu_dm_set_atomic_regamma(struct 
dc_stream_state *stream,
 /**
  * __set_input_tf - calculates the input transfer function based on expected
  * input space.
+ * @caps: dc color capabilities
  * @func: transfer function
  * @lut: lookup table that defines the color space
  * @lut_size: size of respective lut.
@@ -572,7 +573,7 @@ static int amdgpu_dm_set_atomic_regamma(struct 
dc_stream_state *stream,
  * Returns:
  * 0 in case of success. -ENOMEM if fails.
  */
-static int __set_input_tf(struct dc_transfer_func *func,
+static int __set_input_tf(struct dc_color_caps *caps, struct dc_transfer_func 
*func,
  const struct drm_color_lut *lut, uint32_t lut_size)
 {
struct dc_gamma *gamma = NULL;
@@ -589,7 +590,7 @@ static int __set_input_tf(struct dc_transfer_func *func,
__drm_lut_to_dc_gamma(lut, gamma, false);
}
 
-   res = mod_color_calculate_degamma_params(NULL, func, gamma, gamma != 
NULL);
+   res = mod_color_calculate_degamma_params(caps, func, gamma, gamma != 
NULL);
 
if (gamma)
dc_gamma_release();
@@ -753,7 +754,7 @@ static int amdgpu_dm_atomic_blend_lut(const struct 
drm_color_lut *blend_lut,
func_blend->tf = tf;
func_blend->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
 
-   ret = __set_input_tf(func_blend, blend_lut, blend_size);
+   ret = __set_input_tf(NULL, func_blend, blend_lut, blend_size);
} else {
func_blend->type = TF_TYPE_BYPASS;
func_blend->tf = TRANSFER_FUNCTION_LINEAR;
@@ -969,7 +970,8 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state 
*crtc)
 
 static int
 map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc,
-struct dc_plane_state *dc_plane_state)
+struct dc_plane_state *dc_plane_state,
+struct dc_color_caps *caps)
 {
const struct drm_color_lut *degamma_lut;
enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB;
@@ -1024,7 +1026,7 @@ map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc,
dc_plane_state->in_transfer_func->tf =
TRANSFER_FUNCTION_LINEAR;
 
-   r = __set_input_tf(dc_plane_state->in_transfer_func,
+   r = __set_input_tf(caps, dc_plane_state->in_transfer_func,
   degamma_lut, degamma_size);
if (r)
return r;
@@ -1037,7 +1039,7 @@ map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc,
dc_plane_state->in_transfer_func->tf = tf;
 
if (tf != TRANSFER_FUNCTION_SRGB &&
-   !mod_color_calculate_degamma_params(NULL,
+   !mod_color_calculate_degamma_params(caps,

dc_plane_state->in_transfer_func,
NULL, false))
return -ENOMEM;
@@ -1048,7 +1050,8 @@ map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc,
 
 static int
 __set_dm_plane_degamma(struct drm_plane_state *plane_state,
-  struct dc_plane_state *dc_plane_state)
+  struct dc_plane_state *dc_plane_state,
+  struct dc_color_caps *color_caps)
 {
struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
const struct drm_color_lut *degamma_lut;
@@ -1079,7 +1082,7 @@ __set_dm_plane_degamma(struct drm_plane_state 
*plane_state,
dc_plane_state->in_transfer_func->type =
TF_TYPE_DISTRIBUTED_POINTS;
 
-   ret = __set_input_tf(dc_plane_state->in_transfer_func,
+   ret = __set_input_tf(color_caps, 
dc_plane_state->in_transfer_func,
 degamma_lut, degamma_size);
if (ret)
return ret;
@@ -1087,7 +1090,7 @@ __set_dm_plane_degamma(struct drm_plane_state 
*plane_state,
 

[PATCH v5 29/32] drm/amd/display: copy 3D LUT settings from crtc state to stream_update

2023-11-16 Thread Melissa Wen
From: Joshua Ashton 

When commiting planes, we copy color mgmt resources to the stream state.
Do the same for shaper and 3D LUTs.

Reviewed-by: Harry Wentland 
Signed-off-by: Joshua Ashton 
Co-developed-by: Melissa Wen 
Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 277b4bc82bcf..ef39255bb37e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -8369,6 +8369,10 @@ static void amdgpu_dm_commit_planes(struct 
drm_atomic_state *state,
_state->stream->csc_color_matrix;
bundle->stream_update.out_transfer_func =
acrtc_state->stream->out_transfer_func;
+   bundle->stream_update.lut3d_func =
+   (struct dc_3dlut *) 
acrtc_state->stream->lut3d_func;
+   bundle->stream_update.func_shaper =
+   (struct dc_transfer_func *) 
acrtc_state->stream->func_shaper;
}
 
acrtc_state->stream->abm_level = acrtc_state->abm_level;
-- 
2.40.1



[PATCH v5 21/32] drm/amd/display: add dc_fixpt_from_s3132 helper

2023-11-16 Thread Melissa Wen
From: Joshua Ashton 

Detach value translation from CTM to reuse it for programming HDR
multiplier property.

Reviewed-by: Harry Wentland 
Signed-off-by: Joshua Ashton 
Signed-off-by: Melissa Wen 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c  |  8 +---
 drivers/gpu/drm/amd/display/include/fixed31_32.h | 12 
 2 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 8fc715fa426c..c160dbef5224 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -405,7 +405,6 @@ static void __drm_lut_to_dc_gamma(const struct 
drm_color_lut *lut,
 static void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm,
   struct fixed31_32 *matrix)
 {
-   int64_t val;
int i;
 
/*
@@ -424,12 +423,7 @@ static void __drm_ctm_to_dc_matrix(const struct 
drm_color_ctm *ctm,
}
 
/* gamut_remap_matrix[i] = ctm[i - floor(i/4)] */
-   val = ctm->matrix[i - (i / 4)];
-   /* If negative, convert to 2's complement. */
-   if (val & (1ULL << 63))
-   val = -(val & ~(1ULL << 63));
-
-   matrix[i].value = val;
+   matrix[i] = dc_fixpt_from_s3132(ctm->matrix[i - (i / 4)]);
}
 }
 
diff --git a/drivers/gpu/drm/amd/display/include/fixed31_32.h 
b/drivers/gpu/drm/amd/display/include/fixed31_32.h
index d4cf7ead1d87..84da1dd34efd 100644
--- a/drivers/gpu/drm/amd/display/include/fixed31_32.h
+++ b/drivers/gpu/drm/amd/display/include/fixed31_32.h
@@ -69,6 +69,18 @@ static const struct fixed31_32 dc_fixpt_epsilon = { 1LL };
 static const struct fixed31_32 dc_fixpt_half = { 0x8000LL };
 static const struct fixed31_32 dc_fixpt_one = { 0x1LL };
 
+static inline struct fixed31_32 dc_fixpt_from_s3132(__u64 x)
+{
+   struct fixed31_32 val;
+
+   /* If negative, convert to 2's complement. */
+   if (x & (1ULL << 63))
+   x = -(x & ~(1ULL << 63));
+
+   val.value = x;
+   return val;
+}
+
 /*
  * @brief
  * Initialization routines
-- 
2.40.1



[PATCH v5 24/32] drm/amd/display: add plane shaper TF support

2023-11-16 Thread Melissa Wen
Enable usage of predefined transfer func in addition to shaper 1D LUT.
That means we can save some complexity by just setting a predefined
curve, instead of programming a custom curve when preparing color space
for applying 3D LUT.

Reviewed-by: Harry Wentland 
Signed-off-by: Melissa Wen 
---
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_color.c   | 15 +++
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index daa500b04cb5..8239904f9d90 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -624,20 +624,23 @@ amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf)
 }
 
 static int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut,
+  bool has_rom,
+  enum dc_transfer_func_predefined tf,
   uint32_t shaper_size,
   struct dc_transfer_func *func_shaper)
 {
int ret = 0;
 
-   if (shaper_size) {
+   if (shaper_size || tf != TRANSFER_FUNCTION_LINEAR) {
/*
 * If user shaper LUT is set, we assume a linear color space
 * (linearized by degamma 1D LUT or not).
 */
func_shaper->type = TF_TYPE_DISTRIBUTED_POINTS;
-   func_shaper->tf = TRANSFER_FUNCTION_LINEAR;
+   func_shaper->tf = tf;
+   func_shaper->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
 
-   ret = __set_output_tf(func_shaper, shaper_lut, shaper_size, 
false);
+   ret = __set_output_tf(func_shaper, shaper_lut, shaper_size, 
has_rom);
} else {
func_shaper->type = TF_TYPE_BYPASS;
func_shaper->tf = TRANSFER_FUNCTION_LINEAR;
@@ -972,6 +975,7 @@ amdgpu_dm_plane_set_color_properties(struct drm_plane_state 
*plane_state,
 struct dc_plane_state *dc_plane_state)
 {
struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
+   enum amdgpu_transfer_function shaper_tf = 
AMDGPU_TRANSFER_FUNCTION_DEFAULT;
const struct drm_color_lut *shaper_lut;
uint32_t shaper_size;
int ret;
@@ -980,8 +984,11 @@ amdgpu_dm_plane_set_color_properties(struct 
drm_plane_state *plane_state,
 
shaper_lut = __extract_blob_lut(dm_plane_state->shaper_lut, 
_size);
shaper_size = shaper_lut != NULL ? shaper_size : 0;
+   shaper_tf = dm_plane_state->shaper_tf;
 
-   ret = amdgpu_dm_atomic_shaper_lut(shaper_lut, shaper_size,
+   ret = amdgpu_dm_atomic_shaper_lut(shaper_lut, false,
+ amdgpu_tf_to_dc_tf(shaper_tf),
+ shaper_size,
  dc_plane_state->in_shaper_func);
if (ret)
drm_dbg_kms(plane_state->plane->dev,
-- 
2.40.1



[PATCH v5 32/32] drm/amd/display: Add 3x4 CTM support for plane CTM

2023-11-16 Thread Melissa Wen
From: Joshua Ashton 

Create drm_color_ctm_3x4 to support 3x4-dimension plane CTM matrix and
convert DRM CTM to DC CSC float matrix.

v3:
- rename ctm2 to ctm_3x4 (Harry)

Reviewed-by: Harry Wentland 
Signed-off-by: Joshua Ashton 
---
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 28 +--
 .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   |  2 +-
 include/uapi/drm/drm_mode.h   |  8 ++
 3 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index d52cea13..96aecc1a71a3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -434,6 +434,28 @@ static void __drm_ctm_to_dc_matrix(const struct 
drm_color_ctm *ctm,
}
 }
 
+/**
+ * __drm_ctm_3x4_to_dc_matrix - converts a DRM CTM 3x4 to a DC CSC float matrix
+ * @ctm: DRM color transformation matrix with 3x4 dimensions
+ * @matrix: DC CSC float matrix
+ *
+ * The matrix needs to be a 3x4 (12 entry) matrix.
+ */
+static void __drm_ctm_3x4_to_dc_matrix(const struct drm_color_ctm_3x4 *ctm,
+  struct fixed31_32 *matrix)
+{
+   int i;
+
+   /* The format provided is S31.32, using signed-magnitude representation.
+* Our fixed31_32 is also S31.32, but is using 2's complement. We have
+* to convert from signed-magnitude to 2's complement.
+*/
+   for (i = 0; i < 12; i++) {
+   /* gamut_remap_matrix[i] = ctm[i - floor(i/4)] */
+   matrix[i] = dc_fixpt_from_s3132(ctm->matrix[i]);
+   }
+}
+
 /**
  * __set_legacy_tf - Calculates the legacy transfer function
  * @func: transfer function
@@ -1173,7 +1195,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct 
dm_crtc_state *crtc,
 {
struct amdgpu_device *adev = drm_to_adev(crtc->base.state->dev);
struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
-   struct drm_color_ctm *ctm = NULL;
+   struct drm_color_ctm_3x4 *ctm = NULL;
struct dc_color_caps *color_caps = NULL;
bool has_crtc_cm_degamma;
int ret;
@@ -1228,7 +1250,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct 
dm_crtc_state *crtc,
 
/* Setup CRTC CTM. */
if (dm_plane_state->ctm) {
-   ctm = (struct drm_color_ctm *)dm_plane_state->ctm->data;
+   ctm = (struct drm_color_ctm_3x4 *)dm_plane_state->ctm->data;
/*
 * DCN2 and older don't support both pre-blending and
 * post-blending gamut remap. For this HW family, if we have
@@ -1240,7 +1262,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct 
dm_crtc_state *crtc,
 * mapping CRTC CTM to MPC and keeping plane CTM setup at DPP,
 * as it's done by dcn30_program_gamut_remap().
 */
-   __drm_ctm_to_dc_matrix(ctm, 
dc_plane_state->gamut_remap_matrix.matrix);
+   __drm_ctm_3x4_to_dc_matrix(ctm, 
dc_plane_state->gamut_remap_matrix.matrix);
 
dc_plane_state->gamut_remap_matrix.enable_remap = true;
dc_plane_state->input_csc_color_matrix.enable_adjustment = 
false;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index f10c5154d06a..8a4c40b4c27e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -1561,7 +1561,7 @@ dm_atomic_plane_set_property(struct drm_plane *plane,
ret = drm_property_replace_blob_from_id(plane->dev,
_plane_state->ctm,
val,
-   sizeof(struct 
drm_color_ctm), -1,
+   sizeof(struct 
drm_color_ctm_3x4), -1,
);
dm_plane_state->base.color_mgmt_changed |= replaced;
return ret;
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index 46becedf5b2f..a811d24e8ed5 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -838,6 +838,14 @@ struct drm_color_ctm {
__u64 matrix[9];
 };
 
+struct drm_color_ctm_3x4 {
+   /*
+* Conversion matrix with 3x4 dimensions in S31.32 sign-magnitude
+* (not two's complement!) format.
+*/
+   __u64 matrix[12];
+};
+
 struct drm_color_lut {
/*
 * Values are mapped linearly to 0.0 - 1.0 range, with 0x0 == 0.0 and
-- 
2.40.1



[PATCH v5 27/32] drm/amd/display: add plane blend LUT and TF support

2023-11-16 Thread Melissa Wen
From: Joshua Ashton 

Map plane blend properties to DPP blend gamma. Plane blend is a
post-3D LUT curve that linearizes color space for blending. It may be
defined by a user-blob LUT and/or predefined transfer function. As
hardcoded curve (ROM) is not supported on blend gamma, we use AMD color
module to fill parameters when setting non-linear TF with empty LUT.

v2:
- rename DRM TFs to AMDGPU TFs

Reviewed-by: Harry Wentland 
Signed-off-by: Joshua Ashton 
Signed-off-by: Melissa Wen 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  1 +
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 56 +--
 2 files changed, 53 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 83b1440ad69a..277b4bc82bcf 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -8157,6 +8157,7 @@ static void amdgpu_dm_commit_planes(struct 
drm_atomic_state *state,
bundle->surface_updates[planes_count].hdr_mult = 
dc_plane->hdr_mult;
bundle->surface_updates[planes_count].func_shaper = 
dc_plane->in_shaper_func;
bundle->surface_updates[planes_count].lut3d_func = 
dc_plane->lut3d_func;
+   bundle->surface_updates[planes_count].blend_tf = 
dc_plane->blend_tf;
}
 
amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 738399538432..27ddc6576719 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -733,6 +733,35 @@ static int amdgpu_dm_atomic_shaper_lut(const struct 
drm_color_lut *shaper_lut,
return ret;
 }
 
+static int amdgpu_dm_atomic_blend_lut(const struct drm_color_lut *blend_lut,
+  bool has_rom,
+  enum dc_transfer_func_predefined tf,
+  uint32_t blend_size,
+  struct dc_transfer_func *func_blend)
+{
+   int ret = 0;
+
+   if (blend_size || tf != TRANSFER_FUNCTION_LINEAR) {
+   /*
+* DRM plane gamma LUT or TF means we are linearizing color
+* space before blending (similar to degamma programming). As
+* we don't have hardcoded curve support, or we use AMD color
+* module to fill the parameters that will be translated to HW
+* points.
+*/
+   func_blend->type = TF_TYPE_DISTRIBUTED_POINTS;
+   func_blend->tf = tf;
+   func_blend->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
+
+   ret = __set_input_tf(func_blend, blend_lut, blend_size);
+   } else {
+   func_blend->type = TF_TYPE_BYPASS;
+   func_blend->tf = TRANSFER_FUNCTION_LINEAR;
+   }
+
+   return ret;
+}
+
 /**
  * amdgpu_dm_verify_lut3d_size - verifies if 3D LUT is supported and if user
  * shaper and 3D LUTs match the hw supported size
@@ -1071,8 +1100,9 @@ amdgpu_dm_plane_set_color_properties(struct 
drm_plane_state *plane_state,
 {
struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
enum amdgpu_transfer_function shaper_tf = 
AMDGPU_TRANSFER_FUNCTION_DEFAULT;
-   const struct drm_color_lut *shaper_lut, *lut3d;
-   uint32_t shaper_size, lut3d_size;
+   enum amdgpu_transfer_function blend_tf = 
AMDGPU_TRANSFER_FUNCTION_DEFAULT;
+   const struct drm_color_lut *shaper_lut, *lut3d, *blend_lut;
+   uint32_t shaper_size, lut3d_size, blend_size;
int ret;
 
dc_plane_state->hdr_mult = 
dc_fixpt_from_s3132(dm_plane_state->hdr_mult);
@@ -1088,12 +1118,30 @@ amdgpu_dm_plane_set_color_properties(struct 
drm_plane_state *plane_state,
  amdgpu_tf_to_dc_tf(shaper_tf),
  shaper_size,
  dc_plane_state->in_shaper_func);
-   if (ret)
+   if (ret) {
drm_dbg_kms(plane_state->plane->dev,
"setting plane %d shaper LUT failed.\n",
plane_state->plane->index);
 
-   return ret;
+   return ret;
+   }
+
+   blend_tf = dm_plane_state->blend_tf;
+   blend_lut = __extract_blob_lut(dm_plane_state->blend_lut, _size);
+   blend_size = blend_lut != NULL ? blend_size : 0;
+
+   ret = amdgpu_dm_atomic_blend_lut(blend_lut, false,
+amdgpu_tf_to_dc_tf(blend_tf),
+blend_size, dc_plane_stat

[PATCH v5 30/32] drm/amd/display: add plane CTM driver-specific property

2023-11-16 Thread Melissa Wen
Plane CTM for pre-blending color space conversion. Only enable
driver-specific plane CTM property on drivers that support both pre- and
post-blending gamut remap matrix, i.e., DCN3+ family. Otherwise it
conflits with DRM CRTC CTM property.

Reviewed-by: Harry Wentland 
Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h  |  2 ++
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  7 +++
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   |  7 +++
 .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 21 +++
 4 files changed, 37 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index f4e74acd8dca..076d5762167a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -364,6 +364,8 @@ struct amdgpu_mode_info {
 * @plane_hdr_mult_property:
 */
struct drm_property *plane_hdr_mult_property;
+
+   struct drm_property *plane_ctm_property;
/**
 * @shaper_lut_property: Plane property to set pre-blending shaper LUT
 * that converts color content before 3D LUT. If
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 0a0193c00247..1893ff882074 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -776,6 +776,13 @@ struct dm_plane_state {
 * TF is needed for any subsequent linear-to-non-linear transforms.
 */
__u64 hdr_mult;
+   /**
+* @ctm:
+*
+* Color transformation matrix. The blob (if not NULL) is a 
+* drm_color_ctm_3x4.
+*/
+   struct drm_property_blob *ctm;
/**
 * @shaper_lut: shaper lookup table blob. The blob (if not NULL) is an
 * array of  drm_color_lut.
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 3a1ca13eaee4..3eed47736b26 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -240,6 +240,13 @@ amdgpu_dm_create_color_properties(struct amdgpu_device 
*adev)
return -ENOMEM;
adev->mode_info.plane_hdr_mult_property = prop;
 
+   prop = drm_property_create(adev_to_drm(adev),
+  DRM_MODE_PROP_BLOB,
+  "AMD_PLANE_CTM", 0);
+   if (!prop)
+   return -ENOMEM;
+   adev->mode_info.plane_ctm_property = prop;
+
prop = drm_property_create(adev_to_drm(adev),
   DRM_MODE_PROP_BLOB,
   "AMD_PLANE_SHAPER_LUT", 0);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index 35a4732483ba..f10c5154d06a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -1366,6 +1366,9 @@ static struct drm_plane_state 
*amdgpu_dm_plane_drm_plane_duplicate_state(struct
if (old_dm_plane_state->degamma_lut)
dm_plane_state->degamma_lut =
drm_property_blob_get(old_dm_plane_state->degamma_lut);
+   if (old_dm_plane_state->ctm)
+   dm_plane_state->ctm =
+   drm_property_blob_get(old_dm_plane_state->ctm);
if (old_dm_plane_state->shaper_lut)
dm_plane_state->shaper_lut =
drm_property_blob_get(old_dm_plane_state->shaper_lut);
@@ -1450,6 +1453,8 @@ static void 
amdgpu_dm_plane_drm_plane_destroy_state(struct drm_plane *plane,
 
if (dm_plane_state->degamma_lut)
drm_property_blob_put(dm_plane_state->degamma_lut);
+   if (dm_plane_state->ctm)
+   drm_property_blob_put(dm_plane_state->ctm);
if (dm_plane_state->lut3d)
drm_property_blob_put(dm_plane_state->lut3d);
if (dm_plane_state->shaper_lut)
@@ -1490,6 +1495,11 @@ dm_atomic_plane_attach_color_mgmt_properties(struct 
amdgpu_display_manager *dm,
   dm->adev->mode_info.plane_hdr_mult_property,
   AMDGPU_HDR_MULT_DEFAULT);
 
+   /* Only enable plane CTM if both DPP and MPC gamut remap is available. 
*/
+   if (dm->dc->caps.color.mpc.gamut_remap)
+   drm_object_attach_property(>base,
+  
dm->adev->mode_info.plane_ctm_property, 0);
+
if (dpp_color_caps.hw_3d_lut) {
drm_object_attach_property(>base,
   mode_info.plane_shaper_lut_property, 
0);
@@ -1547,6 +1557,14 @@ dm_atomic_

[PATCH v5 25/32] drm/amd/display: add plane 3D LUT support

2023-11-16 Thread Melissa Wen
Wire up DC 3D LUT to DM plane color management (pre-blending). On AMD
display HW, 3D LUT comes after a shaper curve and we always have to
program a shaper curve to delinearize or normalize the color space
before applying a 3D LUT (since we have a reduced number of LUT
entries).

In this version, the default values of 3D LUT for size and bit_depth are
17x17x17 and 12-bit, but we already provide here a more generic
mechanisms to program other supported values (9x9x9 size and 10-bit).

v2:
- started with plane 3D LUT instead of CRTC 3D LUT support

v4:
- lut3d_size is the max dimension size instead of # of entries

Reviewed-by: Harry Wentland 
Signed-off-by: Melissa Wen 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |   1 +
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 102 +-
 2 files changed, 99 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index c94fdb3478c7..83b1440ad69a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -8156,6 +8156,7 @@ static void amdgpu_dm_commit_planes(struct 
drm_atomic_state *state,

bundle->surface_updates[planes_count].gamut_remap_matrix = 
_plane->gamut_remap_matrix;
bundle->surface_updates[planes_count].hdr_mult = 
dc_plane->hdr_mult;
bundle->surface_updates[planes_count].func_shaper = 
dc_plane->in_shaper_func;
+   bundle->surface_updates[planes_count].lut3d_func = 
dc_plane->lut3d_func;
}
 
amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 8239904f9d90..f55e0a69dd32 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -623,6 +623,86 @@ amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf)
}
 }
 
+static void __to_dc_lut3d_color(struct dc_rgb *rgb,
+   const struct drm_color_lut lut,
+   int bit_precision)
+{
+   rgb->red = drm_color_lut_extract(lut.red, bit_precision);
+   rgb->green = drm_color_lut_extract(lut.green, bit_precision);
+   rgb->blue  = drm_color_lut_extract(lut.blue, bit_precision);
+}
+
+static void __drm_3dlut_to_dc_3dlut(const struct drm_color_lut *lut,
+   uint32_t lut3d_size,
+   struct tetrahedral_params *params,
+   bool use_tetrahedral_9,
+   int bit_depth)
+{
+   struct dc_rgb *lut0;
+   struct dc_rgb *lut1;
+   struct dc_rgb *lut2;
+   struct dc_rgb *lut3;
+   int lut_i, i;
+
+
+   if (use_tetrahedral_9) {
+   lut0 = params->tetrahedral_9.lut0;
+   lut1 = params->tetrahedral_9.lut1;
+   lut2 = params->tetrahedral_9.lut2;
+   lut3 = params->tetrahedral_9.lut3;
+   } else {
+   lut0 = params->tetrahedral_17.lut0;
+   lut1 = params->tetrahedral_17.lut1;
+   lut2 = params->tetrahedral_17.lut2;
+   lut3 = params->tetrahedral_17.lut3;
+   }
+
+   for (lut_i = 0, i = 0; i < lut3d_size - 4; lut_i++, i += 4) {
+   /*
+* We should consider the 3D LUT RGB values are distributed
+* along four arrays lut0-3 where the first sizes 1229 and the
+* other 1228. The bit depth supported for 3dlut channel is
+* 12-bit, but DC also supports 10-bit.
+*
+* TODO: improve color pipeline API to enable the userspace set
+* bit depth and 3D LUT size/stride, as specified by VA-API.
+*/
+   __to_dc_lut3d_color([lut_i], lut[i], bit_depth);
+   __to_dc_lut3d_color([lut_i], lut[i + 1], bit_depth);
+   __to_dc_lut3d_color([lut_i], lut[i + 2], bit_depth);
+   __to_dc_lut3d_color([lut_i], lut[i + 3], bit_depth);
+   }
+   /* lut0 has 1229 points (lut_size/4 + 1) */
+   __to_dc_lut3d_color([lut_i], lut[i], bit_depth);
+}
+
+/* amdgpu_dm_atomic_lut3d - set DRM 3D LUT to DC stream
+ * @drm_lut3d: user 3D LUT
+ * @drm_lut3d_size: size of 3D LUT
+ * @lut3d: DC 3D LUT
+ *
+ * Map user 3D LUT data to DC 3D LUT and all necessary bits to program it
+ * on DCN accordingly.
+ */
+static void amdgpu_dm_atomic_lut3d(const struct drm_color_lut *drm_lut3d,
+  uint32_t drm_lut3d_size,
+  struct dc_3dlut *lut)
+{
+   if (!drm_lut3d_size) {
+   lut->state.bits.initialized = 0;
+   } else {
+

[PATCH v5 19/32] drm/amd/display: add plane degamma TF and LUT support

2023-11-16 Thread Melissa Wen
From: Joshua Ashton 

Set DC plane with user degamma LUT or predefined TF from driver-specific
plane color properties. If plane and CRTC degamma are set in the same
time, plane degamma has priority.  That means, we only set CRTC degamma
if we don't have plane degamma LUT or TF to configure. We return -EINVAL
if we don't have plane degamma settings, so we can continue and check
CRTC degamma.

Reviewed-by: Harry Wentland 
Signed-off-by: Joshua Ashton 
Signed-off-by: Melissa Wen 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  4 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  1 +
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 70 +--
 3 files changed, 69 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 8f82d9837a41..e694bc3c2d5f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -5092,7 +5092,9 @@ static int fill_dc_plane_attributes(struct amdgpu_device 
*adev,
 * Always set input transfer function, since plane state is refreshed
 * every time.
 */
-   ret = amdgpu_dm_update_plane_color_mgmt(dm_crtc_state, dc_plane_state);
+   ret = amdgpu_dm_update_plane_color_mgmt(dm_crtc_state,
+   plane_state,
+   dc_plane_state);
if (ret)
return ret;
 
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index b997bb287dda..daae70f618a7 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -910,6 +910,7 @@ int amdgpu_dm_create_color_properties(struct amdgpu_device 
*adev);
 int amdgpu_dm_verify_lut_sizes(const struct drm_crtc_state *crtc_state);
 int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc);
 int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc,
+ struct drm_plane_state *plane_state,
  struct dc_plane_state *dc_plane_state);
 
 void amdgpu_dm_update_connector_after_detect(
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index f13d22851fe4..13117516f2a4 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -868,9 +868,58 @@ map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc,
return 0;
 }
 
+static int
+__set_dm_plane_degamma(struct drm_plane_state *plane_state,
+  struct dc_plane_state *dc_plane_state)
+{
+   struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
+   const struct drm_color_lut *degamma_lut;
+   enum amdgpu_transfer_function tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT;
+   uint32_t degamma_size;
+   bool has_degamma_lut;
+   int ret;
+
+   degamma_lut = __extract_blob_lut(dm_plane_state->degamma_lut,
+_size);
+
+   has_degamma_lut = degamma_lut &&
+ !__is_lut_linear(degamma_lut, degamma_size);
+
+   tf = dm_plane_state->degamma_tf;
+
+   /* If we don't have plane degamma LUT nor TF to set on DC, we have
+* nothing to do here, return.
+*/
+   if (!has_degamma_lut && tf == AMDGPU_TRANSFER_FUNCTION_DEFAULT)
+   return -EINVAL;
+
+   dc_plane_state->in_transfer_func->tf = amdgpu_tf_to_dc_tf(tf);
+
+   if (has_degamma_lut) {
+   ASSERT(degamma_size == MAX_COLOR_LUT_ENTRIES);
+
+   dc_plane_state->in_transfer_func->type =
+   TF_TYPE_DISTRIBUTED_POINTS;
+
+   ret = __set_input_tf(dc_plane_state->in_transfer_func,
+degamma_lut, degamma_size);
+   if (ret)
+   return ret;
+   } else {
+   dc_plane_state->in_transfer_func->type =
+   TF_TYPE_PREDEFINED;
+
+   if (!mod_color_calculate_degamma_params(NULL,
+   dc_plane_state->in_transfer_func, NULL, false))
+   return -ENOMEM;
+   }
+   return 0;
+}
+
 /**
  * amdgpu_dm_update_plane_color_mgmt: Maps DRM color management to DC plane.
  * @crtc: amdgpu_dm crtc state
+ * @plane_state: DRM plane state
  * @dc_plane_state: target DC surface
  *
  * Update the underlying dc_stream_state's input transfer function (ITF) in
@@ -881,13 +930,28 @@ map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc,
  * 0 on success. -ENOMEM if mem allocation fails.
  */
 int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc,
+ struct drm_plane_state *plane_state

[PATCH v5 23/32] drm/amd/display: add plane shaper LUT support

2023-11-16 Thread Melissa Wen
Map DC shaper LUT to DM plane color management. Shaper LUT can be used
to delinearize and/or normalize the color space for computational
efficiency and achiving specific visual styles. If a plane degamma is
apply to linearize the color space, a custom shaper 1D LUT can be used
just before applying 3D LUT.

v2:
- use DPP color caps to verify plane 3D LUT support
- add debug message if shaper LUT programming fails

v4:
- remove helper to check 3D LUT color caps (Harry)
- update desc of lut3d-setup helper from MPC to DPP

v5:
- remove color_mgmt_changed check that prevents color updates (Joshua)

Reviewed-by: Harry Wentland 
Signed-off-by: Melissa Wen 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  1 +
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  2 +
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 93 ++-
 3 files changed, 92 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index aa91a4b245f6..c94fdb3478c7 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -8155,6 +8155,7 @@ static void amdgpu_dm_commit_planes(struct 
drm_atomic_state *state,
bundle->surface_updates[planes_count].in_transfer_func 
= dc_plane->in_transfer_func;

bundle->surface_updates[planes_count].gamut_remap_matrix = 
_plane->gamut_remap_matrix;
bundle->surface_updates[planes_count].hdr_mult = 
dc_plane->hdr_mult;
+   bundle->surface_updates[planes_count].func_shaper = 
dc_plane->in_shaper_func;
}
 
amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index daae70f618a7..0a0193c00247 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -900,6 +900,8 @@ void amdgpu_dm_trigger_timing_sync(struct drm_device *dev);
 /* 3D LUT max size is 17x17x17 (4913 entries) */
 #define MAX_COLOR_3DLUT_SIZE 17
 #define MAX_COLOR_3DLUT_BITDEPTH 12
+int amdgpu_dm_verify_lut3d_size(struct amdgpu_device *adev,
+   struct drm_plane_state *plane_state);
 /* 1D LUT size */
 #define MAX_COLOR_LUT_ENTRIES 4096
 /* Legacy gamm LUT users such as X doesn't like large LUT sizes */
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 35f148524827..daa500b04cb5 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -623,6 +623,63 @@ amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf)
}
 }
 
+static int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut,
+  uint32_t shaper_size,
+  struct dc_transfer_func *func_shaper)
+{
+   int ret = 0;
+
+   if (shaper_size) {
+   /*
+* If user shaper LUT is set, we assume a linear color space
+* (linearized by degamma 1D LUT or not).
+*/
+   func_shaper->type = TF_TYPE_DISTRIBUTED_POINTS;
+   func_shaper->tf = TRANSFER_FUNCTION_LINEAR;
+
+   ret = __set_output_tf(func_shaper, shaper_lut, shaper_size, 
false);
+   } else {
+   func_shaper->type = TF_TYPE_BYPASS;
+   func_shaper->tf = TRANSFER_FUNCTION_LINEAR;
+   }
+
+   return ret;
+}
+
+/**
+ * amdgpu_dm_verify_lut3d_size - verifies if 3D LUT is supported and if user
+ * shaper and 3D LUTs match the hw supported size
+ * @adev: amdgpu device
+ * @crtc_state: the DRM CRTC state
+ *
+ * Verifies if pre-blending (DPP) 3D LUT is supported by the HW (DCN 2.0 or
+ * newer) and if the user shaper and 3D LUTs match the supported size.
+ *
+ * Returns:
+ * 0 on success. -EINVAL if lut size are invalid.
+ */
+int amdgpu_dm_verify_lut3d_size(struct amdgpu_device *adev,
+   struct drm_plane_state *plane_state)
+{
+   struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
+   const struct drm_color_lut *shaper = NULL;
+   uint32_t exp_size, size;
+   bool has_3dlut = adev->dm.dc->caps.color.dpp.hw_3d_lut;
+
+   /* shaper LUT is only available if 3D LUT color caps */
+   exp_size = has_3dlut ? MAX_COLOR_LUT_ENTRIES : 0;
+   shaper = __extract_blob_lut(dm_plane_state->shaper_lut, );
+
+   if (shaper && size != exp_size) {
+   drm_dbg(>ddev,
+   "Invalid Shaper LUT size. Should be %u but got %u.\n",
+   exp_size, size);
+   return -EINVAL;
+   }
+
+   return 0;

[PATCH v5 26/32] drm/amd/display: handle empty LUTs in __set_input_tf

2023-11-16 Thread Melissa Wen
From: Joshua Ashton 

Unlike degamma, blend gamma doesn't support hardcoded curve
(predefined/ROM), but we can use AMD color module to fill blend gamma
parameters when we have non-linear plane gamma TF without plane gamma
LUT. The regular degamma path doesn't hit this.

Reviewed-by: Harry Wentland 
Signed-off-by: Joshua Ashton 
Signed-off-by: Melissa Wen 
---
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 20 +++
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index f55e0a69dd32..738399538432 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -578,17 +578,21 @@ static int __set_input_tf(struct dc_transfer_func *func,
struct dc_gamma *gamma = NULL;
bool res;
 
-   gamma = dc_create_gamma();
-   if (!gamma)
-   return -ENOMEM;
+   if (lut_size) {
+   gamma = dc_create_gamma();
+   if (!gamma)
+   return -ENOMEM;
 
-   gamma->type = GAMMA_CUSTOM;
-   gamma->num_entries = lut_size;
+   gamma->type = GAMMA_CUSTOM;
+   gamma->num_entries = lut_size;
 
-   __drm_lut_to_dc_gamma(lut, gamma, false);
+   __drm_lut_to_dc_gamma(lut, gamma, false);
+   }
 
-   res = mod_color_calculate_degamma_params(NULL, func, gamma, true);
-   dc_gamma_release();
+   res = mod_color_calculate_degamma_params(NULL, func, gamma, gamma != 
NULL);
+
+   if (gamma)
+   dc_gamma_release();
 
return res ? 0 : -ENOMEM;
 }
-- 
2.40.1



[PATCH v5 22/32] drm/amd/display: add HDR multiplier support

2023-11-16 Thread Melissa Wen
From: Joshua Ashton 

With `dc_fixpt_from_s3132()` translation, we can just use it to set
hdr_mult.

Reviewed-by: Harry Wentland 
Signed-off-by: Joshua Ashton 
Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c   | 1 +
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 3 +++
 2 files changed, 4 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index e694bc3c2d5f..aa91a4b245f6 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -8154,6 +8154,7 @@ static void amdgpu_dm_commit_planes(struct 
drm_atomic_state *state,
bundle->surface_updates[planes_count].gamma = 
dc_plane->gamma_correction;
bundle->surface_updates[planes_count].in_transfer_func 
= dc_plane->in_transfer_func;

bundle->surface_updates[planes_count].gamut_remap_matrix = 
_plane->gamut_remap_matrix;
+   bundle->surface_updates[planes_count].hdr_mult = 
dc_plane->hdr_mult;
}
 
amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index c160dbef5224..35f148524827 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -927,6 +927,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state 
*crtc,
  struct drm_plane_state *plane_state,
  struct dc_plane_state *dc_plane_state)
 {
+   struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
bool has_crtc_cm_degamma;
int ret;
 
@@ -937,6 +938,8 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state 
*crtc,
/* After, we start to update values according to color props */
has_crtc_cm_degamma = (crtc->cm_has_degamma || 
crtc->cm_is_degamma_srgb);
 
+   dc_plane_state->hdr_mult = 
dc_fixpt_from_s3132(dm_plane_state->hdr_mult);
+
ret = __set_dm_plane_degamma(plane_state, dc_plane_state);
if (ret == -ENOMEM)
return ret;
-- 
2.40.1



[PATCH v5 18/32] drm/amd/display: decouple steps for mapping CRTC degamma to DC plane

2023-11-16 Thread Melissa Wen
The next patch adds pre-blending degamma to AMD color mgmt pipeline, but
pre-blending degamma caps (DPP) is currently in use to provide DRM CRTC
atomic degamma or implict degamma on legacy gamma. Detach degamma usage
regarging CRTC color properties to manage plane and CRTC color
correction combinations.

Reviewed-by: Harry Wentland 
Signed-off-by: Melissa Wen 
---
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 60 +--
 1 file changed, 42 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 83c14fb57721..f13d22851fe4 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -789,20 +789,9 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state 
*crtc)
return 0;
 }
 
-/**
- * amdgpu_dm_update_plane_color_mgmt: Maps DRM color management to DC plane.
- * @crtc: amdgpu_dm crtc state
- * @dc_plane_state: target DC surface
- *
- * Update the underlying dc_stream_state's input transfer function (ITF) in
- * preparation for hardware commit. The transfer function used depends on
- * the preparation done on the stream for color management.
- *
- * Returns:
- * 0 on success. -ENOMEM if mem allocation fails.
- */
-int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc,
- struct dc_plane_state *dc_plane_state)
+static int
+map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc,
+struct dc_plane_state *dc_plane_state)
 {
const struct drm_color_lut *degamma_lut;
enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB;
@@ -825,8 +814,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state 
*crtc,
 _size);
ASSERT(degamma_size == MAX_COLOR_LUT_ENTRIES);
 
-   dc_plane_state->in_transfer_func->type =
-   TF_TYPE_DISTRIBUTED_POINTS;
+   dc_plane_state->in_transfer_func->type = 
TF_TYPE_DISTRIBUTED_POINTS;
 
/*
 * This case isn't fully correct, but also fairly
@@ -862,7 +850,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state 
*crtc,
   degamma_lut, degamma_size);
if (r)
return r;
-   } else if (crtc->cm_is_degamma_srgb) {
+   } else {
/*
 * For legacy gamma support we need the regamma input
 * in linear space. Assume that the input is sRGB.
@@ -872,8 +860,44 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state 
*crtc,
 
if (tf != TRANSFER_FUNCTION_SRGB &&
!mod_color_calculate_degamma_params(NULL,
-   dc_plane_state->in_transfer_func, NULL, false))
+   
dc_plane_state->in_transfer_func,
+   NULL, false))
return -ENOMEM;
+   }
+
+   return 0;
+}
+
+/**
+ * amdgpu_dm_update_plane_color_mgmt: Maps DRM color management to DC plane.
+ * @crtc: amdgpu_dm crtc state
+ * @dc_plane_state: target DC surface
+ *
+ * Update the underlying dc_stream_state's input transfer function (ITF) in
+ * preparation for hardware commit. The transfer function used depends on
+ * the preparation done on the stream for color management.
+ *
+ * Returns:
+ * 0 on success. -ENOMEM if mem allocation fails.
+ */
+int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc,
+ struct dc_plane_state *dc_plane_state)
+{
+   bool has_crtc_cm_degamma;
+   int ret;
+
+   has_crtc_cm_degamma = (crtc->cm_has_degamma || 
crtc->cm_is_degamma_srgb);
+   if (has_crtc_cm_degamma){
+   /*
+* AMD HW doesn't have post-blending degamma caps. When DRM
+* CRTC atomic degamma is set, we maps it to DPP degamma block
+* (pre-blending) or, on legacy gamma, we use DPP degamma to
+* linearize (implicit degamma) from sRGB/BT709 according to
+* the input space.
+*/
+   ret = map_crtc_degamma_to_dc_plane(crtc, dc_plane_state);
+   if (ret)
+   return ret;
} else {
/* ...Otherwise we can just bypass the DGM block. */
dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS;
-- 
2.40.1



[PATCH v5 20/32] drm/amd/display: reject atomic commit if setting both plane and CRTC degamma

2023-11-16 Thread Melissa Wen
DC only has pre-blending degamma caps (plane/DPP) that is currently in
use for CRTC/post-blending degamma, so that we don't have HW caps to
perform plane and CRTC degamma at the same time. Reject atomic updates
when serspace sets both plane and CRTC degamma properties.

Reviewed-by: Harry Wentland 
Signed-off-by: Melissa Wen 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 13 -
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 13117516f2a4..8fc715fa426c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -944,9 +944,20 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state 
*crtc,
has_crtc_cm_degamma = (crtc->cm_has_degamma || 
crtc->cm_is_degamma_srgb);
 
ret = __set_dm_plane_degamma(plane_state, dc_plane_state);
-   if (ret != -EINVAL)
+   if (ret == -ENOMEM)
return ret;
 
+   /* We only have one degamma block available (pre-blending) for the
+* whole color correction pipeline, so that we can't actually perform
+* plane and CRTC degamma at the same time. Explicitly reject atomic
+* updates when userspace sets both plane and CRTC degamma properties.
+*/
+   if (has_crtc_cm_degamma && ret != -EINVAL){
+   drm_dbg_kms(crtc->base.crtc->dev,
+   "doesn't support plane and CRTC degamma at the same 
time\n");
+   return -EINVAL;
+   }
+
/* If we are here, it means we don't have plane degamma settings, check
 * if we have CRTC degamma waiting for mapping to pre-blending degamma
 * block
-- 
2.40.1



[PATCH v5 13/32] drm/amd/display: add comments to describe DM crtc color mgmt behavior

2023-11-16 Thread Melissa Wen
Describe some expected behavior of the AMD DM color mgmt programming.

Reviewed-by: Harry Wentland 
Signed-off-by: Melissa Wen 
---
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_color.c  | 16 ++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 4150e9370daf..0b92513eab98 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -661,13 +661,25 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state 
*crtc)
crtc->cm_is_degamma_srgb = true;
stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS;
stream->out_transfer_func->tf = TRANSFER_FUNCTION_SRGB;
-
+   /*
+* Note: although we pass has_rom as parameter here, we never
+* actually use ROM because the color module only takes the ROM
+* path if transfer_func->type == PREDEFINED.
+*
+* See more in mod_color_calculate_regamma_params()
+*/
r = __set_legacy_tf(stream->out_transfer_func, regamma_lut,
regamma_size, has_rom);
if (r)
return r;
} else if (has_regamma) {
-   /* If atomic regamma, CRTC RGM goes into RGM LUT. */
+   /*
+* CRTC RGM goes into RGM LUT.
+*
+* Note: there is no implicit sRGB regamma here. We are using
+* degamma calculation from color module to calculate the curve
+* from a linear base.
+*/
stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS;
stream->out_transfer_func->tf = TRANSFER_FUNCTION_LINEAR;
 
-- 
2.40.1



[PATCH v5 16/32] drm/amd/display: set sdr_ref_white_level to 80 for out_transfer_func

2023-11-16 Thread Melissa Wen
From: Joshua Ashton 

Otherwise this is just initialized to 0. This needs to actually have a
value so that compute_curve can work for PQ EOTF.

Reviewed-by: Harry Wentland 
Signed-off-by: Joshua Ashton 
Co-developed-by: Melissa Wen 
Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 9b930e3eb79d..83c14fb57721 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -72,6 +72,7 @@
  */
 
 #define MAX_DRM_LUT_VALUE 0x
+#define SDR_WHITE_LEVEL_INIT_VALUE 80
 
 /**
  * amdgpu_dm_init_color_mod - Initialize the color module.
@@ -552,6 +553,7 @@ static int amdgpu_dm_set_atomic_regamma(struct 
dc_stream_state *stream,
 */
out_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
out_tf->tf = tf;
+   out_tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
 
ret = __set_output_tf(out_tf, regamma_lut, regamma_size, 
has_rom);
} else {
-- 
2.40.1



[PATCH v5 17/32] drm/amd/display: mark plane as needing reset if color props change

2023-11-16 Thread Melissa Wen
From: Joshua Ashton 

We should reset a plane state if at least one of the color management
properties differs from old and new state.

Reviewed-by: Harry Wentland 
Signed-off-by: Joshua Ashton 
Co-developed-by: Melissa Wen 
Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 15 +++
 1 file changed, 15 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 8bf7866ee1af..8f82d9837a41 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -9632,6 +9632,10 @@ static bool should_reset_plane(struct drm_atomic_state 
*state,
 */
for_each_oldnew_plane_in_state(state, other, old_other_state, 
new_other_state, i) {
struct amdgpu_framebuffer *old_afb, *new_afb;
+   struct dm_plane_state *dm_new_other_state, *dm_old_other_state;
+
+   dm_new_other_state = to_dm_plane_state(new_other_state);
+   dm_old_other_state = to_dm_plane_state(old_other_state);
 
if (other->type == DRM_PLANE_TYPE_CURSOR)
continue;
@@ -9668,6 +9672,17 @@ static bool should_reset_plane(struct drm_atomic_state 
*state,
old_other_state->color_encoding != 
new_other_state->color_encoding)
return true;
 
+   /* HDR/Transfer Function changes. */
+   if (dm_old_other_state->degamma_tf != 
dm_new_other_state->degamma_tf ||
+   dm_old_other_state->degamma_lut != 
dm_new_other_state->degamma_lut ||
+   dm_old_other_state->hdr_mult != 
dm_new_other_state->hdr_mult ||
+   dm_old_other_state->shaper_lut != 
dm_new_other_state->shaper_lut ||
+   dm_old_other_state->shaper_tf != 
dm_new_other_state->shaper_tf ||
+   dm_old_other_state->lut3d != dm_new_other_state->lut3d ||
+   dm_old_other_state->blend_lut != 
dm_new_other_state->blend_lut ||
+   dm_old_other_state->blend_tf != 
dm_new_other_state->blend_tf)
+   return true;
+
/* Framebuffer checks fall at the end. */
if (!old_other_state->fb || !new_other_state->fb)
continue;
-- 
2.40.1



[PATCH v5 15/32] drm/amd/display: add CRTC gamma TF support

2023-11-16 Thread Melissa Wen
From: Joshua Ashton 

Add predefined transfer function programming. There is no post-blending
out gamma ROM for hardcoded curves, but we can use AMD color modules to
program LUT parameters from pre-defined coefficients and an empty
regamma LUT (or bump up LUT parameters with pre-defined TF values).

v2:
- update crtc color mgmt if regamma TF differs between states (Joshua)
- map inverse EOTF to DC transfer function (Melissa)

v3:
- update AMDGPU TF list

v4:
- update comment regarding regamma behavior

Reviewed-by: Harry Wentland 
Signed-off-by: Joshua Ashton 
Co-developed-by: Melissa Wen 
Signed-off-by: Melissa Wen 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  1 +
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 77 +++
 2 files changed, 61 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 56053de2aaea..8bf7866ee1af 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -9564,6 +9564,7 @@ static int dm_update_crtc_state(struct 
amdgpu_display_manager *dm,
 * when a modeset is needed, to ensure it gets reprogrammed.
 */
if (dm_new_crtc_state->base.color_mgmt_changed ||
+   dm_old_crtc_state->regamma_tf != dm_new_crtc_state->regamma_tf ||
drm_atomic_crtc_needs_modeset(new_crtc_state)) {
ret = amdgpu_dm_update_crtc_color_mgmt(dm_new_crtc_state);
if (ret)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index dec734f03832..9b930e3eb79d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -490,16 +490,18 @@ static int __set_output_tf(struct dc_transfer_func *func,
struct calculate_buffer cal_buffer = {0};
bool res;
 
-   ASSERT(lut && lut_size == MAX_COLOR_LUT_ENTRIES);
-
cal_buffer.buffer_index = -1;
 
-   gamma = dc_create_gamma();
-   if (!gamma)
-   return -ENOMEM;
+   if (lut_size) {
+   ASSERT(lut && lut_size == MAX_COLOR_LUT_ENTRIES);
 
-   gamma->num_entries = lut_size;
-   __drm_lut_to_dc_gamma(lut, gamma, false);
+   gamma = dc_create_gamma();
+   if (!gamma)
+   return -ENOMEM;
+
+   gamma->num_entries = lut_size;
+   __drm_lut_to_dc_gamma(lut, gamma, false);
+   }
 
if (func->tf == TRANSFER_FUNCTION_LINEAR) {
/*
@@ -507,41 +509,49 @@ static int __set_output_tf(struct dc_transfer_func *func,
 * on top of a linear input. But degamma params can be used
 * instead to simulate this.
 */
-   gamma->type = GAMMA_CUSTOM;
+   if (gamma)
+   gamma->type = GAMMA_CUSTOM;
res = mod_color_calculate_degamma_params(NULL, func,
-   gamma, true);
+gamma, gamma != NULL);
} else {
/*
 * Assume sRGB. The actual mapping will depend on whether the
 * input was legacy or not.
 */
-   gamma->type = GAMMA_CS_TFM_1D;
-   res = mod_color_calculate_regamma_params(func, gamma, false,
+   if (gamma)
+   gamma->type = GAMMA_CS_TFM_1D;
+   res = mod_color_calculate_regamma_params(func, gamma, gamma != 
NULL,
 has_rom, NULL, 
_buffer);
}
 
-   dc_gamma_release();
+   if (gamma)
+   dc_gamma_release();
 
return res ? 0 : -ENOMEM;
 }
 
 static int amdgpu_dm_set_atomic_regamma(struct dc_stream_state *stream,
const struct drm_color_lut *regamma_lut,
-   uint32_t regamma_size, bool has_rom)
+   uint32_t regamma_size, bool has_rom,
+   enum dc_transfer_func_predefined tf)
 {
struct dc_transfer_func *out_tf = stream->out_transfer_func;
int ret = 0;
 
-   if (regamma_size) {
+   if (regamma_size || tf != TRANSFER_FUNCTION_LINEAR) {
/*
 * CRTC RGM goes into RGM LUT.
 *
 * Note: there is no implicit sRGB regamma here. We are using
 * degamma calculation from color module to calculate the curve
-* from a linear base.
+* from a linear base if gamma TF is not set. However, if gamma
+* TF (!= Linear) and LUT are set at the same time, we will use
+* regam

[PATCH v5 07/32] drm/amd/display: document AMDGPU pre-defined transfer functions

2023-11-16 Thread Melissa Wen
Brief documentation about pre-defined transfer function usage on AMD
display driver and standardized EOTFs and inverse EOTFs.

v3:
- Document BT709 OETF (Pekka)
- Fix description of sRGB and pure power funcs (Pekka)

v4:
- Add description of linear and non-linear forms (Harry)

Reviewed-by: Harry Wentland 
Co-developed-by: Harry Wentland 
Signed-off-by: Harry Wentland 
Signed-off-by: Melissa Wen 
---
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 62 +++
 1 file changed, 62 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index a32abbd93a61..49faaf606cfe 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -85,6 +85,68 @@ void amdgpu_dm_init_color_mod(void)
 }
 
 #ifdef AMD_PRIVATE_COLOR
+/* Pre-defined Transfer Functions (TF)
+ *
+ * AMD driver supports pre-defined mathematical functions for transferring
+ * between encoded values and optical/linear space. Depending on HW color caps,
+ * ROMs and curves built by the AMD color module support these transforms.
+ *
+ * The driver-specific color implementation exposes properties for pre-blending
+ * degamma TF, shaper TF (before 3D LUT), and blend(dpp.ogam) TF and
+ * post-blending regamma (mpc.ogam) TF. However, only pre-blending degamma
+ * supports ROM curves. AMD color module uses pre-defined coefficients to build
+ * curves for the other blocks. What can be done by each color block is
+ * described by struct dpp_color_capsand struct mpc_color_caps.
+ *
+ * AMD driver-specific color API exposes the following pre-defined transfer
+ * functions:
+ *
+ * - Identity: linear/identity relationship between pixel value and
+ *   luminance value;
+ * - Gamma 2.2, Gamma 2.4, Gamma 2.6: pure power functions;
+ * - sRGB: 2.4: The piece-wise transfer function from IEC 61966-2-1:1999;
+ * - BT.709: has a linear segment in the bottom part and then a power function
+ *   with a 0.45 (~1/2.22) gamma for the rest of the range; standardized by
+ *   ITU-R BT.709-6;
+ * - PQ (Perceptual Quantizer): used for HDR display, allows luminance range
+ *   capability of 0 to 10,000 nits; standardized by SMPTE ST 2084.
+ *
+ * The AMD color model is designed with an assumption that SDR (sRGB, BT.709,
+ * Gamma 2.2, etc.) peak white maps (normalized to 1.0 FP) to 80 nits in the PQ
+ * system. This has the implication that PQ EOTF (non-linear to linear) maps to
+ * [0.0..125.0] where 125.0 = 10,000 nits / 80 nits.
+ *
+ * Non-linear and linear forms are described in the table below:
+ *
+ * ┌───┬─┬──┐
+ * │   │ Non-linear  │   Linear │
+ * ├───┼─┼──┤
+ * │  sRGB │ UNORM or [0.0, 1.0] │ [0.0, 1.0]   │
+ * ├───┼─┼──┤
+ * │ BT709 │ UNORM or [0.0, 1.0] │ [0.0, 1.0]   │
+ * ├───┼─┼──┤
+ * │ Gamma 2.x │ UNORM or [0.0, 1.0] │ [0.0, 1.0]   │
+ * ├───┼─┼──┤
+ * │PQ │ UNORM or FP16 CCCS* │ [0.0, 125.0] │
+ * ├───┼─┼──┤
+ * │  Identity │ UNORM or FP16 CCCS* │ [0.0, 1.0] or CCCS** │
+ * └───┴─┴──┘
+ * * CCCS: Windows canonical composition color space
+ * ** Respectively
+ *
+ * In the driver-specific API, color block names attached to TF properties
+ * suggest the intention regarding non-linear encoding pixel's luminance
+ * values. As some newer encodings don't use gamma curve, we make encoding and
+ * decoding explicit by defining an enum list of transfer functions supported
+ * in terms of EOTF and inverse EOTF, where:
+ *
+ * - EOTF (electro-optical transfer function): is the transfer function to go
+ *   from the encoded value to an optical (linear) value. De-gamma functions
+ *   traditionally do this.
+ * - Inverse EOTF (simply the inverse of the EOTF): is usually intended to go
+ *   from an optical/linear space (which might have been used for blending)
+ *   back to the encoded values. Gamma functions traditionally do this.
+ */
 static const char * const
 amdgpu_transfer_function_names[] = {
[AMDGPU_TRANSFER_FUNCTION_DEFAULT]  = "Default",
-- 
2.40.1



[PATCH v5 09/32] drm/amd/display: add plane 3D LUT driver-specific properties

2023-11-16 Thread Melissa Wen
Add 3D LUT property for plane color transformations using a 3D lookup
table. 3D LUT allows for highly accurate and complex color
transformations and is suitable to adjust the balance between color
channels. It's also more complex to manage and require more
computational resources.

Since a 3D LUT has a limited number of entries in each dimension we want
to use them in an optimal fashion. This means using the 3D LUT in a
colorspace that is optimized for human vision, such as sRGB, PQ, or
another non-linear space. Therefore, userpace may need one 1D LUT
(shaper) before it to delinearize content and another 1D LUT after 3D
LUT (blend) to linearize content again for blending. The next patches
add these 1D LUTs to the plane color mgmt pipeline.

v3:
- improve commit message about 3D LUT
- describe the 3D LUT entries and size (Harry)

v4:
- advertise 3D LUT max size as the size of a single-dimension

v5:
- get lut3d blob correctly (Joshua)
- fix doc about 3d-lut dimension size (Sebastian)

Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h  | 18 ++
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  9 +++
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 14 +++
 .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 24 +++
 4 files changed, 65 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index ee67c5adf0f1..57822477408f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -364,6 +364,24 @@ struct amdgpu_mode_info {
 * @plane_hdr_mult_property:
 */
struct drm_property *plane_hdr_mult_property;
+   /**
+* @plane_lut3d_property: Plane property for color transformation using
+* a 3D LUT (pre-blending), a three-dimensional array where each
+* element is an RGB triplet. Each dimension has the size of
+* lut3d_size. The array contains samples from the approximated
+* function. On AMD, values between samples are estimated by
+* tetrahedral interpolation. The array is accessed with three indices,
+* one for each input dimension (color channel), blue being the
+* outermost dimension, red the innermost.
+*/
+   struct drm_property *plane_lut3d_property;
+   /**
+* @plane_degamma_lut_size_property: Plane property to define the max
+* size of 3D LUT as supported by the driver (read-only). The max size
+* is the max size of one dimension and, therefore, the max number of
+* entries for 3D LUT array is the 3D LUT size cubed;
+*/
+   struct drm_property *plane_lut3d_size_property;
 };
 
 #define AMDGPU_MAX_BL_LEVEL 0xFF
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 38163b7084fa..03b48b331b7c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -776,6 +776,11 @@ struct dm_plane_state {
 * TF is needed for any subsequent linear-to-non-linear transforms.
 */
__u64 hdr_mult;
+   /**
+* @lut3d: 3D lookup table blob. The blob (if not NULL) is an array of
+*  drm_color_lut.
+*/
+   struct drm_property_blob *lut3d;
 };
 
 struct dm_crtc_state {
@@ -861,6 +866,10 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector 
*connector,
 
 void amdgpu_dm_trigger_timing_sync(struct drm_device *dev);
 
+/* 3D LUT max size is 17x17x17 (4913 entries) */
+#define MAX_COLOR_3DLUT_SIZE 17
+#define MAX_COLOR_3DLUT_BITDEPTH 12
+/* 1D LUT size */
 #define MAX_COLOR_LUT_ENTRIES 4096
 /* Legacy gamm LUT users such as X doesn't like large LUT sizes */
 #define MAX_COLOR_LEGACY_LUT_ENTRIES 256
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index b5b34a9209e4..a3b4f6a4c4a8 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -231,6 +231,20 @@ amdgpu_dm_create_color_properties(struct amdgpu_device 
*adev)
return -ENOMEM;
adev->mode_info.plane_hdr_mult_property = prop;
 
+   prop = drm_property_create(adev_to_drm(adev),
+  DRM_MODE_PROP_BLOB,
+  "AMD_PLANE_LUT3D", 0);
+   if (!prop)
+   return -ENOMEM;
+   adev->mode_info.plane_lut3d_property = prop;
+
+   prop = drm_property_create_range(adev_to_drm(adev),
+DRM_MODE_PROP_IMMUTABLE,
+"AMD_PLANE_LUT3D_SIZE", 0, UINT_MAX);
+   if (!prop)
+   return -ENOMEM;
+   adev->mode_info.plane_lut3d_size_property = prop;
+
return 0;
 }
 #endif
diff --git a/drivers/gpu/drm/amd/display/a

[PATCH v5 12/32] drm/amd/display: add CRTC gamma TF driver-specific property

2023-11-16 Thread Melissa Wen
Add AMD pre-defined transfer function property to default DRM CRTC gamma
to convert to wire encoding with or without a user gamma LUT. There is
no post-blending regamma ROM for pre-defined TF. When setting Gamma TF
(!= Identity) and LUT at the same time, the color module will combine
the pre-defined TF and the custom LUT values into the LUT that's
actually programmed.

v2:
- enable CRTC prop in the end of driver-specific prop sequence
- define inverse EOTFs as supported regamma TFs
- reword driver-specific function doc to remove shaper/3D LUT

v3:
- spell out TF+LUT behavior in the commit and comments (Harry)

Reviewed-by: Harry Wentland 
Co-developed-by: Joshua Ashton 
Signed-off-by: Joshua Ashton 
Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h  |  7 ++
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  8 +++
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   |  7 ++
 .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c| 72 +++
 4 files changed, 94 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index d1c38dedfc7a..f4e74acd8dca 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -425,6 +425,13 @@ struct amdgpu_mode_info {
 * from a combination of pre-defined TF and the custom 1D LUT).
 */
struct drm_property *plane_blend_tf_property;
+   /* @regamma_tf_property: Transfer function for CRTC regamma
+* (post-blending). Possible values are defined by `enum
+* amdgpu_transfer_function`. There is no regamma ROM, but we can use
+* AMD color modules to program LUT parameters from predefined TF (or
+* from a combination of pre-defined TF and the custom 1D LUT).
+*/
+   struct drm_property *regamma_tf_property;
 };
 
 #define AMDGPU_MAX_BL_LEVEL 0xFF
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 8c040c55359b..b997bb287dda 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -828,6 +828,14 @@ struct dm_crtc_state {
struct dc_info_packet vrr_infopacket;
 
int abm_level;
+
+/**
+* @regamma_tf:
+*
+* Pre-defined transfer function for converting internal FB -> wire
+* encoding.
+*/
+   enum amdgpu_transfer_function regamma_tf;
 };
 
 #define to_dm_crtc_state(x) container_of(x, struct dm_crtc_state, base)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 425676f5afb7..4150e9370daf 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -295,6 +295,13 @@ amdgpu_dm_create_color_properties(struct amdgpu_device 
*adev)
return -ENOMEM;
adev->mode_info.plane_blend_tf_property = prop;
 
+   prop = amdgpu_create_tf_property(adev_to_drm(adev),
+"AMD_CRTC_REGAMMA_TF",
+amdgpu_inv_eotf);
+   if (!prop)
+   return -ENOMEM;
+   adev->mode_info.regamma_tf_property = prop;
+
return 0;
 }
 #endif
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
index 611849e3bf91..e8dfc4aa92c6 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
@@ -253,6 +253,7 @@ static struct drm_crtc_state 
*amdgpu_dm_crtc_duplicate_state(struct drm_crtc *cr
state->freesync_config = cur->freesync_config;
state->cm_has_degamma = cur->cm_has_degamma;
state->cm_is_degamma_srgb = cur->cm_is_degamma_srgb;
+   state->regamma_tf = cur->regamma_tf;
state->crc_skip_count = cur->crc_skip_count;
state->mpo_requested = cur->mpo_requested;
/* TODO Duplicate dc_stream after objects are stream object is 
flattened */
@@ -289,6 +290,70 @@ static int amdgpu_dm_crtc_late_register(struct drm_crtc 
*crtc)
 }
 #endif
 
+#ifdef AMD_PRIVATE_COLOR
+/**
+ * drm_crtc_additional_color_mgmt - enable additional color properties
+ * @crtc: DRM CRTC
+ *
+ * This function lets the driver enable post-blending CRTC regamma transfer
+ * function property in addition to DRM CRTC gamma LUT. Default value means
+ * linear transfer function, which is the default CRTC gamma LUT behaviour
+ * without this property.
+ */
+static void
+dm_crtc_additional_color_mgmt(struct drm_crtc *crtc)
+{
+   struct amdgpu_device *adev = drm_to_adev(crtc->dev);
+
+   if(adev->dm.dc->caps.color.mpc.ogam_ram)
+   drm_object_attach_property(>base,
+  

[PATCH v5 14/32] drm/amd/display: encapsulate atomic regamma operation

2023-11-16 Thread Melissa Wen
We will wire up MPC 3D LUT to DM CRTC color pipeline in the next patch,
but so far, only for atomic interface. By checking
set_output_transfer_func in DC drivers with MPC 3D LUT support, we can
verify that regamma is only programmed when 3D LUT programming fails. As
a groundwork to introduce 3D LUT programming and better understand each
step, detach atomic regamma programming from the crtc colocr updating
code.

Reviewed-by: Harry Wentland 
Signed-off-by: Melissa Wen 
---
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 55 ---
 1 file changed, 35 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 0b92513eab98..dec734f03832 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -525,6 +525,37 @@ static int __set_output_tf(struct dc_transfer_func *func,
return res ? 0 : -ENOMEM;
 }
 
+static int amdgpu_dm_set_atomic_regamma(struct dc_stream_state *stream,
+   const struct drm_color_lut *regamma_lut,
+   uint32_t regamma_size, bool has_rom)
+{
+   struct dc_transfer_func *out_tf = stream->out_transfer_func;
+   int ret = 0;
+
+   if (regamma_size) {
+   /*
+* CRTC RGM goes into RGM LUT.
+*
+* Note: there is no implicit sRGB regamma here. We are using
+* degamma calculation from color module to calculate the curve
+* from a linear base.
+*/
+   out_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
+   out_tf->tf = TRANSFER_FUNCTION_LINEAR;
+
+   ret = __set_output_tf(out_tf, regamma_lut, regamma_size, 
has_rom);
+   } else {
+   /*
+* No CRTC RGM means we can just put the block into bypass
+* since we don't have any plane level adjustments using it.
+*/
+   out_tf->type = TF_TYPE_BYPASS;
+   out_tf->tf = TRANSFER_FUNCTION_LINEAR;
+   }
+
+   return ret;
+}
+
 /**
  * __set_input_tf - calculates the input transfer function based on expected
  * input space.
@@ -672,28 +703,12 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state 
*crtc)
regamma_size, has_rom);
if (r)
return r;
-   } else if (has_regamma) {
-   /*
-* CRTC RGM goes into RGM LUT.
-*
-* Note: there is no implicit sRGB regamma here. We are using
-* degamma calculation from color module to calculate the curve
-* from a linear base.
-*/
-   stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS;
-   stream->out_transfer_func->tf = TRANSFER_FUNCTION_LINEAR;
-
-   r = __set_output_tf(stream->out_transfer_func, regamma_lut,
-   regamma_size, has_rom);
+   } else {
+   regamma_size = has_regamma ? regamma_size : 0;
+   r = amdgpu_dm_set_atomic_regamma(stream, regamma_lut,
+regamma_size, has_rom);
if (r)
return r;
-   } else {
-   /*
-* No CRTC RGM means we can just put the block into bypass
-* since we don't have any plane level adjustments using it.
-*/
-   stream->out_transfer_func->type = TF_TYPE_BYPASS;
-   stream->out_transfer_func->tf = TRANSFER_FUNCTION_LINEAR;
}
 
/*
-- 
2.40.1



[PATCH v5 11/32] drm/amd/display: add plane blend LUT and TF driver-specific properties

2023-11-16 Thread Melissa Wen
From: Joshua Ashton 

Blend 1D LUT or a pre-defined transfer function (TF) can be set to
linearize content before blending, so that it's positioned just before
blending planes in the AMD color mgmt pipeline, and after 3D LUT
(non-linear space). Shaper and Blend LUTs are 1D LUTs that sandwich 3D
LUT. Drivers should advertize blend properties according to HW caps.

There is no blend ROM for pre-defined TF. When setting blend TF (!=
Identity) and LUT at the same time, the color module will combine the
pre-defined TF and the custom LUT values into the LUT that's actually
programmed.

v3:
- spell out TF+LUT behavior in the commit and comments (Harry)

v5:
- get blend blob correctly

Reviewed-by: Harry Wentland 
Signed-off-by: Joshua Ashton 
Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h  | 22 +++
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 12 ++
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 21 +++
 .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 37 +++
 4 files changed, 92 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index bb27a3156204..d1c38dedfc7a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -403,6 +403,28 @@ struct amdgpu_mode_info {
 * entries for 3D LUT array is the 3D LUT size cubed;
 */
struct drm_property *plane_lut3d_size_property;
+   /**
+* @plane_blend_lut_property: Plane property for output gamma before
+* blending. Userspace set a blend LUT to convert colors after 3D LUT
+* conversion. It works as a post-3DLUT 1D LUT. With shaper LUT, they
+* are sandwiching 3D LUT with two 1D LUT. If plane_blend_tf_property
+* != Identity TF, AMD color module will combine the user LUT values
+* with pre-defined TF into the LUT parameters to be programmed.
+*/
+   struct drm_property *plane_blend_lut_property;
+   /**
+* @plane_blend_lut_size_property: Plane property to define the max
+* size of blend LUT as supported by the driver (read-only).
+*/
+   struct drm_property *plane_blend_lut_size_property;
+   /**
+* @plane_blend_tf_property: Plane property to set a predefined
+* transfer function for pre-blending blend/out_gamma (after applying
+* 3D LUT) with or without LUT. There is no blend ROM, but we can use
+* AMD color modules to program LUT parameters from predefined TF (or
+* from a combination of pre-defined TF and the custom 1D LUT).
+*/
+   struct drm_property *plane_blend_tf_property;
 };
 
 #define AMDGPU_MAX_BL_LEVEL 0xFF
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 33e18005226a..8c040c55359b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -792,6 +792,18 @@ struct dm_plane_state {
 *  drm_color_lut.
 */
struct drm_property_blob *lut3d;
+   /**
+* @blend_lut: blend lut lookup table blob. The blob (if not NULL) is an
+* array of  drm_color_lut.
+*/
+   struct drm_property_blob *blend_lut;
+   /**
+* @blend_tf:
+*
+* Pre-defined transfer function for converting plane pixel data before
+* applying blend LUT.
+*/
+   enum amdgpu_transfer_function blend_tf;
 };
 
 struct dm_crtc_state {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 866c6f1d3d99..425676f5afb7 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -274,6 +274,27 @@ amdgpu_dm_create_color_properties(struct amdgpu_device 
*adev)
return -ENOMEM;
adev->mode_info.plane_lut3d_size_property = prop;
 
+   prop = drm_property_create(adev_to_drm(adev),
+  DRM_MODE_PROP_BLOB,
+  "AMD_PLANE_BLEND_LUT", 0);
+   if (!prop)
+   return -ENOMEM;
+   adev->mode_info.plane_blend_lut_property = prop;
+
+   prop = drm_property_create_range(adev_to_drm(adev),
+DRM_MODE_PROP_IMMUTABLE,
+"AMD_PLANE_BLEND_LUT_SIZE", 0, 
UINT_MAX);
+   if (!prop)
+   return -ENOMEM;
+   adev->mode_info.plane_blend_lut_size_property = prop;
+
+   prop = amdgpu_create_tf_property(adev_to_drm(adev),
+"AMD_PLANE_BLEND_TF",
+amdgpu_eotf);
+   if (!prop)
+   return -ENOMEM;
+   adev->mode_info.plane_blend_tf_property = prop;
+
return 0;
 

[PATCH v5 08/32] drm/amd/display: add plane HDR multiplier driver-specific property

2023-11-16 Thread Melissa Wen
From: Joshua Ashton 

Multiplier to 'gain' the plane. When PQ is decoded using the fixed func
transfer function to the internal FP16 fb, 1.0 -> 80 nits (on AMD at
least) When sRGB is decoded, 1.0 -> 1.0.  Therefore, 1.0 multiplier = 80
nits for SDR content. So if you want, 203 nits for SDR content, pass in
(203.0 / 80.0).

v4:
- comment about the PQ TF need for L-to-NL (from Harry's review)

Reviewed-by: Harry Wentland 
Signed-off-by: Joshua Ashton 
Co-developed-by: Melissa Wen 
Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h|  4 
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h   | 17 +
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_color.c |  6 ++
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 13 +
 4 files changed, 40 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index 50572fe27ab0..ee67c5adf0f1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -360,6 +360,10 @@ struct amdgpu_mode_info {
 * to go from scanout/encoded values to linear values.
 */
struct drm_property *plane_degamma_tf_property;
+   /**
+* @plane_hdr_mult_property:
+*/
+   struct drm_property *plane_hdr_mult_property;
 };
 
 #define AMDGPU_MAX_BL_LEVEL 0xFF
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 98f7267d5ee7..38163b7084fa 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -54,6 +54,9 @@
 #define HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_IEEE_REGISTRATION_ID 0x1A
 #define AMD_VSDB_VERSION_3_FEATURECAP_REPLAYMODE 0x40
 #define HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3 0x3
+
+#define AMDGPU_HDR_MULT_DEFAULT (0x1LL)
+
 /*
 #include "include/amdgpu_dal_power_if.h"
 #include "amdgpu_dm_irq.h"
@@ -759,6 +762,20 @@ struct dm_plane_state {
 * linearize.
 */
enum amdgpu_transfer_function degamma_tf;
+   /**
+* @hdr_mult:
+*
+* Multiplier to 'gain' the plane.  When PQ is decoded using the fixed
+* func transfer function to the internal FP16 fb, 1.0 -> 80 nits (on
+* AMD at least). When sRGB is decoded, 1.0 -> 1.0, obviously.
+* Therefore, 1.0 multiplier = 80 nits for SDR content.  So if you
+* want, 203 nits for SDR content, pass in (203.0 / 80.0).  Format is
+* S31.32 sign-magnitude.
+*
+* HDR multiplier can wide range beyond [0.0, 1.0]. This means that PQ
+* TF is needed for any subsequent linear-to-non-linear transforms.
+*/
+   __u64 hdr_mult;
 };
 
 struct dm_crtc_state {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 49faaf606cfe..b5b34a9209e4 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -225,6 +225,12 @@ amdgpu_dm_create_color_properties(struct amdgpu_device 
*adev)
return -ENOMEM;
adev->mode_info.plane_degamma_tf_property = prop;
 
+   prop = drm_property_create_range(adev_to_drm(adev),
+0, "AMD_PLANE_HDR_MULT", 0, U64_MAX);
+   if (!prop)
+   return -ENOMEM;
+   adev->mode_info.plane_hdr_mult_property = prop;
+
return 0;
 }
 #endif
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index d5e12e05d161..45a2c9b36630 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -1342,6 +1342,7 @@ static void amdgpu_dm_plane_drm_plane_reset(struct 
drm_plane *plane)
 
__drm_atomic_helper_plane_reset(plane, _state->base);
amdgpu_state->degamma_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT;
+   amdgpu_state->hdr_mult = AMDGPU_HDR_MULT_DEFAULT;
 }
 
 static struct drm_plane_state 
*amdgpu_dm_plane_drm_plane_duplicate_state(struct drm_plane *plane)
@@ -1365,6 +1366,7 @@ static struct drm_plane_state 
*amdgpu_dm_plane_drm_plane_duplicate_state(struct
drm_property_blob_get(old_dm_plane_state->degamma_lut);
 
dm_plane_state->degamma_tf = old_dm_plane_state->degamma_tf;
+   dm_plane_state->hdr_mult = old_dm_plane_state->hdr_mult;
 
return _plane_state->base;
 }
@@ -1464,6 +1466,10 @@ dm_atomic_plane_attach_color_mgmt_properties(struct 
amdgpu_display_manager *dm,
   
dm->adev->mode_info.plane_degamma_tf_property,
   AMDGPU_TRANSFER_FUNCTION_DEFAULT);
}
+   /* HDR MULT is always available */
+   

[PATCH v5 03/32] drm/drm_plane: track color mgmt changes per plane

2023-11-16 Thread Melissa Wen
We will add color mgmt properties to DRM planes in the next patches and
we want to track when one of this properties change to define atomic
commit behaviors. Using a similar approach from CRTC color props, we set
a color_mgmt_changed boolean whenever a plane color prop changes.

Reviewed-by: Harry Wentland 
Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/drm_atomic.c  | 1 +
 drivers/gpu/drm/drm_atomic_state_helper.c | 1 +
 include/drm/drm_plane.h   | 7 +++
 3 files changed, 9 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 2c454568a607..2925371d230d 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -724,6 +724,7 @@ static void drm_atomic_plane_print_state(struct drm_printer 
*p,
   drm_get_color_encoding_name(state->color_encoding));
drm_printf(p, "\tcolor-range=%s\n",
   drm_get_color_range_name(state->color_range));
+   drm_printf(p, "\tcolor_mgmt_changed=%d\n", state->color_mgmt_changed);
 
if (plane->funcs->atomic_print_state)
plane->funcs->atomic_print_state(p, state);
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c 
b/drivers/gpu/drm/drm_atomic_state_helper.c
index 784e63d70a42..25bb0859fda7 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -338,6 +338,7 @@ void __drm_atomic_helper_plane_duplicate_state(struct 
drm_plane *plane,
state->fence = NULL;
state->commit = NULL;
state->fb_damage_clips = NULL;
+   state->color_mgmt_changed = false;
 }
 EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state);
 
diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
index 51291983ea44..52c3287da0da 100644
--- a/include/drm/drm_plane.h
+++ b/include/drm/drm_plane.h
@@ -237,6 +237,13 @@ struct drm_plane_state {
 
/** @state: backpointer to global drm_atomic_state */
struct drm_atomic_state *state;
+
+   /**
+* @color_mgmt_changed: Color management properties have changed. Used
+* by the atomic helpers and drivers to steer the atomic commit control
+* flow.
+*/
+   bool color_mgmt_changed : 1;
 };
 
 static inline struct drm_rect
-- 
2.40.1



[PATCH v5 06/32] drm/amd/display: explicitly define EOTF and inverse EOTF

2023-11-16 Thread Melissa Wen
Instead of relying on color block names to get the transfer function
intention regarding encoding pixel's luminance, define supported
Electro-Optical Transfer Functions (EOTFs) and inverse EOTFs, that
includes pure gamma or standardized transfer functions.

v3:
- squash linear and unity TFs to identity (Pekka)
- define the right TFs for BT.709 (Pekka and Harry)
- add comment about AMD TF coefficients

Suggested-by: Harry Wentland 
Reviewed-by: Harry Wentland 
Signed-off-by: Melissa Wen 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 27 +---
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 67 ++-
 2 files changed, 71 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index ab89538d5663..98f7267d5ee7 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -716,16 +716,27 @@ static inline void amdgpu_dm_set_mst_status(uint8_t 
*status,
 
 extern const struct amdgpu_ip_block_version dm_ip_block;
 
+/* enum amdgpu_transfer_function: pre-defined transfer function supported by 
AMD.
+ *
+ * It includes standardized transfer functions and pure power functions. The
+ * transfer function coefficients are available at modules/color/color_gamma.c
+ */
 enum amdgpu_transfer_function {
AMDGPU_TRANSFER_FUNCTION_DEFAULT,
-   AMDGPU_TRANSFER_FUNCTION_SRGB,
-   AMDGPU_TRANSFER_FUNCTION_BT709,
-   AMDGPU_TRANSFER_FUNCTION_PQ,
-   AMDGPU_TRANSFER_FUNCTION_LINEAR,
-   AMDGPU_TRANSFER_FUNCTION_UNITY,
-   AMDGPU_TRANSFER_FUNCTION_GAMMA22,
-   AMDGPU_TRANSFER_FUNCTION_GAMMA24,
-   AMDGPU_TRANSFER_FUNCTION_GAMMA26,
+   AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF,
+   AMDGPU_TRANSFER_FUNCTION_BT709_INV_OETF,
+   AMDGPU_TRANSFER_FUNCTION_PQ_EOTF,
+   AMDGPU_TRANSFER_FUNCTION_IDENTITY,
+   AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF,
+   AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF,
+   AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF,
+   AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF,
+   AMDGPU_TRANSFER_FUNCTION_BT709_OETF,
+   AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF,
+   AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF,
+   AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF,
+   AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF,
+AMDGPU_TRANSFER_FUNCTION_COUNT
 };
 
 struct dm_plane_state {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 8e02d2b1249d..a32abbd93a61 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -85,18 +85,57 @@ void amdgpu_dm_init_color_mod(void)
 }
 
 #ifdef AMD_PRIVATE_COLOR
-static const struct drm_prop_enum_list amdgpu_transfer_function_enum_list[] = {
-   { AMDGPU_TRANSFER_FUNCTION_DEFAULT, "Default" },
-   { AMDGPU_TRANSFER_FUNCTION_SRGB, "sRGB" },
-   { AMDGPU_TRANSFER_FUNCTION_BT709, "BT.709" },
-   { AMDGPU_TRANSFER_FUNCTION_PQ, "PQ (Perceptual Quantizer)" },
-   { AMDGPU_TRANSFER_FUNCTION_LINEAR, "Linear" },
-   { AMDGPU_TRANSFER_FUNCTION_UNITY, "Unity" },
-   { AMDGPU_TRANSFER_FUNCTION_GAMMA22, "Gamma 2.2" },
-   { AMDGPU_TRANSFER_FUNCTION_GAMMA24, "Gamma 2.4" },
-   { AMDGPU_TRANSFER_FUNCTION_GAMMA26, "Gamma 2.6" },
+static const char * const
+amdgpu_transfer_function_names[] = {
+   [AMDGPU_TRANSFER_FUNCTION_DEFAULT]  = "Default",
+   [AMDGPU_TRANSFER_FUNCTION_IDENTITY] = "Identity",
+   [AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF]= "sRGB EOTF",
+   [AMDGPU_TRANSFER_FUNCTION_BT709_INV_OETF]   = "BT.709 inv_OETF",
+   [AMDGPU_TRANSFER_FUNCTION_PQ_EOTF]  = "PQ EOTF",
+   [AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF] = "Gamma 2.2 EOTF",
+   [AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF] = "Gamma 2.4 EOTF",
+   [AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF] = "Gamma 2.6 EOTF",
+   [AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF]= "sRGB inv_EOTF",
+   [AMDGPU_TRANSFER_FUNCTION_BT709_OETF]   = "BT.709 OETF",
+   [AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF]  = "PQ inv_EOTF",
+   [AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF] = "Gamma 2.2 inv_EOTF",
+   [AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF] = "Gamma 2.4 inv_EOTF",
+   [AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF] = "Gamma 2.6 inv_EOTF",
 };
 
+static const u32 amdgpu_eotf =
+   BIT(AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF) |
+   BIT(AMDGPU_TRANSFER_FUNCTION_BT709_INV_OETF) |
+   BIT(AMDGPU_TRANSFER_FUNCTION_PQ_EOTF) |
+   BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF) |

[PATCH v5 10/32] drm/amd/display: add plane shaper LUT and TF driver-specific properties

2023-11-16 Thread Melissa Wen
On AMD HW, 3D LUT always assumes a preceding shaper 1D LUT used for
delinearizing and/or normalizing the color space before applying a 3D
LUT. Add pre-defined transfer function to enable delinearizing content
with or without shaper LUT, where AMD color module calculates the
resulted shaper curve. We apply an inverse EOTF to go from linear
values to encoded values. If we are already in a non-linear space and/or
don't need to normalize values, we can bypass shaper LUT with a linear
transfer function that is also the default TF value.

There is no shaper ROM. When setting shaper TF (!= Identity) and LUT at
the same time, the color module will combine the pre-defined TF and the
custom LUT values into the LUT that's actually programmed.

v2:
- squash commits for shaper LUT and shaper TF
- define inverse EOTF as supported shaper TFs

v3:
- spell out TF+LUT behavior in the commit and comments (Harry)
- replace BT709 EOTF by inv OETF

v5:
- get shaper blob correctly (Joshua)

Reviewed-by: Harry Wentland 
Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h  | 21 
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 11 +++
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 29 
 .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 33 +++
 4 files changed, 94 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index 57822477408f..bb27a3156204 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -364,6 +364,27 @@ struct amdgpu_mode_info {
 * @plane_hdr_mult_property:
 */
struct drm_property *plane_hdr_mult_property;
+   /**
+* @shaper_lut_property: Plane property to set pre-blending shaper LUT
+* that converts color content before 3D LUT. If
+* plane_shaper_tf_property != Identity TF, AMD color module will
+* combine the user LUT values with pre-defined TF into the LUT
+* parameters to be programmed.
+*/
+   struct drm_property *plane_shaper_lut_property;
+   /**
+* @shaper_lut_size_property: Plane property for the size of
+* pre-blending shaper LUT as supported by the driver (read-only).
+*/
+   struct drm_property *plane_shaper_lut_size_property;
+   /**
+* @plane_shaper_tf_property: Plane property to set a predefined
+* transfer function for pre-blending shaper (before applying 3D LUT)
+* with or without LUT. There is no shaper ROM, but we can use AMD
+* color modules to program LUT parameters from predefined TF (or
+* from a combination of pre-defined TF and the custom 1D LUT).
+*/
+   struct drm_property *plane_shaper_tf_property;
/**
 * @plane_lut3d_property: Plane property for color transformation using
 * a 3D LUT (pre-blending), a three-dimensional array where each
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 03b48b331b7c..33e18005226a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -776,6 +776,17 @@ struct dm_plane_state {
 * TF is needed for any subsequent linear-to-non-linear transforms.
 */
__u64 hdr_mult;
+   /**
+* @shaper_lut: shaper lookup table blob. The blob (if not NULL) is an
+* array of  drm_color_lut.
+*/
+   struct drm_property_blob *shaper_lut;
+   /**
+* @shaper_tf:
+*
+* Predefined transfer function to delinearize color space.
+*/
+   enum amdgpu_transfer_function shaper_tf;
/**
 * @lut3d: 3D lookup table blob. The blob (if not NULL) is an array of
 *  drm_color_lut.
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index a3b4f6a4c4a8..866c6f1d3d99 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -173,6 +173,14 @@ static const u32 amdgpu_eotf =
BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF) |
BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF);
 
+static const u32 amdgpu_inv_eotf =
+   BIT(AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF) |
+   BIT(AMDGPU_TRANSFER_FUNCTION_BT709_OETF) |
+   BIT(AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF) |
+   BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF) |
+   BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF) |
+   BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF);
+
 static struct drm_property *
 amdgpu_create_tf_property(struct drm_device *dev,
  const char *name,
@@ -231,6 +239,27 @@ amdgpu_dm_create_color_properties(struct amdgpu_device 
*adev)
return -ENOMEM;
adev->mode_info.plane_hdr_mult_property = p

[PATCH v5 05/32] drm/amd/display: add plane degamma TF driver-specific property

2023-11-16 Thread Melissa Wen
From: Joshua Ashton 

Allow userspace to tell the kernel driver the input space and,
therefore, uses correct predefined transfer function (TF) to go from
encoded values to linear values.

v2:
- rename TF enum prefix from DRM_ to AMDGPU_ (Harry)
- remove HLG TF

Reviewed-by: Harry Wentland 
Signed-off-by: Joshua Ashton 
Co-developed-by: Melissa Wen 
Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h  |  5 +
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 19 +
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 21 +++
 .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 19 +++--
 4 files changed, 62 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index 13efb12edbcf..50572fe27ab0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -355,6 +355,11 @@ struct amdgpu_mode_info {
 * size of degamma LUT as supported by the driver (read-only).
 */
struct drm_property *plane_degamma_lut_size_property;
+   /**
+* @plane_degamma_tf_property: Plane pre-defined transfer function to
+* to go from scanout/encoded values to linear values.
+*/
+   struct drm_property *plane_degamma_tf_property;
 };
 
 #define AMDGPU_MAX_BL_LEVEL 0xFF
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 0eafbf00505b..ab89538d5663 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -716,6 +716,18 @@ static inline void amdgpu_dm_set_mst_status(uint8_t 
*status,
 
 extern const struct amdgpu_ip_block_version dm_ip_block;
 
+enum amdgpu_transfer_function {
+   AMDGPU_TRANSFER_FUNCTION_DEFAULT,
+   AMDGPU_TRANSFER_FUNCTION_SRGB,
+   AMDGPU_TRANSFER_FUNCTION_BT709,
+   AMDGPU_TRANSFER_FUNCTION_PQ,
+   AMDGPU_TRANSFER_FUNCTION_LINEAR,
+   AMDGPU_TRANSFER_FUNCTION_UNITY,
+   AMDGPU_TRANSFER_FUNCTION_GAMMA22,
+   AMDGPU_TRANSFER_FUNCTION_GAMMA24,
+   AMDGPU_TRANSFER_FUNCTION_GAMMA26,
+};
+
 struct dm_plane_state {
struct drm_plane_state base;
struct dc_plane_state *dc_state;
@@ -729,6 +741,13 @@ struct dm_plane_state {
 * The blob (if not NULL) is an array of  drm_color_lut.
 */
struct drm_property_blob *degamma_lut;
+   /**
+* @degamma_tf:
+*
+* Predefined transfer function to tell DC driver the input space to
+* linearize.
+*/
+   enum amdgpu_transfer_function degamma_tf;
 };
 
 struct dm_crtc_state {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 421af919387f..8e02d2b1249d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -85,6 +85,18 @@ void amdgpu_dm_init_color_mod(void)
 }
 
 #ifdef AMD_PRIVATE_COLOR
+static const struct drm_prop_enum_list amdgpu_transfer_function_enum_list[] = {
+   { AMDGPU_TRANSFER_FUNCTION_DEFAULT, "Default" },
+   { AMDGPU_TRANSFER_FUNCTION_SRGB, "sRGB" },
+   { AMDGPU_TRANSFER_FUNCTION_BT709, "BT.709" },
+   { AMDGPU_TRANSFER_FUNCTION_PQ, "PQ (Perceptual Quantizer)" },
+   { AMDGPU_TRANSFER_FUNCTION_LINEAR, "Linear" },
+   { AMDGPU_TRANSFER_FUNCTION_UNITY, "Unity" },
+   { AMDGPU_TRANSFER_FUNCTION_GAMMA22, "Gamma 2.2" },
+   { AMDGPU_TRANSFER_FUNCTION_GAMMA24, "Gamma 2.4" },
+   { AMDGPU_TRANSFER_FUNCTION_GAMMA26, "Gamma 2.6" },
+};
+
 int
 amdgpu_dm_create_color_properties(struct amdgpu_device *adev)
 {
@@ -105,6 +117,15 @@ amdgpu_dm_create_color_properties(struct amdgpu_device 
*adev)
return -ENOMEM;
adev->mode_info.plane_degamma_lut_size_property = prop;
 
+   prop = drm_property_create_enum(adev_to_drm(adev),
+   DRM_MODE_PROP_ENUM,
+   "AMD_PLANE_DEGAMMA_TF",
+   amdgpu_transfer_function_enum_list,
+   
ARRAY_SIZE(amdgpu_transfer_function_enum_list));
+   if (!prop)
+   return -ENOMEM;
+   adev->mode_info.plane_degamma_tf_property = prop;
+
return 0;
 }
 #endif
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index b1e50cfa9f83..d5e12e05d161 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -1337,8 +1337,11 @@ static void amdgpu_dm_plane_drm_plane_reset(struct 
drm_plane *plane)
amdgpu_state = kza

[PATCH v5 04/32] drm/amd/display: add driver-specific property for plane degamma LUT

2023-11-16 Thread Melissa Wen
Hook up driver-specific atomic operations for managing AMD color
properties. Create AMD driver-specific color management properties
and attach them according to HW capabilities defined by `struct
dc_color_caps`.

First add plane degamma LUT properties that means user-blob and its
size. We will add more plane color properties in the next patches. In
addition, we define AMD_PRIVATE_COLOR to guard these driver-specific
plane properties.

Plane degamma can be used to linearize input space for arithmetical
operations that are more accurate when applied in linear color.

v2:
- update degamma LUT prop description
- move private color operations from amdgpu_display to amdgpu_dm_color

v5:
- get degamma blob correctly (Joshua)

Reviewed-by: Harry Wentland 
Co-developed-by: Joshua Ashton 
Signed-off-by: Joshua Ashton 
Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h  | 12 +++
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  5 ++
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 11 +++
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 25 ++
 .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 85 +++
 5 files changed, 138 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index 32fe05c810c6..13efb12edbcf 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -343,6 +343,18 @@ struct amdgpu_mode_info {
int disp_priority;
const struct amdgpu_display_funcs *funcs;
const enum drm_plane_type *plane_type;
+
+   /* Driver-private color mgmt props */
+
+   /* @plane_degamma_lut_property: Plane property to set a degamma LUT to
+* convert encoded values to light linear values before sampling or
+* blending.
+*/
+   struct drm_property *plane_degamma_lut_property;
+   /* @plane_degamma_lut_size_property: Plane property to define the max
+* size of degamma LUT as supported by the driver (read-only).
+*/
+   struct drm_property *plane_degamma_lut_size_property;
 };
 
 #define AMDGPU_MAX_BL_LEVEL 0xFF
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index adbeb2c897b5..56053de2aaea 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -4027,6 +4027,11 @@ static int amdgpu_dm_mode_config_init(struct 
amdgpu_device *adev)
return r;
}
 
+#ifdef AMD_PRIVATE_COLOR
+   if (amdgpu_dm_create_color_properties(adev))
+   return -ENOMEM;
+#endif
+
r = amdgpu_dm_audio_init(adev);
if (r) {
dc_release_state(state->context);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 3d480be802cb..0eafbf00505b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -719,6 +719,16 @@ extern const struct amdgpu_ip_block_version dm_ip_block;
 struct dm_plane_state {
struct drm_plane_state base;
struct dc_plane_state *dc_state;
+
+   /* Plane color mgmt */
+   /**
+* @degamma_lut:
+*
+* 1D LUT for mapping framebuffer/plane pixel data before sampling or
+* blending operations. It's usually applied to linearize input space.
+* The blob (if not NULL) is an array of  drm_color_lut.
+*/
+   struct drm_property_blob *degamma_lut;
 };
 
 struct dm_crtc_state {
@@ -809,6 +819,7 @@ void amdgpu_dm_trigger_timing_sync(struct drm_device *dev);
 #define MAX_COLOR_LEGACY_LUT_ENTRIES 256
 
 void amdgpu_dm_init_color_mod(void);
+int amdgpu_dm_create_color_properties(struct amdgpu_device *adev);
 int amdgpu_dm_verify_lut_sizes(const struct drm_crtc_state *crtc_state);
 int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc);
 int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index a4cb23d059bd..421af919387f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -84,6 +84,31 @@ void amdgpu_dm_init_color_mod(void)
setup_x_points_distribution();
 }
 
+#ifdef AMD_PRIVATE_COLOR
+int
+amdgpu_dm_create_color_properties(struct amdgpu_device *adev)
+{
+   struct drm_property *prop;
+
+   prop = drm_property_create(adev_to_drm(adev),
+  DRM_MODE_PROP_BLOB,
+  "AMD_PLANE_DEGAMMA_LUT", 0);
+   if (!prop)
+   return -ENOMEM;
+   adev->mode_info.plane_degamma_lut_property = prop;
+
+   prop = drm_property_create_range(

[PATCH v5 02/32] drm/drm_property: make replace_property_blob_from_id a DRM helper

2023-11-16 Thread Melissa Wen
Place it in drm_property where drm_property_replace_blob and
drm_property_lookup_blob live. Then we can use the DRM helper for
driver-specific KMS properties too.

Reviewed-by: Harry Wentland 
Reviewed-by: Liviu Dudau 
Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/arm/malidp_crtc.c |  2 +-
 drivers/gpu/drm/drm_atomic_uapi.c | 43 ---
 drivers/gpu/drm/drm_property.c| 49 +++
 include/drm/drm_property.h|  6 
 4 files changed, 61 insertions(+), 39 deletions(-)

diff --git a/drivers/gpu/drm/arm/malidp_crtc.c 
b/drivers/gpu/drm/arm/malidp_crtc.c
index dc01c43f6193..d72c22dcf685 100644
--- a/drivers/gpu/drm/arm/malidp_crtc.c
+++ b/drivers/gpu/drm/arm/malidp_crtc.c
@@ -221,7 +221,7 @@ static int malidp_crtc_atomic_check_ctm(struct drm_crtc 
*crtc,
 
/*
 * The size of the ctm is checked in
-* drm_atomic_replace_property_blob_from_id.
+* drm_property_replace_blob_from_id.
 */
ctm = (struct drm_color_ctm *)state->ctm->data;
for (i = 0; i < ARRAY_SIZE(ctm->matrix); ++i) {
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c 
b/drivers/gpu/drm/drm_atomic_uapi.c
index d867e7f9f2cd..a6a9ee5086dd 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -362,39 +362,6 @@ static s32 __user *get_out_fence_for_connector(struct 
drm_atomic_state *state,
return fence_ptr;
 }
 
-static int
-drm_atomic_replace_property_blob_from_id(struct drm_device *dev,
-struct drm_property_blob **blob,
-uint64_t blob_id,
-ssize_t expected_size,
-ssize_t expected_elem_size,
-bool *replaced)
-{
-   struct drm_property_blob *new_blob = NULL;
-
-   if (blob_id != 0) {
-   new_blob = drm_property_lookup_blob(dev, blob_id);
-   if (new_blob == NULL)
-   return -EINVAL;
-
-   if (expected_size > 0 &&
-   new_blob->length != expected_size) {
-   drm_property_blob_put(new_blob);
-   return -EINVAL;
-   }
-   if (expected_elem_size > 0 &&
-   new_blob->length % expected_elem_size != 0) {
-   drm_property_blob_put(new_blob);
-   return -EINVAL;
-   }
-   }
-
-   *replaced |= drm_property_replace_blob(blob, new_blob);
-   drm_property_blob_put(new_blob);
-
-   return 0;
-}
-
 static int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
struct drm_crtc_state *state, struct drm_property *property,
uint64_t val)
@@ -415,7 +382,7 @@ static int drm_atomic_crtc_set_property(struct drm_crtc 
*crtc,
} else if (property == config->prop_vrr_enabled) {
state->vrr_enabled = val;
} else if (property == config->degamma_lut_property) {
-   ret = drm_atomic_replace_property_blob_from_id(dev,
+   ret = drm_property_replace_blob_from_id(dev,
>degamma_lut,
val,
-1, sizeof(struct drm_color_lut),
@@ -423,7 +390,7 @@ static int drm_atomic_crtc_set_property(struct drm_crtc 
*crtc,
state->color_mgmt_changed |= replaced;
return ret;
} else if (property == config->ctm_property) {
-   ret = drm_atomic_replace_property_blob_from_id(dev,
+   ret = drm_property_replace_blob_from_id(dev,
>ctm,
val,
sizeof(struct drm_color_ctm), -1,
@@ -431,7 +398,7 @@ static int drm_atomic_crtc_set_property(struct drm_crtc 
*crtc,
state->color_mgmt_changed |= replaced;
return ret;
} else if (property == config->gamma_lut_property) {
-   ret = drm_atomic_replace_property_blob_from_id(dev,
+   ret = drm_property_replace_blob_from_id(dev,
>gamma_lut,
val,
-1, sizeof(struct drm_color_lut),
@@ -563,7 +530,7 @@ static int drm_atomic_plane_set_property(struct drm_plane 
*plane,
} else if (property == plane->color_range_property) {
state->color_range = val;
} else if (property == config->prop_fb_damage_clips) {
-   ret = drm_atomic_replace_property_blob_from_id(dev,
+   ret = drm_property_replace_blob_from_id(dev,
>fb_damage_clips,
 

[PATCH v5 00/32] drm/amd/display: add AMD driver-specific properties for color mgmt

2023-11-16 Thread Melissa Wen
Hello,

This series extends the current KMS color management API with AMD
driver-specific properties to enhance the color management support on
AMD Steam Deck. The key additions to the color pipeline include:

- plane degamma LUT and pre-defined TF;
- plane HDR multiplier;
- plane CTM 3x4;
- plane shaper LUT and pre-defined TF;
- plane 3D LUT;
- plane blend LUT and pre-defined TF;
- CRTC gamma pre-defined TF;

You can find the AMD HW color capabilities documented here:
https://dri.freedesktop.org/docs/drm/gpu/amdgpu/display/display-manager.html#color-management-properties

The userspace case is Gamescope[1], the compositor for SteamOS.
Gamescope has already adopted AMD driver-specific properties to
implement comprehensive color management support, including gamut
mapping, HDR rendering, SDR on HDR, HDR on SDR. Using these features in
the SteamOS 3.5[2] users can expect a significantly enhanced visual
experience. 

You can find a brief overview of the Steam Deck color pipeline here:
https://github.com/ValveSoftware/gamescope/blob/master/src/docs/Steam%20Deck%20Display%20Pipeline.png

This version (v5) includes the fixes for documentation (Sebastian),
suspend/resume and color management setup (Joshua) suggested in the
previous version. It also includes Harry's reviewed-by.

Thank you everyone for reviews and feedback.

Changes since:

[RFC] https://lore.kernel.org/dri-devel/20230423141051.702990-1-m...@igalia.com
- Remove KConfig and guard properties with `AMD_PRIVATE_COLOR`;
- Remove properties for post-blending/CRTC shaper TF+LUT and 3D LUT;
- Use color caps to improve the support of pre-defined curve;

[v1] https://lore.kernel.org/dri-devel/20230523221520.3115570-1-m...@igalia.com
- Replace DRM_ by AMDGPU_ prefix for transfer function (TF) enum; 
- Explicitly define EOTFs and inverse EOTFs and set props accordingly;
- Document pre-defined transfer functions;
- Remove HLG transfer function from supported TFs;
- Remove misleading comments;
- Remove post-blending shaper TF+LUT and 3D LUT support;
- Move driver-specific property operations from amdgpu_display.c to
  amdgpu_dm_color.c;
- Reset planes if any color props change;
- Add plane CTM 3x4 support;
- Removed two DC fixes already applied upstream;

[v2] https://lore.kernel.org/dri-devel/20230810160314.48225-1-m...@igalia.com
- Many documentation fixes: BT.709 OETF, description of sRGB and pure
  power functions, TF+1D LUT behavior;
- Rename CTM2 to CTM 3x4 and fix misleading comment about DC gamut remap;
- Squash `Linear` and `Unity` TF in `Identity`;
- Remove the `MPC gamut remap` patch already applied upstream[3];
- Remove outdated delta segmentation fix;
- Nits/small fixes;

[v3] https://lore.kernel.org/amd-gfx/20230925194932.1329483-1-m...@igalia.com
- Add table to describe value range in linear and non-linear forms;
- Comment the PQ TF need after HDR multiplier;
- Advertise the 3D LUT size as the size of a single-dimension (read-only);
- remove function to check expected size from 3DLUT caps;
- cleanup comments.

[v4] https://lore.kernel.org/amd-gfx/20231005171527.203657-1-m...@igalia.com
- Fix documentation about 3D LUT size;
- Correctly getting LUT blobs;
- Always set plane color properties, regardless plane->color_mgmt_changed.

It's worth noting that driver-specific properties are guarded by
cflags `AMD_PRIVATE_COLOR`.

Best Regards,

Melissa Wen

[1] https://github.com/ValveSoftware/gamescope
[2] https://store.steampowered.com/news/app/1675200/view/3686804163591367815
[3] https://lore.kernel.org/dri-devel/20230721132431.692158-1-m...@igalia.com

Joshua Ashton (14):
  drm/amd/display: add plane degamma TF driver-specific property
  drm/amd/display: add plane HDR multiplier driver-specific property
  drm/amd/display: add plane blend LUT and TF driver-specific properties
  drm/amd/display: add CRTC gamma TF support
  drm/amd/display: set sdr_ref_white_level to 80 for out_transfer_func
  drm/amd/display: mark plane as needing reset if color props change
  drm/amd/display: add plane degamma TF and LUT support
  drm/amd/display: add dc_fixpt_from_s3132 helper
  drm/amd/display: add HDR multiplier support
  drm/amd/display: handle empty LUTs in __set_input_tf
  drm/amd/display: add plane blend LUT and TF support
  drm/amd/display: allow newer DC hardware to use degamma ROM for PQ/HLG
  drm/amd/display: copy 3D LUT settings from crtc state to stream_update
  drm/amd/display: Add 3x4 CTM support for plane CTM

Melissa Wen (18):
  drm/drm_mode_object: increase max objects to accommodate new color
props
  drm/drm_property: make replace_property_blob_from_id a DRM helper
  drm/drm_plane: track color mgmt changes per plane
  drm/amd/display: add driver-specific property for plane degamma LUT
  drm/amd/display: explicitly define EOTF and inverse EOTF
  drm/amd/display: document AMDGPU pre-defined transfer functions
  drm/amd/display: add plane 3D LUT driver-specific properties
  drm/amd/display: add plane shaper LUT and TF driver-specific
propert

[PATCH v5 01/32] drm/drm_mode_object: increase max objects to accommodate new color props

2023-11-16 Thread Melissa Wen
DRM_OBJECT_MAX_PROPERTY limits the number of properties to be attached
and we are increasing that value all time we add a new property (generic
or driver-specific).

In this series, we are adding 13 new KMS driver-specific properties for
AMD color manage:
- CRTC Gamma enumerated Transfer Function
- Plane: Degamma LUT+size+TF, HDR multiplier, shaper LUT+size+TF, 3D
  LUT+size, blend LUT+size+TF (12)

Therefore, just increase DRM_OBJECT_MAX_PROPERTY to a number (64) that
accomodates these new properties and gives some room for others,
avoiding change this number everytime we add a new KMS property.

Reviewed-by: Harry Wentland 
Reviewed-by: Simon Ser 
Signed-off-by: Melissa Wen 
---
 include/drm/drm_mode_object.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/drm/drm_mode_object.h b/include/drm/drm_mode_object.h
index 912f1e415685..08d7a7f0188f 100644
--- a/include/drm/drm_mode_object.h
+++ b/include/drm/drm_mode_object.h
@@ -60,7 +60,7 @@ struct drm_mode_object {
void (*free_cb)(struct kref *kref);
 };
 
-#define DRM_OBJECT_MAX_PROPERTY 24
+#define DRM_OBJECT_MAX_PROPERTY 64
 /**
  * struct drm_object_properties - property tracking for _mode_object
  */
-- 
2.40.1



Re: [PATCH v4 00/32] drm/amd/display: add AMD driver-specific properties for color mgmt

2023-11-06 Thread Melissa Wen
On 10/06, Sebastian Wick wrote:
> On Thu, Oct 05, 2023 at 04:14:55PM -0100, Melissa Wen wrote:
> > Hello,
> > 
> > Just another iteration for AMD driver-specific color properties.
> > Basically, addressing comments from the previous version.
> > 
> > Recap: this series extends the current KMS color management API with AMD
> > driver-specific properties to enhance the color management support on
> > AMD Steam Deck. The key additions to the color pipeline include:
> 
> Did you talk with the maintainers about this already? The last few times
> driver specific properties, and even kind of generic plane properties
> with a fixed position in the pipeline were proposed they were all
> NAKed. Just putting them behind a define doesn't sound great and I don't
> think there is any precedence for allowing this in. This is basically
> just more burden for upstream without any benefits for upstream.

Hi Sebastian,

Sorry for delaying. I believe it was already answered during the XDC KMS
color workshop, but: yes, I've talked with them and they are fine with
the cflags approach. Remember that we are not using here kconfig anymore.
The driver-specific properties (creation and attachment) are guarded by
cflags, not a kernel building option. We changed to cflags after Harry's
suggestion in the first version.

I think the main point for upstream it now is that we can actually
exercise the plane color properties and all machinery around new color
elements (as 3D LUT) with a userspace that cares about it (Gamescope).
Worth mentioning that I removed CRTC shaper/3D LUT support from previous
version, because, even with the internal implementation, we don't have
how to exercise these CRTC properties right now.

Finally, the main goal is ofc attaching it to the generic API from
Harry's series. We are all in the same page about it.

BR,

Melissa

> 
> Maybe you can separate the uAPI changes from the internal improvements
> to land at least parts of this faster.
> 
> > - plane degamma LUT and pre-defined TF;
> > - plane HDR multiplier;
> > - plane CTM 3x4;
> > - plane shaper LUT and pre-defined TF;
> > - plane 3D LUT;
> > - plane blend LUT and pre-defined TF;
> > - CRTC gamma pre-defined TF;
> > 
> > You can find the AMD HW color capabilities documented here:
> > https://dri.freedesktop.org/docs/drm/gpu/amdgpu/display/display-manager.html#color-management-properties
> > 
> > The userspace case is Gamescope[1], the compositor for SteamOS.
> > Gamescope has already adopted AMD driver-specific properties to
> > implement comprehensive color management support, including gamut
> > mapping, HDR rendering, SDR on HDR, HDR on SDR. Using these features in
> > the SteamOS 3.5[2] users can expect a significantly enhanced visual
> > experience. 
> > 
> > You can find a brief overview of the Steam Deck color pipeline here:
> > https://github.com/ValveSoftware/gamescope/blob/master/src/docs/Steam%20Deck%20Display%20Pipeline.png
> > 
> > Changes from:
> > 
> > [RFC] 
> > https://lore.kernel.org/dri-devel/20230423141051.702990-1-m...@igalia.com
> > - Remove KConfig and guard properties with `AMD_PRIVATE_COLOR`;
> > - Remove properties for post-blending/CRTC shaper TF+LUT and 3D LUT;
> > - Use color caps to improve the support of pre-defined curve;
> > 
> > [v1] 
> > https://lore.kernel.org/dri-devel/20230523221520.3115570-1-m...@igalia.com
> > - Replace DRM_ by AMDGPU_ prefix for transfer function (TF) enum; 
> > - Explicitly define EOTFs and inverse EOTFs and set props accordingly;
> > - Document pre-defined transfer functions;
> > - Remove HLG transfer function from supported TFs;
> > - Remove misleading comments;
> > - Remove post-blending shaper TF+LUT and 3D LUT support;
> > - Move driver-specific property operations from amdgpu_display.c to
> >   amdgpu_dm_color.c;
> > - Reset planes if any color props change;
> > - Add plane CTM 3x4 support;
> > - Removed two DC fixes already applied upstream;
> > 
> > [v2] 
> > https://lore.kernel.org/dri-devel/20230810160314.48225-1-m...@igalia.com
> > - Many documentation fixes: BT.709 OETF, description of sRGB and pure
> >   power functions, TF+1D LUT behavior;
> > - Rename CTM2 to CTM 3x4 and fix misleading comment about DC gamut remap;
> > - Squash `Linear` and `Unity` TF in `Identity`;
> > - Remove the `MPC gamut remap` patch already applied upstream[3];
> > - Remove outdated delta segmentation fix;
> > - Nits/small fixes;
> > 
> > [v3] 
> > https://lore.kernel.org/amd-gfx/20230925194932.1329483-1-m...@igalia.com
> > - Add table to describe value range in linear and n

Re: [PATCH v4 09/32] drm/amd/display: add plane 3D LUT driver-specific properties

2023-11-06 Thread Melissa Wen
On 11/02, Joshua Ashton wrote:
> Also, Melissa, you cannot do:
> 
>   if (!plane_state->color_mgmt_changed)
>   return 0;
> 
> in amdgpu_dm_plane_set_color_properties.
> 
> The allocation for dc_plane_state could be new and zero'ed so it needs to be
> set every time. (Until AMDGPU has better dedup'ing of stuff there)
> 
> The reason it looked like it worked for you now is because the duplicate was
> broken, so color mgmt for planes was always being marked as dirty there.

I see, it makes sense. I'll double-check it out, but thanks again for
debugging the issue.

BR,

Melissa

> 
> Thanks
> 
> - Joshie ✨
> 
> On 11/2/23 03:48, Joshua Ashton wrote:
> > 
> > 
> > On 10/5/23 18:15, Melissa Wen wrote:
> > > Add 3D LUT property for plane color transformations using a 3D lookup
> > > table. 3D LUT allows for highly accurate and complex color
> > > transformations and is suitable to adjust the balance between color
> > > channels. It's also more complex to manage and require more
> > > computational resources.
> > > 
> > > Since a 3D LUT has a limited number of entries in each dimension we want
> > > to use them in an optimal fashion. This means using the 3D LUT in a
> > > colorspace that is optimized for human vision, such as sRGB, PQ, or
> > > another non-linear space. Therefore, userpace may need one 1D LUT
> > > (shaper) before it to delinearize content and another 1D LUT after 3D
> > > LUT (blend) to linearize content again for blending. The next patches
> > > add these 1D LUTs to the plane color mgmt pipeline.
> > > 
> > > v3:
> > > - improve commit message about 3D LUT
> > > - describe the 3D LUT entries and size (Harry)
> > > 
> > > v4:
> > > - advertise 3D LUT max size as the size of a single-dimension
> > > 
> > > Signed-off-by: Melissa Wen 
> > > ---
> > >   drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h  | 18 +++
> > >   .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  9 
> > >   .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 14 +++
> > >   .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 23 +++
> > >   4 files changed, 64 insertions(+)
> > > 
> > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> > > b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> > > index 62044d41da75..f7adaa52c23f 100644
> > > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> > > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> > > @@ -363,6 +363,24 @@ struct amdgpu_mode_info {
> > >    * @plane_hdr_mult_property:
> > >    */
> > >   struct drm_property *plane_hdr_mult_property;
> > > +    /**
> > > + * @plane_lut3d_property: Plane property for color
> > > transformation using
> > > + * a 3D LUT (pre-blending), a three-dimensional array where each
> > > + * element is an RGB triplet. Each dimension has a size of the cubed
> > > + * root of lut3d_size. The array contains samples from the
> > > approximated
> > > + * function. On AMD, values between samples are estimated by
> > > + * tetrahedral interpolation. The array is accessed with three
> > > indices,
> > > + * one for each input dimension (color channel), blue being the
> > > + * outermost dimension, red the innermost.
> > > + */
> > > +    struct drm_property *plane_lut3d_property;
> > > +    /**
> > > + * @plane_degamma_lut_size_property: Plane property to define
> > > the max
> > > + * size of 3D LUT as supported by the driver (read-only). The
> > > max size
> > > + * is the max size of one dimension and, therefore, the max
> > > number of
> > > + * entries for 3D LUT array is the 3D LUT size cubed;
> > > + */
> > > +    struct drm_property *plane_lut3d_size_property;
> > >   };
> > >   #define AMDGPU_MAX_BL_LEVEL 0xFF
> > > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> > > b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> > > index bb2ce843369d..7a2350c62cf1 100644
> > > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> > > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> > > @@ -784,6 +784,11 @@ struct dm_plane_state {
> > >    * TF is needed for any subsequent linear-to-non-linear transforms.
> > >    */
> > >   __u64 hdr_mult;
> > > +    /**
> > > +

Re: [PATCH v4 09/32] drm/amd/display: add plane 3D LUT driver-specific properties

2023-11-06 Thread Melissa Wen
On 11/02, Joshua Ashton wrote:
> 
> 
> On 10/5/23 18:15, Melissa Wen wrote:
> > Add 3D LUT property for plane color transformations using a 3D lookup
> > table. 3D LUT allows for highly accurate and complex color
> > transformations and is suitable to adjust the balance between color
> > channels. It's also more complex to manage and require more
> > computational resources.
> > 
> > Since a 3D LUT has a limited number of entries in each dimension we want
> > to use them in an optimal fashion. This means using the 3D LUT in a
> > colorspace that is optimized for human vision, such as sRGB, PQ, or
> > another non-linear space. Therefore, userpace may need one 1D LUT
> > (shaper) before it to delinearize content and another 1D LUT after 3D
> > LUT (blend) to linearize content again for blending. The next patches
> > add these 1D LUTs to the plane color mgmt pipeline.
> > 
> > v3:
> > - improve commit message about 3D LUT
> > - describe the 3D LUT entries and size (Harry)
> > 
> > v4:
> > - advertise 3D LUT max size as the size of a single-dimension
> > 
> > Signed-off-by: Melissa Wen 
> > ---
> >   drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h  | 18 +++
> >   .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  9 
> >   .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 14 +++
> >   .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 23 +++
> >   4 files changed, 64 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h 
> > b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> > index 62044d41da75..f7adaa52c23f 100644
> > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> > @@ -363,6 +363,24 @@ struct amdgpu_mode_info {
> >  * @plane_hdr_mult_property:
> >  */
> > struct drm_property *plane_hdr_mult_property;
> > +   /**
> > +* @plane_lut3d_property: Plane property for color transformation using
> > +* a 3D LUT (pre-blending), a three-dimensional array where each
> > +* element is an RGB triplet. Each dimension has a size of the cubed
> > +* root of lut3d_size. The array contains samples from the approximated
> > +* function. On AMD, values between samples are estimated by
> > +* tetrahedral interpolation. The array is accessed with three indices,
> > +* one for each input dimension (color channel), blue being the
> > +* outermost dimension, red the innermost.
> > +*/
> > +   struct drm_property *plane_lut3d_property;
> > +   /**
> > +* @plane_degamma_lut_size_property: Plane property to define the max
> > +* size of 3D LUT as supported by the driver (read-only). The max size
> > +* is the max size of one dimension and, therefore, the max number of
> > +* entries for 3D LUT array is the 3D LUT size cubed;
> > +*/
> > +   struct drm_property *plane_lut3d_size_property;
> >   };
> >   #define AMDGPU_MAX_BL_LEVEL 0xFF
> > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
> > b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> > index bb2ce843369d..7a2350c62cf1 100644
> > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> > @@ -784,6 +784,11 @@ struct dm_plane_state {
> >  * TF is needed for any subsequent linear-to-non-linear transforms.
> >  */
> > __u64 hdr_mult;
> > +   /**
> > +* @lut3d: 3D lookup table blob. The blob (if not NULL) is an array of
> > +*  drm_color_lut.
> > +*/
> > +   struct drm_property_blob *lut3d;
> >   };
> >   struct dm_crtc_state {
> > @@ -869,6 +874,10 @@ void amdgpu_dm_update_freesync_caps(struct 
> > drm_connector *connector,
> >   void amdgpu_dm_trigger_timing_sync(struct drm_device *dev);
> > +/* 3D LUT max size is 17x17x17 (4913 entries) */
> > +#define MAX_COLOR_3DLUT_SIZE 17
> > +#define MAX_COLOR_3DLUT_BITDEPTH 12
> > +/* 1D LUT size */
> >   #define MAX_COLOR_LUT_ENTRIES 4096
> >   /* Legacy gamm LUT users such as X doesn't like large LUT sizes */
> >   #define MAX_COLOR_LEGACY_LUT_ENTRIES 256
> > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
> > b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
> > index caf49a044ab4..011f2f9ec890 100644
> > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
> > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
> > @@ -230,6 +230,20 @@ amdgpu_

Re: [PATCH v4 09/32] drm/amd/display: add plane 3D LUT driver-specific properties

2023-11-06 Thread Melissa Wen
On 10/06, Sebastian Wick wrote:
> On Thu, Oct 05, 2023 at 04:15:04PM -0100, Melissa Wen wrote:
> > Add 3D LUT property for plane color transformations using a 3D lookup
> > table. 3D LUT allows for highly accurate and complex color
> > transformations and is suitable to adjust the balance between color
> > channels. It's also more complex to manage and require more
> > computational resources.
> > 
> > Since a 3D LUT has a limited number of entries in each dimension we want
> > to use them in an optimal fashion. This means using the 3D LUT in a
> > colorspace that is optimized for human vision, such as sRGB, PQ, or
> > another non-linear space. Therefore, userpace may need one 1D LUT
> > (shaper) before it to delinearize content and another 1D LUT after 3D
> > LUT (blend) to linearize content again for blending. The next patches
> > add these 1D LUTs to the plane color mgmt pipeline.
> > 
> > v3:
> > - improve commit message about 3D LUT
> > - describe the 3D LUT entries and size (Harry)
> > 
> > v4:
> > - advertise 3D LUT max size as the size of a single-dimension
> > 
> > Signed-off-by: Melissa Wen 
> > ---
> >  drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h  | 18 +++
> >  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  9 
> >  .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 14 +++
> >  .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 23 +++
> >  4 files changed, 64 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h 
> > b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> > index 62044d41da75..f7adaa52c23f 100644
> > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> > @@ -363,6 +363,24 @@ struct amdgpu_mode_info {
> >  * @plane_hdr_mult_property:
> >  */
> > struct drm_property *plane_hdr_mult_property;
> > +   /**
> > +* @plane_lut3d_property: Plane property for color transformation using
> > +* a 3D LUT (pre-blending), a three-dimensional array where each
> > +* element is an RGB triplet. Each dimension has a size of the cubed
> > +* root of lut3d_size. The array contains samples from the approximated
> 
> This should be "Each dimension has a size of lut3d_size" now.

You're right. Thanks for pointed it out.

> 
> > +* function. On AMD, values between samples are estimated by
> > +* tetrahedral interpolation. The array is accessed with three indices,
> > +* one for each input dimension (color channel), blue being the
> > +* outermost dimension, red the innermost.
> > +*/
> > +   struct drm_property *plane_lut3d_property;
> > +   /**
> > +* @plane_degamma_lut_size_property: Plane property to define the max
> > +* size of 3D LUT as supported by the driver (read-only). The max size
> > +* is the max size of one dimension and, therefore, the max number of
> > +* entries for 3D LUT array is the 3D LUT size cubed;
> > +*/
> > +   struct drm_property *plane_lut3d_size_property;
> >  };
> >  
> >  #define AMDGPU_MAX_BL_LEVEL 0xFF
> > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
> > b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> > index bb2ce843369d..7a2350c62cf1 100644
> > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> > @@ -784,6 +784,11 @@ struct dm_plane_state {
> >  * TF is needed for any subsequent linear-to-non-linear transforms.
> >  */
> > __u64 hdr_mult;
> > +   /**
> > +* @lut3d: 3D lookup table blob. The blob (if not NULL) is an array of
> > +*  drm_color_lut.
> > +*/
> > +   struct drm_property_blob *lut3d;
> >  };
> >  
> >  struct dm_crtc_state {
> > @@ -869,6 +874,10 @@ void amdgpu_dm_update_freesync_caps(struct 
> > drm_connector *connector,
> >  
> >  void amdgpu_dm_trigger_timing_sync(struct drm_device *dev);
> >  
> > +/* 3D LUT max size is 17x17x17 (4913 entries) */
> > +#define MAX_COLOR_3DLUT_SIZE 17
> > +#define MAX_COLOR_3DLUT_BITDEPTH 12
> > +/* 1D LUT size */
> >  #define MAX_COLOR_LUT_ENTRIES 4096
> >  /* Legacy gamm LUT users such as X doesn't like large LUT sizes */
> >  #define MAX_COLOR_LEGACY_LUT_ENTRIES 256
> > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
> > b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
> > index caf49a044ab4..011f2f9ec890 100644
> > --- a/drivers/gpu/drm/amd/dis

[PATCH v4 32/32] drm/amd/display: Add 3x4 CTM support for plane CTM

2023-10-05 Thread Melissa Wen
From: Joshua Ashton 

Create drm_color_ctm_3x4 to support 3x4-dimension plane CTM matrix and
convert DRM CTM to DC CSC float matrix.

v3:
- rename ctm2 to ctm_3x4 (Harry)

Reviewed-by: Harry Wentland 
Signed-off-by: Joshua Ashton 
---
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 28 +--
 .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   |  2 +-
 include/uapi/drm/drm_mode.h   |  8 ++
 3 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index bc9dd75e8881..655c18c9a2d7 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -433,6 +433,28 @@ static void __drm_ctm_to_dc_matrix(const struct 
drm_color_ctm *ctm,
}
 }
 
+/**
+ * __drm_ctm_3x4_to_dc_matrix - converts a DRM CTM 3x4 to a DC CSC float matrix
+ * @ctm: DRM color transformation matrix with 3x4 dimensions
+ * @matrix: DC CSC float matrix
+ *
+ * The matrix needs to be a 3x4 (12 entry) matrix.
+ */
+static void __drm_ctm_3x4_to_dc_matrix(const struct drm_color_ctm_3x4 *ctm,
+  struct fixed31_32 *matrix)
+{
+   int i;
+
+   /* The format provided is S31.32, using signed-magnitude representation.
+* Our fixed31_32 is also S31.32, but is using 2's complement. We have
+* to convert from signed-magnitude to 2's complement.
+*/
+   for (i = 0; i < 12; i++) {
+   /* gamut_remap_matrix[i] = ctm[i - floor(i/4)] */
+   matrix[i] = dc_fixpt_from_s3132(ctm->matrix[i]);
+   }
+}
+
 /**
  * __set_legacy_tf - Calculates the legacy transfer function
  * @func: transfer function
@@ -1176,7 +1198,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct 
dm_crtc_state *crtc,
 {
struct amdgpu_device *adev = drm_to_adev(crtc->base.state->dev);
struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
-   struct drm_color_ctm *ctm = NULL;
+   struct drm_color_ctm_3x4 *ctm = NULL;
struct dc_color_caps *color_caps = NULL;
bool has_crtc_cm_degamma;
int ret;
@@ -1231,7 +1253,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct 
dm_crtc_state *crtc,
 
/* Setup CRTC CTM. */
if (dm_plane_state->ctm) {
-   ctm = (struct drm_color_ctm *)dm_plane_state->ctm->data;
+   ctm = (struct drm_color_ctm_3x4 *)dm_plane_state->ctm->data;
/*
 * DCN2 and older don't support both pre-blending and
 * post-blending gamut remap. For this HW family, if we have
@@ -1243,7 +1265,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct 
dm_crtc_state *crtc,
 * mapping CRTC CTM to MPC and keeping plane CTM setup at DPP,
 * as it's done by dcn30_program_gamut_remap().
 */
-   __drm_ctm_to_dc_matrix(ctm, 
dc_plane_state->gamut_remap_matrix.matrix);
+   __drm_ctm_3x4_to_dc_matrix(ctm, 
dc_plane_state->gamut_remap_matrix.matrix);
 
dc_plane_state->gamut_remap_matrix.enable_remap = true;
dc_plane_state->input_csc_color_matrix.enable_adjustment = 
false;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index d9537d9bf18c..a3935c56189b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -1549,7 +1549,7 @@ dm_atomic_plane_set_property(struct drm_plane *plane,
ret = drm_property_replace_blob_from_id(plane->dev,
_plane_state->ctm,
val,
-   sizeof(struct 
drm_color_ctm), -1,
+   sizeof(struct 
drm_color_ctm_3x4), -1,
);
dm_plane_state->base.color_mgmt_changed |= replaced;
return ret;
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index 46becedf5b2f..a811d24e8ed5 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -838,6 +838,14 @@ struct drm_color_ctm {
__u64 matrix[9];
 };
 
+struct drm_color_ctm_3x4 {
+   /*
+* Conversion matrix with 3x4 dimensions in S31.32 sign-magnitude
+* (not two's complement!) format.
+*/
+   __u64 matrix[12];
+};
+
 struct drm_color_lut {
/*
 * Values are mapped linearly to 0.0 - 1.0 range, with 0x0 == 0.0 and
-- 
2.40.1



[PATCH v4 31/32] drm/amd/display: add plane CTM support

2023-10-05 Thread Melissa Wen
Map the plane CTM driver-specific property to DC plane, instead of DC
stream. The remaining steps to program DPP block are already implemented
on DC shared-code.

v3:
- fix comment about plane and CRTC CTMs priorities (Harry)

Reviewed-by: Harry Wentland 
Signed-off-by: Melissa Wen 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  1 +
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 26 +++
 2 files changed, 27 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 5e64eda6ed11..7de67b5ab6e9 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -9998,6 +9998,7 @@ static bool should_reset_plane(struct drm_atomic_state 
*state,
if (dm_old_other_state->degamma_tf != 
dm_new_other_state->degamma_tf ||
dm_old_other_state->degamma_lut != 
dm_new_other_state->degamma_lut ||
dm_old_other_state->hdr_mult != 
dm_new_other_state->hdr_mult ||
+   dm_old_other_state->ctm != dm_new_other_state->ctm ||
dm_old_other_state->shaper_lut != 
dm_new_other_state->shaper_lut ||
dm_old_other_state->shaper_tf != 
dm_new_other_state->shaper_tf ||
dm_old_other_state->lut3d != dm_new_other_state->lut3d ||
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 41c5926ca068..bc9dd75e8881 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -1175,6 +1175,8 @@ int amdgpu_dm_update_plane_color_mgmt(struct 
dm_crtc_state *crtc,
  struct dc_plane_state *dc_plane_state)
 {
struct amdgpu_device *adev = drm_to_adev(crtc->base.state->dev);
+   struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
+   struct drm_color_ctm *ctm = NULL;
struct dc_color_caps *color_caps = NULL;
bool has_crtc_cm_degamma;
int ret;
@@ -1227,5 +1229,29 @@ int amdgpu_dm_update_plane_color_mgmt(struct 
dm_crtc_state *crtc,
return ret;
}
 
+   /* Setup CRTC CTM. */
+   if (dm_plane_state->ctm) {
+   ctm = (struct drm_color_ctm *)dm_plane_state->ctm->data;
+   /*
+* DCN2 and older don't support both pre-blending and
+* post-blending gamut remap. For this HW family, if we have
+* the plane and CRTC CTMs simultaneously, CRTC CTM takes
+* priority, and we discard plane CTM, as implemented in
+* dcn10_program_gamut_remap(). However, DCN3+ has DPP
+* (pre-blending) and MPC (post-blending) `gamut remap` blocks;
+* therefore, we can program plane and CRTC CTMs together by
+* mapping CRTC CTM to MPC and keeping plane CTM setup at DPP,
+* as it's done by dcn30_program_gamut_remap().
+*/
+   __drm_ctm_to_dc_matrix(ctm, 
dc_plane_state->gamut_remap_matrix.matrix);
+
+   dc_plane_state->gamut_remap_matrix.enable_remap = true;
+   dc_plane_state->input_csc_color_matrix.enable_adjustment = 
false;
+   } else {
+   /* Bypass CTM. */
+   dc_plane_state->gamut_remap_matrix.enable_remap = false;
+   dc_plane_state->input_csc_color_matrix.enable_adjustment = 
false;
+   }
+
return amdgpu_dm_plane_set_color_properties(plane_state, 
dc_plane_state);
 }
-- 
2.40.1



[PATCH v4 30/32] drm/amd/display: add plane CTM driver-specific property

2023-10-05 Thread Melissa Wen
Plane CTM for pre-blending color space conversion. Only enable
driver-specific plane CTM property on drivers that support both pre- and
post-blending gamut remap matrix, i.e., DCN3+ family. Otherwise it
conflits with DRM CRTC CTM property.

Reviewed-by: Harry Wentland 
Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h  |  2 ++
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  7 +++
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   |  7 +++
 .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 20 +++
 4 files changed, 36 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index 071cc10bfd90..1347022ce57d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -363,6 +363,8 @@ struct amdgpu_mode_info {
 * @plane_hdr_mult_property:
 */
struct drm_property *plane_hdr_mult_property;
+
+   struct drm_property *plane_ctm_property;
/**
 * @shaper_lut_property: Plane property to set pre-blending shaper LUT
 * that converts color content before 3D LUT. If
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 219efa7fe181..c9cd2e5f79ae 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -784,6 +784,13 @@ struct dm_plane_state {
 * TF is needed for any subsequent linear-to-non-linear transforms.
 */
__u64 hdr_mult;
+   /**
+* @ctm:
+*
+* Color transformation matrix. The blob (if not NULL) is a 
+* drm_color_ctm_3x4.
+*/
+   struct drm_property_blob *ctm;
/**
 * @shaper_lut: shaper lookup table blob. The blob (if not NULL) is an
 * array of  drm_color_lut.
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 251b5f14bd89..41c5926ca068 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -239,6 +239,13 @@ amdgpu_dm_create_color_properties(struct amdgpu_device 
*adev)
return -ENOMEM;
adev->mode_info.plane_hdr_mult_property = prop;
 
+   prop = drm_property_create(adev_to_drm(adev),
+  DRM_MODE_PROP_BLOB,
+  "AMD_PLANE_CTM", 0);
+   if (!prop)
+   return -ENOMEM;
+   adev->mode_info.plane_ctm_property = prop;
+
prop = drm_property_create(adev_to_drm(adev),
   DRM_MODE_PROP_BLOB,
   "AMD_PLANE_SHAPER_LUT", 0);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index f1070ca7076a..d9537d9bf18c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -1361,6 +1361,8 @@ dm_drm_plane_duplicate_state(struct drm_plane *plane)
 
if (dm_plane_state->degamma_lut)
drm_property_blob_get(dm_plane_state->degamma_lut);
+   if (dm_plane_state->ctm)
+   drm_property_blob_get(dm_plane_state->ctm);
if (dm_plane_state->shaper_lut)
drm_property_blob_get(dm_plane_state->shaper_lut);
if (dm_plane_state->lut3d)
@@ -1442,6 +1444,8 @@ static void dm_drm_plane_destroy_state(struct drm_plane 
*plane,
 
if (dm_plane_state->degamma_lut)
drm_property_blob_put(dm_plane_state->degamma_lut);
+   if (dm_plane_state->ctm)
+   drm_property_blob_put(dm_plane_state->ctm);
if (dm_plane_state->lut3d)
drm_property_blob_put(dm_plane_state->lut3d);
if (dm_plane_state->shaper_lut)
@@ -1479,6 +1483,11 @@ dm_atomic_plane_attach_color_mgmt_properties(struct 
amdgpu_display_manager *dm,
   dm->adev->mode_info.plane_hdr_mult_property,
   AMDGPU_HDR_MULT_DEFAULT);
 
+   /* Only enable plane CTM if both DPP and MPC gamut remap is available. 
*/
+   if (dm->dc->caps.color.mpc.gamut_remap)
+   drm_object_attach_property(>base,
+  
dm->adev->mode_info.plane_ctm_property, 0);
+
if (dpp_color_caps.hw_3d_lut) {
drm_object_attach_property(>base,
   mode_info.plane_shaper_lut_property, 
0);
@@ -1536,6 +1545,14 @@ dm_atomic_plane_set_property(struct drm_plane *plane,
dm_plane_state->hdr_mult = val;
dm_plane_state->base.color_mgmt_changed = 1;
}
+   } else if (propert

[PATCH v4 29/32] drm/amd/display: copy 3D LUT settings from crtc state to stream_update

2023-10-05 Thread Melissa Wen
From: Joshua Ashton 

When commiting planes, we copy color mgmt resources to the stream state.
Do the same for shaper and 3D LUTs.

Reviewed-by: Harry Wentland 
Signed-off-by: Joshua Ashton 
Co-developed-by: Melissa Wen 
Signed-off-by: Melissa Wen 
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 4b4181447df9..5e64eda6ed11 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -8501,6 +8501,10 @@ static void amdgpu_dm_commit_planes(struct 
drm_atomic_state *state,
_state->stream->csc_color_matrix;
bundle->stream_update.out_transfer_func =
acrtc_state->stream->out_transfer_func;
+   bundle->stream_update.lut3d_func =
+   (struct dc_3dlut *) 
acrtc_state->stream->lut3d_func;
+   bundle->stream_update.func_shaper =
+   (struct dc_transfer_func *) 
acrtc_state->stream->func_shaper;
}
 
acrtc_state->stream->abm_level = acrtc_state->abm_level;
-- 
2.40.1



[PATCH v4 28/32] drm/amd/display: allow newer DC hardware to use degamma ROM for PQ/HLG

2023-10-05 Thread Melissa Wen
From: Joshua Ashton 

Need to funnel the color caps through to these functions so it can check
that the hardware is capable.

v2:
- remove redundant color caps assignment on plane degamma map (Harry)
- pass color caps to degamma params

v3:
- remove unused color_caps parameter from set_color_properties (Harry)

Reviewed-by: Harry Wentland 
Signed-off-by: Joshua Ashton 
Signed-off-by: Melissa Wen 
---
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 29 ---
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 0909ed5639bf..251b5f14bd89 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -564,6 +564,7 @@ static int amdgpu_dm_set_atomic_regamma(struct 
dc_stream_state *stream,
 /**
  * __set_input_tf - calculates the input transfer function based on expected
  * input space.
+ * @caps: dc color capabilities
  * @func: transfer function
  * @lut: lookup table that defines the color space
  * @lut_size: size of respective lut.
@@ -571,7 +572,7 @@ static int amdgpu_dm_set_atomic_regamma(struct 
dc_stream_state *stream,
  * Returns:
  * 0 in case of success. -ENOMEM if fails.
  */
-static int __set_input_tf(struct dc_transfer_func *func,
+static int __set_input_tf(struct dc_color_caps *caps, struct dc_transfer_func 
*func,
  const struct drm_color_lut *lut, uint32_t lut_size)
 {
struct dc_gamma *gamma = NULL;
@@ -588,7 +589,7 @@ static int __set_input_tf(struct dc_transfer_func *func,
__drm_lut_to_dc_gamma(lut, gamma, false);
}
 
-   res = mod_color_calculate_degamma_params(NULL, func, gamma, gamma != 
NULL);
+   res = mod_color_calculate_degamma_params(caps, func, gamma, gamma != 
NULL);
 
if (gamma)
dc_gamma_release();
@@ -752,7 +753,7 @@ static int amdgpu_dm_atomic_blend_lut(const struct 
drm_color_lut *blend_lut,
func_blend->tf = tf;
func_blend->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
 
-   ret = __set_input_tf(func_blend, blend_lut, blend_size);
+   ret = __set_input_tf(NULL, func_blend, blend_lut, blend_size);
} else {
func_blend->type = TF_TYPE_BYPASS;
func_blend->tf = TRANSFER_FUNCTION_LINEAR;
@@ -968,7 +969,8 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state 
*crtc)
 
 static int
 map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc,
-struct dc_plane_state *dc_plane_state)
+struct dc_plane_state *dc_plane_state,
+struct dc_color_caps *caps)
 {
const struct drm_color_lut *degamma_lut;
enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB;
@@ -1023,7 +1025,7 @@ map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc,
dc_plane_state->in_transfer_func->tf =
TRANSFER_FUNCTION_LINEAR;
 
-   r = __set_input_tf(dc_plane_state->in_transfer_func,
+   r = __set_input_tf(caps, dc_plane_state->in_transfer_func,
   degamma_lut, degamma_size);
if (r)
return r;
@@ -1036,7 +1038,7 @@ map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc,
dc_plane_state->in_transfer_func->tf = tf;
 
if (tf != TRANSFER_FUNCTION_SRGB &&
-   !mod_color_calculate_degamma_params(NULL,
+   !mod_color_calculate_degamma_params(caps,

dc_plane_state->in_transfer_func,
NULL, false))
return -ENOMEM;
@@ -1047,7 +1049,8 @@ map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc,
 
 static int
 __set_dm_plane_degamma(struct drm_plane_state *plane_state,
-  struct dc_plane_state *dc_plane_state)
+  struct dc_plane_state *dc_plane_state,
+  struct dc_color_caps *color_caps)
 {
struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
const struct drm_color_lut *degamma_lut;
@@ -1078,7 +1081,7 @@ __set_dm_plane_degamma(struct drm_plane_state 
*plane_state,
dc_plane_state->in_transfer_func->type =
TF_TYPE_DISTRIBUTED_POINTS;
 
-   ret = __set_input_tf(dc_plane_state->in_transfer_func,
+   ret = __set_input_tf(color_caps, 
dc_plane_state->in_transfer_func,
 degamma_lut, degamma_size);
if (ret)
return ret;
@@ -1086,7 +1089,7 @@ __set_dm_plane_degamma(struct drm_plane_state 
*plane_state,
 

  1   2   3   4   5   >