Re: [PATCH v5 1/4] drm/i915: Keep track of pwm-related backlight hooks separately

2021-01-12 Thread Vasily Khoruzhick
On Thu, Jan 7, 2021 at 2:52 PM Lyude Paul  wrote:
>
> Currently, every different type of backlight hook that i915 supports is
> pretty straight forward - you have a backlight, probably through PWM
> (but maybe DPCD), with a single set of platform-specific hooks that are
> used for controlling it.
>
> HDR backlights, in particular VESA and Intel's HDR backlight
> implementations, can end up being more complicated. With Intel's
> proprietary interface, HDR backlight controls always run through the
> DPCD. When the backlight is in SDR backlight mode however, the driver
> may need to bypass the TCON and control the backlight directly through
> PWM.
>
> So, in order to support this we'll need to split our backlight callbacks
> into two groups: a set of high-level backlight control callbacks in
> intel_panel, and an additional set of pwm-specific backlight control
> callbacks. This also implies a functional changes for how these
> callbacks are used:
>
> * We now keep track of two separate backlight level ranges, one for the
>   high-level backlight, and one for the pwm backlight range
> * We also keep track of backlight enablement and PWM backlight
>   enablement separately
> * Since the currently set backlight level might not be the same as the
>   currently programmed PWM backlight level, we stop setting
>   panel->backlight.level with the currently programmed PWM backlight
>   level in panel->backlight.pwm_funcs->setup(). Instead, we rely
>   on the higher level backlight control functions to retrieve the
>   current PWM backlight level (in this case, intel_pwm_get_backlight()).
>   Note that there are still a few PWM backlight setup callbacks that
>   do actually need to retrieve the current PWM backlight level, although
>   we no longer save this value in panel->backlight.level like before.
>
> Additionally, we drop the call to lpt_get_backlight() in
> lpt_setup_backlight(), and avoid unconditionally writing the PWM value that
> we get from it and only write it back if we're in CPU mode, and switching
> to PCH mode. The reason for this is because in the original codepath for
> this, it was expected that the intel_panel_bl_funcs->setup() hook would be
> responsible for fetching the initial backlight level. On lpt systems, the
> only time we could ever be in PCH backlight mode is during the initial
> driver load - meaning that outside of the setup() hook, lpt_get_backlight()
> will always be the callback used for retrieving the current backlight
> level. After this patch we still need to fetch and write-back the PCH
> backlight value if we're switching from CPU mode to PCH, but because
> intel_pwm_setup_backlight() will retrieve the backlight level after setup()
> using the get() hook, which always ends up being lpt_get_backlight(). Thus
> - an additional call to lpt_get_backlight() in lpt_setup_backlight() is
> made redundant.
>
> v5:
> * Fix indenting warnings from checkpatch
> v4:
> * Fix commit message
> * Remove outdated comment in intel_panel.c
> * Rename pwm_(min|max) to pwm_level_(min|max)
> * Use intel_pwm_get_backlight() in intel_pwm_setup_backlight() instead of
>   indirection
> * Don't move intel_dp_aux_init_bcklight_funcs() call to bottom of
>   intel_panel_init_backlight_funcs() quite yet
> v3:
> * Reuse intel_panel_bl_funcs() for pwm_funcs
> * Explain why we drop lpt_get_backlight()
>
> Signed-off-by: Lyude Paul 
> Cc: thay...@noraisin.net
> Cc: Vasily Khoruzhick 

Whole series is:

Tested-by: Vasily Khoruzhick 

> ---
>  .../drm/i915/display/intel_display_types.h|   4 +
>  drivers/gpu/drm/i915/display/intel_panel.c| 333 ++
>  2 files changed, 187 insertions(+), 150 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h 
> b/drivers/gpu/drm/i915/display/intel_display_types.h
> index 1067bd073c95..ee5c2d50b81a 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> @@ -252,6 +252,9 @@ struct intel_panel {
> bool alternate_pwm_increment;   /* lpt+ */
>
> /* PWM chip */
> +   u32 pwm_level_min;
> +   u32 pwm_level_max;
> +   bool pwm_enabled;
> bool util_pin_active_low;   /* bxt+ */
> u8 controller;  /* bxt+ only */
> struct pwm_device *pwm;
> @@ -263,6 +266,7 @@ struct intel_panel {
> struct backlight_device *device;
>
> const struct intel_panel_bl_funcs *funcs;
> +   const struct intel_panel_bl_funcs *pwm_funcs;
> void (*power)(struct intel_connector *, bool enable);
> } backlight;
>  };
> diff --git a/drivers/gpu/drm/i915/display/intel_panel.c 
> b/drivers/gpu/drm/i915/display/intel_panel.c
> index 67f81ae995c4..8c99bf404a32 100644
> --- a/drivers/gpu/drm/i915/display/intel_panel.c
> +++ b/drivers/gpu/drm/i915/display/intel_panel.c
> @@ -511,25 +511,34 @@ static u32 

