drm/amd/display: Fix VABC Init and OLED Support
authorIswara Nagulendran <Iswara.Nagulendran@amd.com>
Tue, 16 Jun 2026 19:31:03 +0000 (15:31 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 15 Jul 2026 13:15:39 +0000 (09:15 -0400)
[Why]
TCONs supporting VESA AUX Backlight does not always
support VESA Smooth Brightness. Driver software
needs to implement smooth brightness by periodically
updating the brightness by small steps. Driver
implementation is completed and verified on LCD
panels but solution is missing for OLED panels.

[How]
Updated driver to include smooth brightness for
OLED panels using VESA Aux Backlight.
Revert original workaround for VABC on oled issue,
as it is no longer needed.
Add VABC backlight Initialization sequence from
driver side.
Add fix to remove conflict between FW and driver
backlight programming for future ASIC.
Enable VABC for all future asic revisions.

Reviewed-by: Anthony Koo <anthony.koo@amd.com>
Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: Iswara Nagulendran <Iswara.Nagulendran@amd.com>
Signed-off-by: George Zhang <george.zhang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c
drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
drivers/gpu/drm/amd/display/modules/power/power_abm.c

index e72e10c..b6f3c04 100644 (file)
@@ -719,6 +719,34 @@ static void dmub_abm_set_backlight(struct dc_context *dc,
        dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
 }
 
+static bool dmub_cacp_set_backlight(struct dc_context *dc,
+       struct set_backlight_level_params *backlight_level_params,
+       unsigned int panel_inst)
+{
+       union dmub_rb_cmd cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.cacp_set_backlight.header.type = DMUB_CMD__CACP;
+       cmd.cacp_set_backlight.header.sub_type = DMUB_CMD__CACP_SET_BACKLIGHT;
+       cmd.cacp_set_backlight.cacp_set_backlight_data.aux_inst = backlight_level_params->aux_inst;
+       cmd.cacp_set_backlight.cacp_set_backlight_data.frame_ramp = backlight_level_params->frame_ramp;
+       cmd.cacp_set_backlight.cacp_set_backlight_data.backlight_user_level =
+               backlight_level_params->backlight_pwm_u16_16;
+       cmd.cacp_set_backlight.cacp_set_backlight_data.backlight_control_type =
+               (enum dmub_backlight_control_type)backlight_level_params->control_type;
+       cmd.cacp_set_backlight.cacp_set_backlight_data.min_luminance = backlight_level_params->min_luminance;
+       cmd.cacp_set_backlight.cacp_set_backlight_data.max_luminance = backlight_level_params->max_luminance;
+       cmd.cacp_set_backlight.cacp_set_backlight_data.min_backlight_pwm = backlight_level_params->min_backlight_pwm;
+       cmd.cacp_set_backlight.cacp_set_backlight_data.max_backlight_pwm = backlight_level_params->max_backlight_pwm;
+       cmd.cacp_set_backlight.cacp_set_backlight_data.version = DMUB_CMD_CACP_CONTROL_VERSION_1;
+       cmd.cacp_set_backlight.cacp_set_backlight_data.panel_mask = (0x01 << panel_inst);
+       cmd.cacp_set_backlight.header.payload_bytes = sizeof(struct dmub_cmd_cacp_set_backlight_data);
+
+       dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
+
+       return true;
+}
+
 bool dcn31_set_backlight_level(struct pipe_ctx *pipe_ctx,
        struct set_backlight_level_params *backlight_level_params)
 {
@@ -746,8 +774,19 @@ bool dcn31_set_backlight_level(struct pipe_ctx *pipe_ctx,
                        panel_cntl->inst,
                        panel_cntl->pwrseq_inst);
 
-       if (backlight_level_params->control_type != BACKLIGHT_CONTROL_AMD_AUX)
+       if (link && link->panel_type == PANEL_TYPE_OLED) {
+               /* For OLED panel with AMD AUX, skip set backlight call */
+               if (backlight_level_params->control_type == BACKLIGHT_CONTROL_VESA_AUX)
+                       dmub_cacp_set_backlight(dc, backlight_level_params, panel_cntl->inst);
+       } else if (link && link->panel_type == PANEL_TYPE_MINILED) {
+               /* For MiniLED panel we need to check if CACP or ABM is being used */
+               if (link->panel_config.cacp.cacp_supported)
+                       dmub_cacp_set_backlight(dc, backlight_level_params, panel_cntl->inst);
+               else
+                       dmub_abm_set_backlight(dc, backlight_level_params, panel_cntl->inst);
+       } else {
                dmub_abm_set_backlight(dc, backlight_level_params, panel_cntl->inst);
+       }
 
        return true;
 }
index f415473..cc8e96f 100644 (file)
@@ -281,6 +281,8 @@ void dcn42_init_hw(struct dc *dc)
                dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr;
                dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver > 0;
                dc->caps.dmub_caps.fams_ver = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver;
+               dc->caps.dmub_caps.aux_backlight_support =
+                       dc->ctx->dmub_srv->dmub->feature_caps.abm_aux_backlight_support;
 
                /* sw and fw FAMS versions must match for support */
                dc->debug.fams2_config.bits.enable &=
index baf5769..16951a9 100644 (file)
@@ -161,9 +161,7 @@ bool edp_set_backlight_level_nits(struct dc_link *link,
        if (link->is_dds && !link->dpcd_caps.panel_luminance_control)
                return true;
 
-       // use internal backlight control if dmub capabilities are not present
-       if (link->backlight_control_type == BACKLIGHT_CONTROL_VESA_AUX &&
-               !link->dc->caps.dmub_caps.aux_backlight_support) {
+       if (link->backlight_control_type == BACKLIGHT_CONTROL_VESA_AUX) {
                uint8_t backlight_enable = 0;
                struct target_luminance_value *target_luminance = NULL;
 
@@ -273,10 +271,11 @@ bool edp_backlight_enable_aux(struct dc_link *link, bool enable)
 
        if (link->is_dds)
                return true;
-       if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_ENABLE,
-               &backlight_enable, 1) != DC_OK)
-               return false;
-
+       if (!link->dpcd_caps.panel_luminance_control) {
+               if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_ENABLE,
+                       &backlight_enable, 1) != DC_OK)
+                       return false;
+       }
        return true;
 }
 
index 5b972f0..b26ceab 100644 (file)
@@ -716,8 +716,9 @@ void mod_power_update_backlight_on_mode_change(
 {
     struct set_backlight_level_params backlight_level_params = { 0 };
 
-               if (link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1 ||
-                       link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1)
+               if ((link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1 ||
+                       link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1) &&
+                       link->backlight_control_type == BACKLIGHT_CONTROL_AMD_AUX)
                        dc_link_set_backlight_level_nits(link, core_power->bl_state[panel_inst].isHDR,
                                core_power->bl_state[panel_inst].backlight_millinit, 0);
 
@@ -746,6 +747,11 @@ static bool set_backlight_millinits_aux(struct core_power *core_power,
 
        link = dc_stream_get_link(stream);
 
+       // only use internal backlight control if dmub capabilities are not present
+       if (link->backlight_control_type == BACKLIGHT_CONTROL_VESA_AUX &&
+               link->dc->caps.dmub_caps.aux_backlight_support)
+               return true;
+
        return dc_link_set_backlight_level_nits(link, core_power->bl_state[inst].isHDR,
                        backlight_millinits, transition_time_millisec);
 }