Intel-XE Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Mario Limonciello (AMD)" <superm1@kernel.org>
Cc: dri-devel@lists.freedesktop.org, intel-gfx@lists.freedesktop.org,
	intel-xe@lists.freedesktop.org
Subject: Re: [PATCH v11 04/12] drm/amd: add luminance property support
Date: Tue, 03 Nov 2026 23:13:21 +0000	[thread overview]
Message-ID: <sashiko-outbox-196185@kernel.org> (raw)
In-Reply-To: <20261103-superm1-backlight-property-v11-4-00cce7b2ba22@kernel.org>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] drm/amd/display: stale brightness restored in amdgpu_dm_commit_streams()
- [Medium] drm/amd/display: race and PSR exit in amdgpu_dm_backlight_restore()
- [Medium] drm/amd/display: zero actual_brightness collision in amdgpu_dm_set_luminance()
--

commit 1f2beac3090b1487d1ed83a29307a7bc88af9241
Author: Mario Limonciello <mario.limonciello@amd.com>

drm/amd: add luminance property support

This commit exposes the DRM LUMINANCE connector property for internal panels
when CONFIG_DRM_LUMINANCE is enabled and applies connector luminance updates
through Display Core backlight helpers and atomic commit callbacks.

> 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 56fca4e22df8d..2a9ddd1dc6f70 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c

[ ... ]