Re: [PATCH v5 1/4] drm/i915: Keep track of pwm-related backlight hooks separately

2021-01-11 Thread Jani Nikula
On Thu, 07 Jan 2021, Lyude Paul  wrote:
> Currently, every different type of backlight hook that i915 supports is
> pretty straight forward - you have a backlight, probably through PWM
> (but maybe DPCD), with a single set of platform-specific hooks that are
> used for controlling it.
>
> HDR backlights, in particular VESA and Intel's HDR backlight
> implementations, can end up being more complicated. With Intel's
> proprietary interface, HDR backlight controls always run through the
> DPCD. When the backlight is in SDR backlight mode however, the driver
> may need to bypass the TCON and control the backlight directly through
> PWM.
>
> So, in order to support this we'll need to split our backlight callbacks
> into two groups: a set of high-level backlight control callbacks in
> intel_panel, and an additional set of pwm-specific backlight control
> callbacks. This also implies a functional changes for how these
> callbacks are used:
>
> * We now keep track of two separate backlight level ranges, one for the
>   high-level backlight, and one for the pwm backlight range
> * We also keep track of backlight enablement and PWM backlight
>   enablement separately
> * Since the currently set backlight level might not be the same as the
>   currently programmed PWM backlight level, we stop setting
>   panel->backlight.level with the currently programmed PWM backlight
>   level in panel->backlight.pwm_funcs->setup(). Instead, we rely
>   on the higher level backlight control functions to retrieve the
>   current PWM backlight level (in this case, intel_pwm_get_backlight()).
>   Note that there are still a few PWM backlight setup callbacks that
>   do actually need to retrieve the current PWM backlight level, although
>   we no longer save this value in panel->backlight.level like before.
>
> Additionally, we drop the call to lpt_get_backlight() in
> lpt_setup_backlight(), and avoid unconditionally writing the PWM value that
> we get from it and only write it back if we're in CPU mode, and switching
> to PCH mode. The reason for this is because in the original codepath for
> this, it was expected that the intel_panel_bl_funcs->setup() hook would be
> responsible for fetching the initial backlight level. On lpt systems, the
> only time we could ever be in PCH backlight mode is during the initial
> driver load - meaning that outside of the setup() hook, lpt_get_backlight()
> will always be the callback used for retrieving the current backlight
> level. After this patch we still need to fetch and write-back the PCH
> backlight value if we're switching from CPU mode to PCH, but because
> intel_pwm_setup_backlight() will retrieve the backlight level after setup()
> using the get() hook, which always ends up being lpt_get_backlight(). Thus
> - an additional call to lpt_get_backlight() in lpt_setup_backlight() is
> made redundant.
>
> v5:
> * Fix indenting warnings from checkpatch
> v4:
> * Fix commit message
> * Remove outdated comment in intel_panel.c
> * Rename pwm_(min|max) to pwm_level_(min|max)
> * Use intel_pwm_get_backlight() in intel_pwm_setup_backlight() instead of
>   indirection
> * Don't move intel_dp_aux_init_bcklight_funcs() call to bottom of
>   intel_panel_init_backlight_funcs() quite yet
> v3:
> * Reuse intel_panel_bl_funcs() for pwm_funcs
> * Explain why we drop lpt_get_backlight()
>
> Signed-off-by: Lyude Paul 
> Cc: thay...@noraisin.net
> Cc: Vasily Khoruzhick 
> ---
>  .../drm/i915/display/intel_display_types.h|   4 +
>  drivers/gpu/drm/i915/display/intel_panel.c| 333 ++
>  2 files changed, 187 insertions(+), 150 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h 
> b/drivers/gpu/drm/i915/display/intel_display_types.h
> index 1067bd073c95..ee5c2d50b81a 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> @@ -252,6 +252,9 @@ struct intel_panel {
>   bool alternate_pwm_increment;   /* lpt+ */
>  
>   /* PWM chip */
> + u32 pwm_level_min;
> + u32 pwm_level_max;
> + bool pwm_enabled;
>   bool util_pin_active_low;   /* bxt+ */
>   u8 controller;  /* bxt+ only */
>   struct pwm_device *pwm;
> @@ -263,6 +266,7 @@ struct intel_panel {
>   struct backlight_device *device;
>  
>   const struct intel_panel_bl_funcs *funcs;
> + const struct intel_panel_bl_funcs *pwm_funcs;
>   void (*power)(struct intel_connector *, bool enable);
>   } backlight;
>  };
> diff --git a/drivers/gpu/drm/i915/display/intel_panel.c 
> b/drivers/gpu/drm/i915/display/intel_panel.c
> index 67f81ae995c4..8c99bf404a32 100644
> --- a/drivers/gpu/drm/i915/display/intel_panel.c
> +++ b/drivers/gpu/drm/i915/display/intel_panel.c
> @@ -511,25 +511,34 @@ static u32 scale_hw_to_user(struct intel_connector 
> *connector,
>0, user_max);
>  }
>  

Re: [PATCH v5 1/4] drm/i915: Keep track of pwm-related backlight hooks separately

2021-01-08 Thread Jani Nikula
On Thu, 07 Jan 2021, Lyude Paul  wrote:
> @@ -1628,37 +1633,32 @@ static int lpt_setup_backlight(struct intel_connector 
> *connector, enum pipe unus
>   panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
>  
>   pch_ctl2 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2);
> - panel->backlight.max = pch_ctl2 >> 16;
> + panel->backlight.pwm_level_max = pch_ctl2 >> 16;
>  
>   cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2);
>  
> - if (!panel->backlight.max)
> - panel->backlight.max = get_backlight_max_vbt(connector);
> + if (!panel->backlight.pwm_level_max)
> + panel->backlight.pwm_level_max = 
> get_backlight_max_vbt(connector);
>  
> - if (!panel->backlight.max)
> + if (!panel->backlight.pwm_level_max)
>   return -ENODEV;
>  
> - panel->backlight.min = get_backlight_min_vbt(connector);
> + panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
>  
> - panel->backlight.enabled = pch_ctl1 & BLM_PCH_PWM_ENABLE;
> + panel->backlight.pwm_enabled = pch_ctl1 & BLM_PCH_PWM_ENABLE;
>  
> - cpu_mode = panel->backlight.enabled && HAS_PCH_LPT(dev_priv) &&
> + cpu_mode = panel->backlight.pwm_enabled && HAS_PCH_LPT(dev_priv) &&
>  !(pch_ctl1 & BLM_PCH_OVERRIDE_ENABLE) &&
>  (cpu_ctl2 & BLM_PWM_ENABLE);
> - if (cpu_mode)
> - val = pch_get_backlight(connector);
> - else
> - val = lpt_get_backlight(connector);
> - val = intel_panel_compute_brightness(connector, val);
> - panel->backlight.level = clamp(val, panel->backlight.min,
> -panel->backlight.max);
>  
>   if (cpu_mode) {
> + val = intel_panel_sanitize_pwm_level(connector, 
> pch_get_backlight(connector));
> +

(This really is a PITA to review, not because of how you do it but
because of the hardware and the code itself. I'm just pointing out one
thing here, but I'm not finished yet.)

I think this sanitize call is wrong here. It should be called only when
converting to and from the hw register. Here, we read directly from one
hw register and write back to another hw register.

Now, looking at the history, I think it's been wrong all the way since
commit 5b1ec9ac7ab5 ("drm/i915/backlight: Fix backlight takeover on LPT,
v3."). Probably nobody noticed, because AFAIK inverted brightness
control has only ever been an issue on some gen4 platforms...

*facepalm*

BR,
Jani.

>   drm_dbg_kms(_priv->drm,
>   "CPU backlight register was enabled, switching to 
> PCH override\n");
>  
>   /* Write converted CPU PWM value to PCH override register */
> - lpt_set_backlight(connector->base.state, 
> panel->backlight.level);
> + lpt_set_backlight(connector->base.state, val);
>   intel_de_write(dev_priv, BLC_PWM_PCH_CTL1,
>  pch_ctl1 | BLM_PCH_OVERRIDE_ENABLE);
>  

-- 
Jani Nikula, Intel Open Source Graphics Center