--- /dev/null
+From 16dc8bc27c2aa3c93905d3e885e27f1e3535f09a Mon Sep 17 00:00:00 2001
+From: Mario Limonciello <mario.limonciello@amd.com>
+Date: Thu, 29 May 2025 09:46:32 -0500
+Subject: drm/amd/display: Export full brightness range to userspace
+
+From: Mario Limonciello <mario.limonciello@amd.com>
+
+commit 16dc8bc27c2aa3c93905d3e885e27f1e3535f09a upstream.
+
+[WHY]
+Userspace currently is offered a range from 0-0xFF but the PWM is
+programmed from 0-0xFFFF. This can be limiting to some software
+that wants to apply greater granularity.
+
+[HOW]
+Convert internally to firmware values only when mapping custom
+brightness curves because these are in 0-0xFF range. Advertise full
+PWM range to userspace.
+
+Cc: Mario Limonciello <mario.limonciello@amd.com>
+Cc: Alex Deucher <alexander.deucher@amd.com>
+Reviewed-by: Roman Li <roman.li@amd.com>
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Alex Hung <alex.hung@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit 8dbd72cb790058ce52279af38a43c2b302fdd3e5)
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 41 ++++++++++++++--------
+ 1 file changed, 27 insertions(+), 14 deletions(-)
+
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -4655,9 +4655,23 @@ static int get_brightness_range(const st
+ return 1;
+ }
+
++/* Rescale from [min..max] to [0..AMDGPU_MAX_BL_LEVEL] */
++static inline u32 scale_input_to_fw(int min, int max, u64 input)
++{
++ return DIV_ROUND_CLOSEST_ULL(input * AMDGPU_MAX_BL_LEVEL, max - min);
++}
++
++/* Rescale from [0..AMDGPU_MAX_BL_LEVEL] to [min..max] */
++static inline u32 scale_fw_to_input(int min, int max, u64 input)
++{
++ return min + DIV_ROUND_CLOSEST_ULL(input * (max - min), AMDGPU_MAX_BL_LEVEL);
++}
++
+ static void convert_custom_brightness(const struct amdgpu_dm_backlight_caps *caps,
+- uint32_t *brightness)
++ unsigned int min, unsigned int max,
++ uint32_t *user_brightness)
+ {
++ u32 brightness = scale_input_to_fw(min, max, *user_brightness);
+ u8 prev_signal = 0, prev_lum = 0;
+ int i = 0;
+
+@@ -4668,7 +4682,7 @@ static void convert_custom_brightness(co
+ return;
+
+ /* choose start to run less interpolation steps */
+- if (caps->luminance_data[caps->data_points/2].input_signal > *brightness)
++ if (caps->luminance_data[caps->data_points/2].input_signal > brightness)
+ i = caps->data_points/2;
+ do {
+ u8 signal = caps->luminance_data[i].input_signal;
+@@ -4679,17 +4693,18 @@ static void convert_custom_brightness(co
+ * brightness < signal: interpolate between previous and current luminance numerator
+ * brightness > signal: find next data point
+ */
+- if (*brightness > signal) {
++ if (brightness > signal) {
+ prev_signal = signal;
+ prev_lum = lum;
+ i++;
+ continue;
+ }
+- if (*brightness < signal)
++ if (brightness < signal)
+ lum = prev_lum + DIV_ROUND_CLOSEST((lum - prev_lum) *
+- (*brightness - prev_signal),
++ (brightness - prev_signal),
+ signal - prev_signal);
+- *brightness = DIV_ROUND_CLOSEST(lum * *brightness, 101);
++ *user_brightness = scale_fw_to_input(min, max,
++ DIV_ROUND_CLOSEST(lum * brightness, 101));
+ return;
+ } while (i < caps->data_points);
+ }
+@@ -4702,11 +4717,10 @@ static u32 convert_brightness_from_user(
+ if (!get_brightness_range(caps, &min, &max))
+ return brightness;
+
+- convert_custom_brightness(caps, &brightness);
++ convert_custom_brightness(caps, min, max, &brightness);
+
+- // Rescale 0..255 to min..max
+- return min + DIV_ROUND_CLOSEST((max - min) * brightness,
+- AMDGPU_MAX_BL_LEVEL);
++ // Rescale 0..max to min..max
++ return min + DIV_ROUND_CLOSEST_ULL((u64)(max - min) * brightness, max);
+ }
+
+ static u32 convert_brightness_to_user(const struct amdgpu_dm_backlight_caps *caps,
+@@ -4719,8 +4733,8 @@ static u32 convert_brightness_to_user(co
+
+ if (brightness < min)
+ return 0;
+- // Rescale min..max to 0..255
+- return DIV_ROUND_CLOSEST(AMDGPU_MAX_BL_LEVEL * (brightness - min),
++ // Rescale min..max to 0..max
++ return DIV_ROUND_CLOSEST_ULL((u64)max * (brightness - min),
+ max - min);
+ }
+
+@@ -4870,11 +4884,10 @@ amdgpu_dm_register_backlight_device(stru
+ drm_dbg(drm, "Backlight caps: min: %d, max: %d, ac %d, dc %d\n", min, max,
+ caps->ac_level, caps->dc_level);
+ } else
+- props.brightness = AMDGPU_MAX_BL_LEVEL;
++ props.brightness = props.max_brightness = AMDGPU_MAX_BL_LEVEL;
+
+ if (caps->data_points && !(amdgpu_dc_debug_mask & DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE))
+ drm_info(drm, "Using custom brightness curve\n");
+- props.max_brightness = AMDGPU_MAX_BL_LEVEL;
+ props.type = BACKLIGHT_RAW;
+
+ snprintf(bl_name, sizeof(bl_name), "amdgpu_bl%d",
--- /dev/null
+From 66abb996999de0d440a02583a6e70c2c24deab45 Mon Sep 17 00:00:00 2001
+From: Mario Limonciello <mario.limonciello@amd.com>
+Date: Mon, 23 Jun 2025 12:11:13 -0500
+Subject: drm/amd/display: Fix AMDGPU_MAX_BL_LEVEL value
+
+From: Mario Limonciello <mario.limonciello@amd.com>
+
+commit 66abb996999de0d440a02583a6e70c2c24deab45 upstream.
+
+[Why]
+commit 16dc8bc27c2a ("drm/amd/display: Export full brightness range to
+userspace") adjusted the brightness range to scale to larger values, but
+missed updating AMDGPU_MAX_BL_LEVEL which is needed to make sure that
+scaling works properly with custom brightness curves.
+
+[How]
+As the change for max brightness of 0xFFFF only applies to devices
+supporting DC, use existing DC define MAX_BACKLIGHT_LEVEL.
+
+Fixes: 16dc8bc27c2a ("drm/amd/display: Export full brightness range to userspace")
+Acked-by: Alex Deucher <alexander.deucher@amd.com>
+Link: https://lore.kernel.org/r/20250623171114.1156451-1-mario.limonciello@amd.com
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit 5b852044eb0d3e1f1c946d32e05fcb068e0a20a0)
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -4655,16 +4655,16 @@ static int get_brightness_range(const st
+ return 1;
+ }
+
+-/* Rescale from [min..max] to [0..AMDGPU_MAX_BL_LEVEL] */
++/* Rescale from [min..max] to [0..MAX_BACKLIGHT_LEVEL] */
+ static inline u32 scale_input_to_fw(int min, int max, u64 input)
+ {
+- return DIV_ROUND_CLOSEST_ULL(input * AMDGPU_MAX_BL_LEVEL, max - min);
++ return DIV_ROUND_CLOSEST_ULL(input * MAX_BACKLIGHT_LEVEL, max - min);
+ }
+
+-/* Rescale from [0..AMDGPU_MAX_BL_LEVEL] to [min..max] */
++/* Rescale from [0..MAX_BACKLIGHT_LEVEL] to [min..max] */
+ static inline u32 scale_fw_to_input(int min, int max, u64 input)
+ {
+- return min + DIV_ROUND_CLOSEST_ULL(input * (max - min), AMDGPU_MAX_BL_LEVEL);
++ return min + DIV_ROUND_CLOSEST_ULL(input * (max - min), MAX_BACKLIGHT_LEVEL);
+ }
+
+ static void convert_custom_brightness(const struct amdgpu_dm_backlight_caps *caps,
+@@ -4884,7 +4884,7 @@ amdgpu_dm_register_backlight_device(stru
+ drm_dbg(drm, "Backlight caps: min: %d, max: %d, ac %d, dc %d\n", min, max,
+ caps->ac_level, caps->dc_level);
+ } else
+- props.brightness = props.max_brightness = AMDGPU_MAX_BL_LEVEL;
++ props.brightness = props.max_brightness = MAX_BACKLIGHT_LEVEL;
+
+ if (caps->data_points && !(amdgpu_dc_debug_mask & DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE))
+ drm_info(drm, "Using custom brightness curve\n");
--- /dev/null
+From ffcaed1d7ecef31198000dfbbea791f30f7ca437 Mon Sep 17 00:00:00 2001
+From: Mario Limonciello <mario.limonciello@amd.com>
+Date: Thu, 29 May 2025 11:33:44 -0500
+Subject: drm/amd/display: Only read ACPI backlight caps once
+
+From: Mario Limonciello <mario.limonciello@amd.com>
+
+commit ffcaed1d7ecef31198000dfbbea791f30f7ca437 upstream.
+
+[WHY]
+Backlight caps are read already in amdgpu_dm_update_backlight_caps().
+They may be updated by update_connector_ext_caps(). Reading again when
+registering backlight device may cause wrong values to be used.
+
+[HOW]
+Use backlight caps already registered to the dm.
+
+Cc: Mario Limonciello <mario.limonciello@amd.com>
+Cc: Alex Deucher <alexander.deucher@amd.com>
+Reviewed-by: Roman Li <roman.li@amd.com>
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Alex Hung <alex.hung@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit 148144f6d2f14b02eaaa39b86bbe023cbff350bd)
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -4832,7 +4832,7 @@ amdgpu_dm_register_backlight_device(stru
+ struct drm_device *drm = aconnector->base.dev;
+ struct amdgpu_display_manager *dm = &drm_to_adev(drm)->dm;
+ struct backlight_properties props = { 0 };
+- struct amdgpu_dm_backlight_caps caps = { 0 };
++ struct amdgpu_dm_backlight_caps *caps;
+ char bl_name[16];
+ int min, max;
+
+@@ -4846,20 +4846,20 @@ amdgpu_dm_register_backlight_device(stru
+ return;
+ }
+
+- amdgpu_acpi_get_backlight_caps(&caps);
+- if (caps.caps_valid && get_brightness_range(&caps, &min, &max)) {
++ caps = &dm->backlight_caps[aconnector->bl_idx];
++ if (get_brightness_range(caps, &min, &max)) {
+ if (power_supply_is_system_supplied() > 0)
+- props.brightness = (max - min) * DIV_ROUND_CLOSEST(caps.ac_level, 100);
++ props.brightness = (max - min) * DIV_ROUND_CLOSEST(caps->ac_level, 100);
+ else
+- props.brightness = (max - min) * DIV_ROUND_CLOSEST(caps.dc_level, 100);
++ props.brightness = (max - min) * DIV_ROUND_CLOSEST(caps->dc_level, 100);
+ /* min is zero, so max needs to be adjusted */
+ props.max_brightness = max - min;
+ drm_dbg(drm, "Backlight caps: min: %d, max: %d, ac %d, dc %d\n", min, max,
+- caps.ac_level, caps.dc_level);
++ caps->ac_level, caps->dc_level);
+ } else
+ props.brightness = AMDGPU_MAX_BL_LEVEL;
+
+- if (caps.data_points && !(amdgpu_dc_debug_mask & DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE))
++ if (caps->data_points && !(amdgpu_dc_debug_mask & DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE))
+ drm_info(drm, "Using custom brightness curve\n");
+ props.max_brightness = AMDGPU_MAX_BL_LEVEL;
+ props.type = BACKLIGHT_RAW;
--- /dev/null
+From 03b979e1025fba1d47cae005022fcdbba140f043 Mon Sep 17 00:00:00 2001
+From: Mario Limonciello <mario.limonciello@amd.com>
+Date: Mon, 24 Mar 2025 12:57:25 -0500
+Subject: drm/amd/display: Optimize custom brightness curve
+
+From: Mario Limonciello <mario.limonciello@amd.com>
+
+commit 03b979e1025fba1d47cae005022fcdbba140f043 upstream.
+
+[Why]
+When BIOS includes a lot of custom brightness data points, walking
+the entire list can be time consuming. This is most noticed when
+dragging a power slider. The "higher" values are "slower" to drag
+around.
+
+[How]
+Move custom brightness calculation loop into a static function. Before
+starting the loop check the "half way" data point to see how it compares
+to the input. If greater than the half way data point use that as the
+starting point instead.
+
+Reviewed-by: Alex Hung <alex.hung@amd.com>
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Roman Li <roman.li@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 53 +++++++++++++---------
+ 1 file changed, 33 insertions(+), 20 deletions(-)
+
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -4655,41 +4655,54 @@ static int get_brightness_range(const st
+ return 1;
+ }
+
+-static u32 convert_brightness_from_user(const struct amdgpu_dm_backlight_caps *caps,
+- uint32_t brightness)
++static void convert_custom_brightness(const struct amdgpu_dm_backlight_caps *caps,
++ uint32_t *brightness)
+ {
+- unsigned int min, max;
+ u8 prev_signal = 0, prev_lum = 0;
++ int i = 0;
+
+- if (!get_brightness_range(caps, &min, &max))
+- return brightness;
+-
+- for (int i = 0; i < caps->data_points; i++) {
+- u8 signal, lum;
++ if (amdgpu_dc_debug_mask & DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE)
++ return;
+
+- if (amdgpu_dc_debug_mask & DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE)
+- break;
++ if (!caps->data_points)
++ return;
+
+- signal = caps->luminance_data[i].input_signal;
+- lum = caps->luminance_data[i].luminance;
++ /* choose start to run less interpolation steps */
++ if (caps->luminance_data[caps->data_points/2].input_signal > *brightness)
++ i = caps->data_points/2;
++ do {
++ u8 signal = caps->luminance_data[i].input_signal;
++ u8 lum = caps->luminance_data[i].luminance;
+
+ /*
+ * brightness == signal: luminance is percent numerator
+ * brightness < signal: interpolate between previous and current luminance numerator
+ * brightness > signal: find next data point
+ */
+- if (brightness < signal)
+- lum = prev_lum + DIV_ROUND_CLOSEST((lum - prev_lum) *
+- (brightness - prev_signal),
+- signal - prev_signal);
+- else if (brightness > signal) {
++ if (*brightness > signal) {
+ prev_signal = signal;
+ prev_lum = lum;
++ i++;
+ continue;
+ }
+- brightness = DIV_ROUND_CLOSEST(lum * brightness, 101);
+- break;
+- }
++ if (*brightness < signal)
++ lum = prev_lum + DIV_ROUND_CLOSEST((lum - prev_lum) *
++ (*brightness - prev_signal),
++ signal - prev_signal);
++ *brightness = DIV_ROUND_CLOSEST(lum * *brightness, 101);
++ return;
++ } while (i < caps->data_points);
++}
++
++static u32 convert_brightness_from_user(const struct amdgpu_dm_backlight_caps *caps,
++ uint32_t brightness)
++{
++ unsigned int min, max;
++
++ if (!get_brightness_range(caps, &min, &max))
++ return brightness;
++
++ convert_custom_brightness(caps, &brightness);
+
+ // Rescale 0..255 to min..max
+ return min + DIV_ROUND_CLOSEST((max - min) * brightness,
riscv-uaccess-only-restore-the-csr_status-sum-bit.patch
drm-amd-display-add-debugging-message-for-brightness-caps.patch
drm-amd-display-fix-default-dc-and-ac-levels.patch
+drm-amd-display-only-read-acpi-backlight-caps-once.patch
+drm-amd-display-optimize-custom-brightness-curve.patch
+drm-amd-display-export-full-brightness-range-to-userspace.patch
+drm-amd-display-fix-amdgpu_max_bl_level-value.patch