> @@ -4802,12 +4799,8 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_commit *state,
>  	 * level. (the dm->brightness is the correct panel level)
>  	 * So we set the backlight level with dm->brightness value after set mode
>  	 */
> -	if (set_backlight_level) {
> -		for (i = 0; i < dm->num_of_edps; i++) {
> -			if (dm->backlight_dev[i])
> -				amdgpu_dm_backlight_set_level(dm, i, dm->brightness[i]);
> -		}
> -	}
> +	if (set_backlight_level)
> +		amdgpu_dm_backlight_restore(dm);
>  }
>  
>  STATIC_IFN_KUNIT void
> @@ -5413,6 +5406,9 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_commit *state)
>  	/* Update audio instances for each connector. */
>  	amdgpu_dm_commit_audio(dev, state);
>  
> +	/* Apply connector luminance after the display pipeline is enabled. */
> +	drm_atomic_helper_commit_luminance_enables(state);
> +
>  	/* restore the backlight level */
>  	for (i = 0; i < dm->num_of_edps; i++) {
>  		if (dm->backlight_dev[i] &&

[Severity: Medium]
When a connector is controlled via the LUMINANCE property, dm->brightness[] is
only updated when drm_atomic_helper_commit_luminance_enables() calls
amdgpu_dm_set_luminance() near the end of amdgpu_dm_atomic_commit_tail().

If userspace updates LUMINANCE while the connector is inactive
(!new_conn_state->crtc or !new_crtc_state->active), or updates LUMINANCE in
the same atomic commit as a modeset, dm->brightness[bl_idx] still holds the
previous level when amdgpu_dm_commit_streams() runs earlier in
amdgpu_dm_atomic_commit_tail():

amdgpu_dm_atomic_commit_tail()
  amdgpu_dm_commit_streams()
    amdgpu_dm_backlight_restore()
      amdgpu_dm_backlight_set_level(dm, i, dm->brightness[i])
  amdgpu_dm_mod_power_setup_streams()
  amdgpu_dm_commit_planes()
  ...
  drm_atomic_helper_commit_luminance_enables()
    amdgpu_dm_set_luminance()
      amdgpu_dm_backlight_set_level(dm, bl_idx, state->luminance)

Because drm_atomic_helper_update_legacy_modeset_state() has already set
aconnector->base.encoder and dc_commit_streams() has committed the stream,
amdgpu_dm_backlight_restore() programs the panel hardware,
dm->power_module->bl_state, and the ATOMBIOS scratch register with the stale
dm->brightness[i] value before planes are committed, and then
drm_atomic_helper_commit_luminance_enables() reprograms the hardware a second
time with state->luminance.

Furthermore, if a LUMINANCE change was committed while the connector was
inactive and a later modeset exits self-refresh
(old_crtc_state->self_refresh_active is true while old_conn_state->luminance ==
new_conn_state->luminance), drm_atomic_helper_commit_luminance_enables() skips
calling set_luminance, leaving the panel permanently at the stale
dm->brightness[i] level applied by amdgpu_dm_backlight_restore().

Should amdgpu_dm_commit_streams() avoid restoring stale dm->brightness[] for
luminance-controlled connectors, or should dm->brightness[] be synced from the
connector state before amdgpu_dm_backlight_restore() runs?

> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c
> index 0f664c658a127..f61e69bbdf69f 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c

[ ... ]

> @@ -675,6 +684,30 @@ void amdgpu_dm_setup_backlight_device(struct amdgpu_display_manager *dm,
>  
>  	amdgpu_dm_update_connector_ext_caps(aconnector);
>  
> +	/*
> +	 * The property must exist before the device is registered. If ACPI
> +	 * video should handle the backlight, leave it to
> +	 * amdgpu_dm_register_backlight_device() to register the fallback.
> +	 */
> +	if (IS_ENABLED(CONFIG_DRM_LUMINANCE) && acpi_video_backlight_use_native()) {
> +		caps = &dm->backlight_caps[bl_idx];
> +		amdgpu_dm_backlight_fill_props(caps, power_supply_is_system_supplied() > 0,
> +					       !(amdgpu_dc_debug_mask &
> +						 DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE),
> +					       &props);
> +		/* Start from the level the hardware is actually at */
> +		ret = amdgpu_dm_backlight_get_level(dm, bl_idx);
> +		if (ret >= 0 && ret <= props.max_brightness)
> +			props.brightness = ret;
> +		ret = drm_connector_attach_luminance_property(connector, 0,
> +							      props.max_brightness,
> +							      props.brightness);
> +		if (!drm_WARN_ON(adev_to_drm(dm->adev), ret)) {
> +			dm->brightness[bl_idx] = props.brightness;
> +			dm->luminance[bl_idx] = true;
> +		}
> +	}
> +
>  	/* Offer ABM property when user didn't turn off by module parameter.
>  	 * OLED panels are included to support CACP (Content Adaptive
>  	 * Contrast and Power) feature via set_abm_level.
> @@ -686,6 +719,45 @@ void amdgpu_dm_setup_backlight_device(struct amdgpu_display_manager *dm,
>  }
>  EXPORT_IF_KUNIT(amdgpu_dm_setup_backlight_device);
>  
> +void amdgpu_dm_set_luminance(const struct drm_connector_state *state)
> +{
> +	struct amdgpu_dm_connector *aconnector =
> +		to_amdgpu_dm_connector(state->connector);
> +	struct amdgpu_display_manager *dm =
> +		&drm_to_adev(state->connector->dev)->dm;
> +
> +	int bl_idx = aconnector->bl_idx;
> +
> +	if (bl_idx < 0)
> +		return;
> +
> +	/* Skip if already applied, e.g. by amdgpu_dm_backlight_restore(). */
> +	if (dm->brightness[bl_idx] == state->luminance &&
> +	    dm->actual_brightness[bl_idx] == state->luminance)
> +		return;
> +
> +	amdgpu_dm_backlight_set_level(dm, bl_idx, state->luminance);
> +}

[Severity: Medium]
Can amdgpu_dm_set_luminance() silently skip programming the hardware when
state->luminance is 0?

In amdgpu_dm_setup_backlight_device(), drm_connector_attach_luminance_property()
registers 0 as the minimum valid luminance level, and dm->actual_brightness[]
starts at 0 (unlike amdgpu_dm_register_backlight_device(), which seeds
dm->actual_brightness[bl_idx] from the hardware level). In addition,
amdgpu_dm_backlight_set_level() uses dm->actual_brightness[bl_idx] = 0 as the
sentinel indicating that brightness was not applied while the connector had no
encoder:

		/* if connector is off, save the brightness for next time it's on */
		if (!aconnector->base.encoder) {
			dm->brightness[bl_idx] = user_brightness;
			dm->actual_brightness[bl_idx] = 0;
			return;
		}

If dm->brightness[bl_idx] is 0 and dm->actual_brightness[bl_idx] is 0 (for
instance, after saving brightness 0 while the connector was disabled, or if a
prior amdgpu_dm_backlight_set_level(dm, bl_idx, 0) returned early or failed
with rc == false), then calling amdgpu_dm_set_luminance() with
state->luminance == 0 sees:

	if (dm->brightness[bl_idx] == state->luminance &&
	    dm->actual_brightness[bl_idx] == state->luminance)
		return;

and returns early without applying minimum brightness to the panel.

Also, in amdgpu_dm_atomic_commit_tail(), the fallback loop that retries
unapplied brightness levels only checks dm->backlight_dev[i]:

	/* restore the backlight level */
	for (i = 0; i < dm->num_of_edps; i++) {
		if (dm->backlight_dev[i] &&
		    (dm->actual_brightness[i] != dm->brightness[i]))
			amdgpu_dm_backlight_set_level(dm, i, dm->brightness[i]);
	}

Should dm->actual_brightness[] track whether a level has been applied without
colliding with valid luminance 0, and should the retry loop in
amdgpu_dm_atomic_commit_tail() also cover dm->luminance[i]?

> +
> +/**
> + * amdgpu_dm_backlight_restore - reprogram the cached backlight levels
> + * @dm: display manager
> + *
> + * Display Core may reset the panel brightness when committing streams, so
> + * reapply the cached level of every panel whose backlight is controlled by
> + * the driver, either through a backlight class device or through the
> + * connector LUMINANCE property.
> + */
> +void amdgpu_dm_backlight_restore(struct amdgpu_display_manager *dm)
> +{
> +	int i;
> +
> +	for (i = 0; i < dm->num_of_edps; i++) {
> +		if (dm->backlight_dev[i] || dm->luminance[i])
> +			amdgpu_dm_backlight_set_level(dm, i, dm->brightness[i]);
> +	}
> +}

[Severity: Medium]
Could calling amdgpu_dm_backlight_restore() from amdgpu_dm_commit_streams() on
every stream commit cause a race with concurrent luminance updates and trigger
unnecessary PSR/Replay/IPS exits on unaffected eDP panels?

First, when a non-blocking modeset commit runs on an external display CRTC,
do_aquire_global_lock() locks all modeset locks during atomic_check but does
not add unmodified CRTCs (such as an active eDP CRTC) to the atomic state.
Once drm_atomic_helper_swap_state() finishes and locks are dropped, a subsequent
fast atomic commit updating LUMINANCE on the eDP connector drops
dm->atomic_obj in amdgpu_dm_atomic_check() and runs amdgpu_dm_atomic_commit_tail()
concurrently:

CPU 0 (external CRTC modeset)           CPU 1 (eDP fast luminance commit)
amdgpu_dm_commit_streams()              drm_atomic_helper_commit_luminance_enables()
  amdgpu_dm_backlight_restore()           amdgpu_dm_set_luminance()
    reads old dm->brightness[0]             amdgpu_dm_backlight_set_level(new)
    amdgpu_dm_backlight_set_level(old)        dm->brightness[0] = new
      dm->brightness[0] = old                 dm->actual_brightness[0] = new
      overwrites hw & actual_brightness

Because nothing serializes dm->brightness[] and dm->actual_brightness[] across
these two commits, CPU 0 can overwrite the panel brightness back to the old
level after CPU 1 has programmed the new luminance, leaving hardware brightness
out of sync with connector->state->luminance.

Second, whenever an external monitor undergoes a modeset while the eDP panel is
idle in PSR, Replay, or IPS with unchanged luminance,
amdgpu_dm_commit_streams() sets set_backlight_level = true and calls
amdgpu_dm_backlight_restore(), which unconditionally calls
amdgpu_dm_backlight_set_level() on all eDP panels. That exits IPS and latches
psr_event_hw_programming and replay_event_hw_programming on the eDP stream,
which is not cleared because the eDP CRTC has no plane commit in the state to
run amdgpu_dm_enable_self_refresh().

Could amdgpu_dm_commit_streams() only restore backlight for eDP streams that
actually underwent a modeset in that commit, or let
drm_atomic_helper_commit_luminance_enables() handle luminance-controlled
connectors?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261103-superm1-backlight-property-v11-0-00cce7b2ba22@kernel.org?part=4

  reply	other threads:[~2026-11-03 23:13 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-03 22:42 [PATCH v11 00/12] Add support for a DRM backlight capability Mario Limonciello (AMD)
2026-11-03 22:42 ` [PATCH v11 01/12] drm: add connector LUMINANCE property Mario Limonciello (AMD)
2026-11-03 22:42 ` [PATCH v11 02/12] drm/amd/display: Pass up errors reading actual brightness Mario Limonciello (AMD)
2026-11-03 22:42 ` [PATCH v11 03/12] drm/amdgpu: Check bios_scratch_reg_offset in backlight level helper Mario Limonciello (AMD)
2026-11-03 22:42 ` [PATCH v11 04/12] drm/amd: add luminance property support Mario Limonciello (AMD)
2026-11-03 23:13   ` sashiko-bot [this message]
2026-11-03 22:42 ` [PATCH v11 05/12] drm/i915/display: " Mario Limonciello (AMD)
2026-11-03 22:42 ` [PATCH v11 06/12] drm/bridge: add connector luminance operations Mario Limonciello (AMD)
2026-11-03 22:42 ` [PATCH v11 07/12] drm/panel: add connector luminance forwarding Mario Limonciello (AMD)
2026-11-03 22:55   ` sashiko-bot
2026-11-03 22:42 ` [PATCH v11 08/12] drm/bridge_connector: add luminance support Mario Limonciello (AMD)
2026-11-03 22:42 ` [PATCH v11 09/12] drm/nouveau: add connector " Mario Limonciello (AMD)
2026-11-03 23:09   ` sashiko-bot
2026-11-03 22:42 ` [PATCH v11 10/12] drm/gud: " Mario Limonciello (AMD)
2026-11-03 22:59   ` sashiko-bot
2026-11-03 22:42 ` [PATCH v11 11/12] drm/bridge: add PS8622 " Mario Limonciello (AMD)
2026-11-03 23:02   ` sashiko-bot
2026-11-03 22:42 ` [PATCH v11 12/12] drm/solomon: add SSD130x " Mario Limonciello (AMD)
2026-11-04 16:18 ` ✓ CI.KUnit: success for Add support for a DRM backlight capability Patchwork
2026-11-04 16:34 ` ✗ CI.checksparse: warning " Patchwork
2026-11-04 16:52 ` ✓ Xe.CI.BAT: success " Patchwork

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-196185@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=intel-xe@lists.freedesktop.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=superm1@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox