From: Chenyu Chen <[email protected]>

[Why]
Enable OLED panels to save more power on the Linux platform by
enabling CACP support on Linux.

[How]
Update abm_feature_support() to return ABM_CACP_SUPPORT for OLED
panels. Enable ABM property for all eDP panels including OLED to
support CACP via set_abm_level.

Reviewed-by: Sun peng (Leo) Li <[email protected]>
Signed-off-by: Chenyu Chen <[email protected]>
Signed-off-by: George Zhang <[email protected]>
---
 .../display/amdgpu_dm/amdgpu_dm_backlight.c   |  23 +-
 .../display/amdgpu_dm/amdgpu_dm_connector.c   |  53 ++++-
 drivers/gpu/drm/amd/display/dc/dc.h           |   1 +
 drivers/gpu/drm/amd/display/dc/dc_types.h     |   8 +
 drivers/gpu/drm/amd/display/dc/dce/Makefile   |   4 +-
 drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c |  73 +++++-
 .../drm/amd/display/dc/dce/dmub_abm_cacp.c    | 213 ++++++++++++++++++
 .../drm/amd/display/dc/dce/dmub_abm_cacp.h    |  20 ++
 .../amd/display/dc/hwss/dcn21/dcn21_hwseq.c   |  40 +++-
 .../amd/display/dc/hwss/dcn21/dcn21_hwseq.h   |   2 +
 .../amd/display/dc/hwss/dcn31/dcn31_hwseq.c   |   8 +
 drivers/gpu/drm/amd/display/dc/inc/hw/abm.h   |   3 +
 .../drm/amd/display/modules/inc/mod_power.h   |  11 +
 .../drm/amd/display/modules/power/power_abm.c | 126 +++++++++++
 .../amd/display/modules/power/power_helpers.h |  10 +
 15 files changed, 566 insertions(+), 29 deletions(-)
 create mode 100644 drivers/gpu/drm/amd/display/dc/dce/dmub_abm_cacp.c
 create mode 100644 drivers/gpu/drm/amd/display/dc/dce/dmub_abm_cacp.h

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 33f4be403a65..11d54897a894 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
@@ -559,7 +559,6 @@ EXPORT_IF_KUNIT(amdgpu_dm_update_connector_ext_caps);
 void amdgpu_dm_setup_backlight_device(struct amdgpu_display_manager *dm,
                            struct amdgpu_dm_connector *aconnector)
 {
-       struct amdgpu_dm_backlight_caps *caps;
        struct dc_link *link = aconnector->dc_link;
        int bl_idx = dm->num_of_edps;

@@ -579,10 +578,12 @@ void amdgpu_dm_setup_backlight_device(struct 
amdgpu_display_manager *dm,
        dm->num_of_edps++;

        amdgpu_dm_update_connector_ext_caps(aconnector);
-       caps = &dm->backlight_caps[aconnector->bl_idx];

-       /* Only offer ABM property when non-OLED and user didn't turn off by 
module parameter */
-       if (caps->ext_caps && !caps->ext_caps->bits.oled && amdgpu_dm_abm_level 
< 0)
+       /* 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.
+        */
+       if (amdgpu_dm_abm_level < 0)
                drm_object_attach_property(&aconnector->base.base,
                                           
dm->adev->mode_info.abm_level_property,
                                           ABM_SYSFS_CONTROL);
@@ -666,22 +667,16 @@ const struct attribute_group amdgpu_group = {
 bool
 amdgpu_dm_should_create_sysfs(struct amdgpu_dm_connector *amdgpu_dm_connector)
 {
+       struct dc_link *link = amdgpu_dm_connector->dc_link;
+
        if (amdgpu_dm_abm_level >= 0)
                return false;

        if (amdgpu_dm_connector->base.connector_type != DRM_MODE_CONNECTOR_eDP)
                return false;

-       /* check for OLED panels */
-       if (amdgpu_dm_connector->bl_idx >= 0) {
-               struct drm_device *drm = amdgpu_dm_connector->base.dev;
-               struct amdgpu_display_manager *dm = &drm_to_adev(drm)->dm;
-               struct amdgpu_dm_backlight_caps *caps;
-
-               caps = &dm->backlight_caps[amdgpu_dm_connector->bl_idx];
-               if (caps->aux_support)
-                       return false;
-       }
+       if (link->panel_type != PANEL_TYPE_LCD && 
!link->panel_config.cacp.cacp_supported)
+               return false;

        return true;
 }
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index 785333d9ed3b..2d10ae5e7616 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -392,32 +392,31 @@ amdgpu_dm_find_first_crtc_matching_connector(struct 
drm_atomic_state *state,
        return NULL;
 }

-static void dm_set_panel_type(struct amdgpu_dm_connector *aconnector)
+static void amdgpu_dm_set_panel_type(struct amdgpu_dm_connector *aconnector)
 {
        struct drm_connector *connector = &aconnector->base;
        struct drm_display_info *display_info = &connector->display_info;
        struct dc_link *link = aconnector->dc_link;
        struct amdgpu_device *adev;
+       enum dc_panel_type panel_type = PANEL_TYPE_NONE;

        adev = drm_to_adev(connector->dev);

-       link->panel_type = PANEL_TYPE_NONE;
-
        switch (display_info->amd_vsdb.panel_type) {
        case AMD_VSDB_PANEL_TYPE_OLED:
-               link->panel_type = PANEL_TYPE_OLED;
+               panel_type = PANEL_TYPE_OLED;
                break;
        case AMD_VSDB_PANEL_TYPE_MINILED:
-               link->panel_type = PANEL_TYPE_MINILED;
+               panel_type = PANEL_TYPE_MINILED;
                break;
        }

        /* If VSDB didn't determine panel type, check DPCD ext caps */
-       if (link->panel_type == PANEL_TYPE_NONE) {
+       if (panel_type == PANEL_TYPE_NONE) {
                if (link->dpcd_sink_ext_caps.bits.miniled == 1)
-                       link->panel_type = PANEL_TYPE_MINILED;
+                       panel_type = PANEL_TYPE_MINILED;
                if (link->dpcd_sink_ext_caps.bits.oled == 1)
-                       link->panel_type = PANEL_TYPE_OLED;
+                       panel_type = PANEL_TYPE_OLED;
        }

        /* If VSDB and DPCD didn't determine panel type, check DID */
@@ -428,7 +427,7 @@ static void dm_set_panel_type(struct amdgpu_dm_connector 
*aconnector)
                        link->panel_type = PANEL_TYPE_OLED;
        }

-       if (link->panel_type == PANEL_TYPE_NONE) {
+       if (panel_type == PANEL_TYPE_NONE) {
                struct drm_amd_vsdb_info *vsdb = &display_info->amd_vsdb;
                u32 lum1_max = vsdb->luminance_range1.max_luminance;
                u32 lum2_max = vsdb->luminance_range2.max_luminance;
@@ -437,9 +436,14 @@ static void dm_set_panel_type(struct amdgpu_dm_connector 
*aconnector)
                    link->local_sink->edid_caps.manufacturer_id ==
                    DDC_MANUFACTURERNAME_SAMSUNG &&
                    lum1_max >= ((lum2_max * 3) / 2))
-                       link->panel_type = PANEL_TYPE_MINILED;
+                       panel_type = PANEL_TYPE_MINILED;
        }

+       if (panel_type != PANEL_TYPE_NONE)
+               link->panel_type = panel_type;
+       else
+               link->panel_type = PANEL_TYPE_LCD;
+
        if (link->panel_type == PANEL_TYPE_OLED)
                drm_object_property_set_value(&connector->base,
                    adev_to_drm(adev)->mode_config.panel_type_property,
@@ -456,6 +460,32 @@ static void dm_set_panel_type(struct amdgpu_dm_connector 
*aconnector)
        drm_dbg_kms(aconnector->base.dev, "Panel type: %d\n", link->panel_type);
 }

+static void amdgpu_dm_update_cacp_caps(struct amdgpu_dm_connector *aconnector)
+{
+       struct amdgpu_device *adev = drm_to_adev(aconnector->base.dev);
+       struct dc_link *link = aconnector->dc_link;
+
+       link->panel_config.cacp.cacp_supported = true;
+
+       if (amdgpu_ip_version(adev, DCE_HWIP, 0) < IP_VERSION(3, 1, 4) ||
+           amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(3, 1, 6)) {
+               link->panel_config.cacp.cacp_supported = false;
+               return;
+       }
+
+       if (link->connector_signal != SIGNAL_TYPE_EDP &&
+           link->connector_signal != SIGNAL_TYPE_LVDS) {
+               link->panel_config.cacp.cacp_supported = false;
+               return;
+       }
+
+       if (link->panel_type == PANEL_TYPE_LCD)
+               link->panel_config.cacp.cacp_supported = false;
+
+       drm_dbg_kms(aconnector->base.dev, "cacp_supported: %d\n",
+                   link->panel_config.cacp.cacp_supported);
+}
+
 DEFINE_FREE(sink_release, struct dc_sink *, if (_T) dc_sink_release(_T))

 void amdgpu_dm_update_connector_after_detect(
@@ -581,7 +611,8 @@ void amdgpu_dm_update_connector_after_detect(

                amdgpu_dm_update_freesync_caps(connector, aconnector->drm_edid, 
true);
                amdgpu_dm_update_connector_ext_caps(aconnector);
-               dm_set_panel_type(aconnector);
+               amdgpu_dm_set_panel_type(aconnector);
+               amdgpu_dm_update_cacp_caps(aconnector);

                if (aconnector->hdmi_comp_auto) {
                        if (sink->sink_signal != SIGNAL_TYPE_HDMI_FRL)
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h 
b/drivers/gpu/drm/amd/display/dc/dc.h
index 13c1f7cd9d7d..2b59a0e9ca38 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -632,6 +632,7 @@ enum visual_confirm {
        VISUAL_CONFIRM_SMARTMUX_DGPU = 10,
        VISUAL_CONFIRM_REPLAY = 12,
        VISUAL_CONFIRM_SUBVP = 14,
+       VISUAL_CONFIRM_ABM = 15,
        VISUAL_CONFIRM_MCLK_SWITCH = 16,
        VISUAL_CONFIRM_FAMS2 = 19,
        VISUAL_CONFIRM_HW_CURSOR = 20,
diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h 
b/drivers/gpu/drm/amd/display/dc/dc_types.h
index 90dd1ae7e953..5ba7a2fffcf0 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_types.h
@@ -1347,6 +1347,14 @@ struct dc_panel_config {
        struct ilr {
                bool optimize_edp_link_rate; /* eDP ILR */
        } ilr;
+       /* CACP*/
+       struct cacp {
+               unsigned int cacp_supported;
+               unsigned int cacp_control_mode;
+               unsigned int strscl_valid;
+               unsigned int strscl_sdr[4];
+               unsigned int strscl_hdr[4];
+       } cacp;
        /* Adaptive VariBright*/
        struct adaptive_vb {
                bool disable_adaptive_vb;
diff --git a/drivers/gpu/drm/amd/display/dc/dce/Makefile 
b/drivers/gpu/drm/amd/display/dc/dce/Makefile
index 986e0e7abbc2..72bf70d89b74 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dce/Makefile
@@ -23,14 +23,14 @@
 # Makefile for common 'dce' logic
 # HW object file under this folder follow similar pattern for HW programming
 #   - register offset and/or shift + mask stored in the dec_hw struct
-#   - register programming through common macros that look up register
+#   - register programming through common macros that look up register
 #     offset/shift/mask stored in dce_hw struct

 DCE = dce_audio.o dce_stream_encoder.o dce_link_encoder.o \
 dce_mem_input.o dce_clock_source.o dce_scl_filters.o dce_transform.o \
 dce_opp.o dce_dmcu.o dce_abm.o dce_ipp.o dce_aux.o \
 dce_i2c.o dce_i2c_hw.o dce_i2c_sw.o dmub_psr.o dmub_abm.o dmub_abm_lcd.o 
dce_panel_cntl.o \
-dmub_hw_lock_mgr.o dmub_outbox.o dmub_replay.o
+dmub_hw_lock_mgr.o dmub_outbox.o dmub_replay.o dmub_abm_cacp.o

 AMD_DAL_DCE = $(addprefix $(AMDDALPATH)/dc/dce/,$(DCE))

diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c 
b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c
index c8077905ff9e..99a2c944ddad 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c
@@ -25,6 +25,7 @@

 #include "dmub_abm.h"
 #include "dmub_abm_lcd.h"
+#include "dmub_abm_cacp.h"
 #include "dc.h"
 #include "core_types.h"
 #include "dmub_cmd.h"
@@ -36,6 +37,7 @@

 #define ABM_FEATURE_NO_SUPPORT 0
 #define ABM_LCD_SUPPORT                        1
+#define ABM_CACP_SUPPORT               2

 static unsigned int abm_feature_support(struct abm *abm, unsigned int 
panel_inst)
 {
@@ -52,15 +54,48 @@ static unsigned int abm_feature_support(struct abm *abm, 
unsigned int panel_inst
        }

        if (i < edp_num) {
-               ret = ABM_LCD_SUPPORT;
+               if (edp_links[panel_inst]->panel_config.cacp.cacp_supported)
+                       ret = ABM_CACP_SUPPORT;
+               else if ((edp_links[panel_inst]->panel_type == PANEL_TYPE_LCD) 
||
+                               (edp_links[panel_inst]->panel_type == 
PANEL_TYPE_MINILED))
+                       ret = ABM_LCD_SUPPORT;
        }

        return ret;
 }

+static enum dc_panel_type abm_get_paneltype(struct abm *abm, unsigned int 
panel_inst)
+{
+       struct dc_context *dc = abm->ctx;
+       struct dc_link *edp_links[MAX_NUM_EDP];
+       unsigned int i, edp_num;
+       enum dc_panel_type ret = PANEL_TYPE_NONE;
+
+       dc_get_edp_links(dc->dc, edp_links, &edp_num);
+
+       for (i = 0; i < edp_num; i++) {
+               if (edp_links[i]->link_status.link_active
+                       && panel_inst == i)
+                       break;
+       }
+
+       if (i < edp_num)
+               ret = edp_links[panel_inst]->panel_type;
+
+       return ret;
+}
+
 static void dmub_abm_init_ex(struct abm *abm, uint32_t backlight, uint32_t 
user_level)
 {
+       unsigned int i = 0;
+       uint8_t panel_mask = 0;
+
        dmub_abm_init(abm, backlight, user_level);
+       for (i = 0; i < MAX_NUM_EDP; i++)
+               panel_mask |= (0x01 << i);
+
+       if (panel_mask)
+               dmub_cacp_enable_fractional_pwm(abm, panel_mask);
 }

 static unsigned int dmub_abm_get_current_backlight_ex(struct abm *abm)
@@ -82,17 +117,23 @@ static bool dmub_abm_set_level_ex(struct abm *abm, 
uint32_t level)
        bool ret = false;
        unsigned int feature_support, i;
        uint8_t panel_mask0 = 0;
+       uint8_t panel_mask1 = 0;

        for (i = 0; i < MAX_NUM_EDP; i++) {
                feature_support = abm_feature_support(abm, i);

                if (feature_support == ABM_LCD_SUPPORT)
                        panel_mask0 |= (0x01 << i);
+               else if (feature_support == ABM_CACP_SUPPORT)
+                       panel_mask1 |= (0x01 << i);
        }

        if (panel_mask0)
                ret = dmub_abm_set_level(abm, level, panel_mask0);

+       if (panel_mask1)
+               ret = dmub_cacp_set_level(abm, level, panel_mask1);
+
        return ret;
 }

@@ -107,6 +148,8 @@ static bool dmub_abm_init_config_ex(struct abm *abm,

        if (feature_support == ABM_LCD_SUPPORT)
                dmub_abm_init_config(abm, src, bytes, inst);
+       else if (feature_support == ABM_CACP_SUPPORT)
+               dmub_cacp_init(abm, src, bytes, inst);

        return true;
 }
@@ -120,6 +163,8 @@ static bool dmub_abm_set_pause_ex(struct abm *abm, bool 
pause, unsigned int pane

        if (feature_support == ABM_LCD_SUPPORT)
                ret = dmub_abm_set_pause(abm, pause, panel_inst, stream_inst);
+       else if (feature_support == ABM_CACP_SUPPORT)
+               ret = dmub_cacp_set_pause(abm, pause, panel_inst, stream_inst);

        return ret;
 }
@@ -163,6 +208,25 @@ static bool dmub_abm_set_pipe_ex(struct abm *abm,

        if (feature_support == ABM_LCD_SUPPORT)
                ret = dmub_abm_set_pipe(abm, otg_inst, option, panel_inst, 
pwrseq_inst);
+       else if (feature_support == ABM_CACP_SUPPORT)
+               ret = dmub_cacp_set_pipe(abm, otg_inst, option, panel_inst, 
pwrseq_inst);
+
+       return ret;
+}
+
+static bool dmub_abm_set_event_ex(struct abm *abm, unsigned int full_screen, 
unsigned int trans_info,
+               unsigned int hdr_mode, unsigned int scaling_enable, unsigned 
int scaling_strength_map,
+               unsigned int panel_inst)
+{
+       bool ret = false;
+       unsigned int feature_support;
+
+       feature_support = abm_feature_support(abm, panel_inst);
+
+       if (feature_support == ABM_LCD_SUPPORT)
+               ret = dmub_abm_set_event(abm, scaling_enable, 
scaling_strength_map, panel_inst);
+       else if (feature_support == ABM_CACP_SUPPORT)
+               ret = dmub_cacp_set_event(abm, full_screen, trans_info, 
hdr_mode, scaling_enable, panel_inst);

        return ret;
 }
@@ -176,11 +240,17 @@ static bool dmub_abm_set_backlight_level_pwm_ex(struct 
abm *abm,
        (void)controller_id;
        bool ret = false;
        unsigned int feature_support;
+       enum dc_panel_type panel_type = PANEL_TYPE_NONE;

        feature_support = abm_feature_support(abm, panel_inst);

        if (feature_support == ABM_LCD_SUPPORT)
                ret = dmub_abm_set_backlight_level(abm, backlight_pwm_u16_16, 
frame_ramp, panel_inst);
+       else if (feature_support == ABM_CACP_SUPPORT) {
+               panel_type = abm_get_paneltype(abm, panel_inst);
+               if (panel_type == PANEL_TYPE_MINILED)
+                       ret = dmub_cacp_set_backlight_level(abm, 
backlight_pwm_u16_16, frame_ramp, panel_inst);
+       }

        return ret;
 }
@@ -194,6 +264,7 @@ static const struct abm_funcs abm_funcs = {
        .set_abm_pause = dmub_abm_set_pause_ex,
        .save_restore = dmub_abm_save_restore_ex,
        .set_pipe_ex = dmub_abm_set_pipe_ex,
+       .set_abm_event = dmub_abm_set_event_ex,
        .set_backlight_level_pwm = dmub_abm_set_backlight_level_pwm_ex,
 };

diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_cacp.c 
b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_cacp.c
new file mode 100644
index 000000000000..9f58fa2e25fd
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_cacp.c
@@ -0,0 +1,213 @@
+/* Copyright (C) 2022 Advanced Micro Devices, Inc. All rights reserved. */
+
+#include "dmub_abm.h"
+#include "dmub_abm_cacp.h"
+#include "dce_abm.h"
+#include "dc.h"
+#include "dc_dmub_srv.h"
+#include "dmub/dmub_srv.h"
+#include "core_types.h"
+
+#define CACP_LEVEL_NUM 4
+
+void dmub_cacp_init(struct abm *abm, const char *src, unsigned int bytes, 
unsigned int panel_inst)
+{
+       union dmub_rb_cmd cmd;
+       struct dc_context *dc = abm->ctx;
+       uint8_t panel_mask = 0x01 << panel_inst;
+       struct dc_link *edp_links[MAX_NUM_EDP];
+       unsigned int i, edp_num;
+
+       // TODO: Optimize by only reading back final 4 bytes
+       dmub_srv_flush_buffer_mem(dc->dmub_srv->dmub, 
&dc->dmub_srv->dmub->scratch_mem_fb);
+
+       // Copy iramtable into cw7
+       memcpy(dc->dmub_srv->dmub->scratch_mem_fb.cpu_addr, (void *)src, bytes);
+
+       memset(&cmd, 0, sizeof(cmd));
+       // Fw will copy from cw7 to fw_state
+       cmd.cacp_init_config.header.type = DMUB_CMD__CACP;
+       cmd.cacp_init_config.header.sub_type = DMUB_CMD__CACP_INIT_CONFIG;
+       cmd.cacp_init_config.cacp_init_config_data.src.quad_part = 
dc->dmub_srv->dmub->scratch_mem_fb.gpu_addr;
+       cmd.cacp_init_config.cacp_init_config_data.bytes = (uint16_t)bytes;
+       cmd.cacp_init_config.cacp_init_config_data.panel_mask = panel_mask;
+       cmd.cacp_init_config.cacp_init_config_data.visual_confirm =
+               (dc->dc->debug.visual_confirm == VISUAL_CONFIRM_ABM) ? true : 
false;
+
+       cmd.cacp_init_config.header.payload_bytes = sizeof(struct 
dmub_cmd_cacp_init_config_data);
+
+       dc_get_edp_links(dc->dc, edp_links, &edp_num);
+       for (i = 0; i < edp_num; i++) {
+               if (panel_inst == i)
+                       break;
+       }
+
+       if (i < edp_num) {
+               cmd.cacp_init_config.cacp_init_config_data.strscl_valid =
+                       
(uint8_t)edp_links[panel_inst]->panel_config.cacp.strscl_valid;
+               cmd.cacp_init_config.cacp_init_config_data.mode =
+                       
edp_links[panel_inst]->panel_config.cacp.cacp_control_mode ?
+                       DMUB_CMD_CACP_CONTROL_MODE_1 : 
DMUB_CMD_CACP_CONTROL_MODE_0;
+               for (int j = 0; j < CACP_LEVEL_NUM; j++) {
+                       
cmd.cacp_init_config.cacp_init_config_data.strscl_sdr[j] =
+                               
(uint8_t)edp_links[panel_inst]->panel_config.cacp.strscl_sdr[j];
+                       
cmd.cacp_init_config.cacp_init_config_data.strscl_hdr[j] =
+                               
(uint8_t)edp_links[panel_inst]->panel_config.cacp.strscl_hdr[j];
+               }
+       }
+
+       dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
+}
+
+bool dmub_cacp_set_level(struct abm *abm, unsigned int abm_level, unsigned 
char panel_mask)
+{
+       union dmub_rb_cmd cmd;
+       struct dc_context *dc = abm->ctx;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.cacp_set_level.header.type = DMUB_CMD__CACP;
+       cmd.cacp_set_level.header.sub_type = DMUB_CMD__CACP_SET_LEVEL;
+
+       cmd.cacp_set_level.cacp_set_level_data.level = abm_level;
+       cmd.cacp_set_level.cacp_set_level_data.version = 
DMUB_CMD_CACP_CONTROL_VERSION_1;
+       cmd.cacp_set_level.cacp_set_level_data.panel_mask = panel_mask;
+
+       cmd.cacp_set_level.header.payload_bytes = sizeof(struct 
dmub_cmd_cacp_set_level_data);
+
+       dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
+
+       return true;
+}
+
+bool dmub_cacp_set_pipe(struct abm *abm, unsigned int otg_inst,
+               unsigned int pipe_option, unsigned int panel_inst, unsigned int 
pwrseq_inst)
+{
+       union dmub_rb_cmd cmd;
+       struct dc_context *dc = abm->ctx;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.cacp_set_pipe.header.type = DMUB_CMD__CACP;
+       cmd.cacp_set_pipe.header.sub_type = DMUB_CMD__CACP_SET_PIPE;
+
+       cmd.cacp_set_pipe.cacp_set_pipe_data.otg_inst = (uint8_t)otg_inst;
+       cmd.cacp_set_pipe.cacp_set_pipe_data.panel_inst = (uint8_t)panel_inst;
+       cmd.cacp_set_pipe.cacp_set_pipe_data.set_pipe_option = 
(uint8_t)pipe_option;
+       cmd.cacp_set_pipe.cacp_set_pipe_data.pwrseq_inst = (uint8_t)pwrseq_inst;
+       cmd.cacp_set_pipe.header.payload_bytes = sizeof(struct 
dmub_cmd_cacp_set_pipe_data);
+
+       dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
+
+       return true;
+}
+
+bool dmub_cacp_set_event(struct abm *abm, unsigned int full_screen, unsigned 
int trans_info,
+               unsigned int hdr_mode, unsigned int scaling_enable, unsigned 
int panel_inst)
+{
+       union dmub_rb_cmd cmd;
+       struct dc_context *dc = abm->ctx;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.cacp_set_event.header.type = DMUB_CMD__CACP;
+       cmd.cacp_set_event.header.sub_type = DMUB_CMD__CACP_SET_EVENT;
+
+       //TODO:
+       cmd.cacp_set_event.cacp_set_event_data.full_screen_mode = 
(uint8_t)full_screen;
+       cmd.cacp_set_event.cacp_set_event_data.trans_info = trans_info;
+       cmd.cacp_set_event.cacp_set_event_data.hdr_mode = (uint8_t)hdr_mode;
+       cmd.cacp_set_event.cacp_set_event_data.vb_scaling_enable = 
(uint8_t)scaling_enable;
+       cmd.cacp_set_event.cacp_set_event_data.panel_mask = (1<<panel_inst);
+
+       cmd.cacp_set_event.header.payload_bytes = sizeof(struct 
dmub_cmd_cacp_set_event_data);
+
+       dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
+
+       return true;
+}
+
+bool dmub_cacp_set_pause(struct abm *abm, bool pause, unsigned int panel_inst, 
unsigned int otg_inst)
+{
+       union dmub_rb_cmd cmd;
+       struct dc_context *dc = abm->ctx;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.cacp_pause.header.type = DMUB_CMD__CACP;
+       cmd.cacp_pause.header.sub_type = DMUB_CMD__CACP_PAUSE;
+
+       cmd.cacp_pause.cacp_pause_data.panel_mask = (1<<panel_inst);
+       cmd.cacp_pause.cacp_pause_data.otg_inst = (uint8_t)otg_inst;
+       cmd.cacp_pause.cacp_pause_data.enable = pause;
+
+       cmd.cacp_pause.header.payload_bytes = sizeof(struct 
dmub_cmd_cacp_pause_data);
+
+       dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
+
+       return true;
+}
+
+bool dmub_cacp_set_backlight_level(struct abm *abm,
+               unsigned int backlight_pwm_u16_16,
+               unsigned int frame_ramp,
+               unsigned int panel_inst)
+{
+       union dmub_rb_cmd cmd;
+       struct dc_context *dc = abm->ctx;
+
+       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.frame_ramp = frame_ramp;
+       cmd.cacp_set_backlight.cacp_set_backlight_data.backlight_user_level = 
backlight_pwm_u16_16;
+       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;
+}
+
+void dmub_cacp_enable_fractional_pwm(struct abm *abm, uint8_t panel_mask)
+{
+       union dmub_rb_cmd cmd;
+       struct dc_context *dc = abm->ctx;
+       uint32_t fractional_pwm = (dc->dc->config.disable_fractional_pwm == 
false) ? 1 : 0;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.cacp_set_pwm_frac.header.type = DMUB_CMD__CACP;
+       cmd.cacp_set_pwm_frac.header.sub_type = DMUB_CMD__CACP_SET_PWM_FRAC;
+       cmd.cacp_set_pwm_frac.cacp_set_pwm_frac_data.fractional_pwm = 
fractional_pwm;
+       cmd.cacp_set_pwm_frac.cacp_set_pwm_frac_data.version = 
DMUB_CMD_CACP_CONTROL_VERSION_1;
+       cmd.cacp_set_pwm_frac.cacp_set_pwm_frac_data.panel_mask = panel_mask;
+       cmd.cacp_set_pwm_frac.header.payload_bytes = sizeof(struct 
dmub_cmd_cacp_set_pwm_frac_data);
+
+       dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
+}
+
+bool dmub_cacp_get_histogram(
+               struct dc_context *dc,
+               unsigned int panel_inst,
+               unsigned int *histogram,
+               enum dmub_abm_histogram_type histogram_type,
+               unsigned int size)
+{
+       union dmub_rb_cmd cmd;
+
+       dmub_srv_flush_buffer_mem(dc->dmub_srv->dmub, 
&dc->dmub_srv->dmub->scratch_mem_fb);
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.cacp_get_histogram.header.type = DMUB_CMD__CACP;
+       cmd.cacp_get_histogram.header.sub_type = DMUB_CMD__CACP_GET_HISTOGRAM;
+
+       cmd.cacp_get_histogram.dest.quad_part = 
dc->dmub_srv->dmub->scratch_mem_fb.gpu_addr;
+       cmd.cacp_get_histogram.bytes = (uint16_t)size;
+       cmd.cacp_get_histogram.panel_inst = (uint8_t)panel_inst;
+       cmd.cacp_get_histogram.histogram_type = histogram_type;
+       cmd.cacp_get_histogram.header.payload_bytes = sizeof(struct 
dmub_rb_cmd_cacp_get_histogram);
+
+       dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
+
+       memcpy((void *)histogram, dc->dmub_srv->dmub->scratch_mem_fb.cpu_addr, 
size);
+
+       return true;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_cacp.h 
b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_cacp.h
new file mode 100644
index 000000000000..3b3b712c1242
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_cacp.h
@@ -0,0 +1,20 @@
+/* Copyright (C) 2022 Advanced Micro Devices, Inc. All rights reserved. */
+
+#include "dmub_cmd.h"
+
+#ifndef __DMUB_ABM_CACP_H__
+#define __DMUB_ABM_CACP_H__
+
+void dmub_cacp_init(struct abm *abm, const char *src, unsigned int bytes, 
unsigned int panel_inst);
+bool dmub_cacp_set_level(struct abm *abm, unsigned int cacp_level, unsigned 
char panel_mask);
+bool dmub_cacp_set_pipe(struct abm *abm, unsigned int otg_inst, unsigned int 
pipe_option,
+                                               unsigned int panel_inst, 
unsigned int pwrseq_inst);
+bool dmub_cacp_set_event(struct abm *abm, unsigned int full_screen, unsigned 
int trans_info, unsigned int hdr_mode,
+                                               unsigned int scaling_enable, 
unsigned int panel_inst);
+bool dmub_cacp_set_pause(struct abm *abm, bool pause, unsigned int panel_inst, 
unsigned int otg_inst);
+bool dmub_cacp_set_backlight_level(struct abm *abm, unsigned int 
backlight_pwm_u16_16, unsigned int frame_ramp,
+                                               unsigned int panel_inst);
+void dmub_cacp_enable_fractional_pwm(struct abm *abm, uint8_t panel_mask);
+bool dmub_cacp_get_histogram(struct dc_context *dc, unsigned int panel_inst, 
unsigned int *histogram,
+               enum dmub_abm_histogram_type histogram_type, unsigned int size);
+#endif
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c 
b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c
index 476c2112afec..2be68f8dd0fc 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c
@@ -136,6 +136,26 @@ void dcn21_PLAT_58856_wa(struct dc_state *context, struct 
pipe_ctx *pipe_ctx)
        pipe_ctx->stream->dpms_off = true;
 }

+bool dcn21_dmub_cacp_set_pipe(struct abm *abm, uint32_t otg_inst,
+               uint32_t option, uint32_t panel_inst, uint32_t pwrseq_inst)
+{
+       union dmub_rb_cmd cmd;
+       struct dc_context *dc = abm->ctx;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.cacp_set_pipe.header.type = DMUB_CMD__CACP;
+       cmd.cacp_set_pipe.header.sub_type = DMUB_CMD__CACP_SET_PIPE;
+       cmd.cacp_set_pipe.cacp_set_pipe_data.otg_inst = (uint8_t)otg_inst;
+       cmd.cacp_set_pipe.cacp_set_pipe_data.pwrseq_inst = (uint8_t)pwrseq_inst;
+       cmd.cacp_set_pipe.cacp_set_pipe_data.set_pipe_option = (uint8_t)option;
+       cmd.cacp_set_pipe.cacp_set_pipe_data.panel_inst = (uint8_t)panel_inst;
+       cmd.cacp_set_pipe.header.payload_bytes = sizeof(struct 
dmub_cmd_cacp_set_pipe_data);
+
+       dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
+
+       return true;
+}
+
 bool dcn21_dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst,
                uint32_t option, uint32_t panel_inst, uint32_t pwrseq_inst)
 {
@@ -181,10 +201,12 @@ void dcn21_set_abm_immediate_disable(struct pipe_ctx 
*pipe_ctx)
        uint32_t otg_inst = pipe_ctx->stream_res.tg->inst;
        struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl;
        struct dmcu *dmcu = pipe_ctx->stream->ctx->dc->res_pool->dmcu;
+       struct dc_link *link = pipe_ctx->stream->link;

        // make a short term w/a for an issue that backlight ramping 
unexpectedly paused in the middle,
        // will decouple backlight from ABM and redefine DMUB interface, then 
this w/a could be removed
-       if (pipe_ctx->stream->abm_level == 0 || pipe_ctx->stream->abm_level == 
ABM_LEVEL_IMMEDIATE_DISABLE) {
+       if ((pipe_ctx->stream->abm_level == 0 || pipe_ctx->stream->abm_level == 
ABM_LEVEL_IMMEDIATE_DISABLE)
+               && (link && !link->panel_config.cacp.cacp_supported)) {
                return;
        }

@@ -197,6 +219,9 @@ void dcn21_set_abm_immediate_disable(struct pipe_ctx 
*pipe_ctx)
                if (abm->funcs && abm->funcs->set_pipe_ex) {
                        abm->funcs->set_pipe_ex(abm, otg_inst, 
SET_ABM_PIPE_IMMEDIATELY_DISABLE,
                                        panel_cntl->inst, 
panel_cntl->pwrseq_inst);
+               } else if (link && link->panel_config.cacp.cacp_supported) {
+                       dcn21_dmub_cacp_set_pipe(abm, otg_inst, 
SET_CACP_PIPE_IMMEDIATELY_DISABLE,
+                                               panel_cntl->inst, 
panel_cntl->pwrseq_inst);
                } else {
                        dcn21_dmub_abm_set_pipe(abm,
                                                otg_inst,
@@ -214,6 +239,7 @@ void dcn21_set_pipe(struct pipe_ctx *pipe_ctx)
        struct timing_generator *tg = pipe_ctx->stream_res.tg;
        struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl;
        struct dmcu *dmcu = pipe_ctx->stream->ctx->dc->res_pool->dmcu;
+       struct dc_link *link = pipe_ctx->stream->link;
        uint32_t otg_inst;

        if (!abm || !tg || !panel_cntl)
@@ -233,6 +259,11 @@ void dcn21_set_pipe(struct pipe_ctx *pipe_ctx)
                                        panel_cntl->inst,
                                        panel_cntl->pwrseq_inst);
        } else {
+
+               if (link && link->panel_config.cacp.cacp_supported)
+                       dcn21_dmub_cacp_set_pipe(abm, otg_inst, 
SET_CACP_PIPE_NORMAL,
+                                       panel_cntl->inst, 
panel_cntl->pwrseq_inst);
+               else
                        dcn21_dmub_abm_set_pipe(abm, otg_inst,
                                  SET_ABM_PIPE_NORMAL,
                                  panel_cntl->inst,
@@ -250,6 +281,7 @@ bool dcn21_set_backlight_level(struct pipe_ctx *pipe_ctx,
        uint32_t otg_inst;
        uint32_t backlight_pwm_u16_16 = 
backlight_level_params->backlight_pwm_u16_16;
        uint32_t frame_ramp = backlight_level_params->frame_ramp;
+       struct dc_link *link = pipe_ctx->stream->link;

        if (!abm || !tg || !panel_cntl)
                return false;
@@ -268,6 +300,12 @@ bool dcn21_set_backlight_level(struct pipe_ctx *pipe_ctx,
                                        panel_cntl->inst,
                                        panel_cntl->pwrseq_inst);
        } else {
+               if (link && link->panel_config.cacp.cacp_supported)
+                       dcn21_dmub_cacp_set_pipe(abm, otg_inst,
+                                       SET_CACP_PIPE_NORMAL,
+                                       panel_cntl->inst,
+                                       panel_cntl->pwrseq_inst);
+               else
                        dcn21_dmub_abm_set_pipe(abm,
                                  otg_inst,
                                  SET_ABM_PIPE_NORMAL,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.h 
b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.h
index f72a27ac1bf1..aae13447cfa8 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.h
@@ -47,6 +47,8 @@ void dcn21_optimize_pwr_state(
 void dcn21_PLAT_58856_wa(struct dc_state *context,
                struct pipe_ctx *pipe_ctx);

+bool dcn21_dmub_cacp_set_pipe(struct abm *abm, uint32_t otg_inst,
+       uint32_t option, uint32_t panel_inst, uint32_t pwrseq_inst);
 bool dcn21_dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst,
        uint32_t option, uint32_t panel_inst, uint32_t pwrseq_inst);
 void dcn21_set_pipe(struct pipe_ctx *pipe_ctx);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c 
b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c
index 43e4edfe9182..e72e10c276de 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c
@@ -54,6 +54,7 @@
 #include "dce/dce_i2c_hw.h"
 #include "dce/dmub_abm_lcd.h"
 #include "dio/dcn10/dcn10_dio.h"
+#include "dce/dmub_abm_cacp.h"

 #define DC_LOGGER_INIT(logger)

@@ -726,12 +727,19 @@ bool dcn31_set_backlight_level(struct pipe_ctx *pipe_ctx,
        struct timing_generator *tg = pipe_ctx->stream_res.tg;
        struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl;
        uint32_t otg_inst;
+       struct dc_link *link = pipe_ctx->stream->link;

        if (!abm || !tg || !panel_cntl)
                return false;

        otg_inst = tg->inst;

+       if (link && link->panel_config.cacp.cacp_supported)
+               dcn21_dmub_cacp_set_pipe(abm, otg_inst,
+                       SET_CACP_PIPE_NORMAL,
+                       panel_cntl->inst,
+                       panel_cntl->pwrseq_inst);
+       else
                dcn21_dmub_abm_set_pipe(abm,
                        otg_inst,
                        SET_ABM_PIPE_NORMAL,
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h 
b/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h
index 3f0161d64675..6ae7cf109565 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h
@@ -66,6 +66,9 @@ struct abm_funcs {
                        unsigned int option,
                        unsigned int panel_inst,
                        unsigned int pwrseq_inst);
+       bool (*set_abm_event)(struct abm *abm, unsigned int full_screen, 
unsigned int trans_info,
+                       unsigned int hdr_mode, unsigned int scaling_enable, 
unsigned int scaling_strength_map,
+                       unsigned int panel_inst);
 };

 #endif
diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_power.h 
b/drivers/gpu/drm/amd/display/modules/inc/mod_power.h
index f9814cf7bbdb..02bee3b1956d 100644
--- a/drivers/gpu/drm/amd/display/modules/inc/mod_power.h
+++ b/drivers/gpu/drm/amd/display/modules/inc/mod_power.h
@@ -328,6 +328,17 @@ bool mod_power_is_abm_active(struct mod_power *mod_power,
                const struct dc_link *link,
                unsigned int inst);

+bool mod_power_is_abm_supported(struct mod_power *mod_power,
+               unsigned int inst);
+
+bool mod_power_abm_set_event(struct mod_power *mod_power,
+               unsigned int full_screen, unsigned int trans_info,
+               unsigned int hdr_mode, unsigned int scaling_enable,
+               unsigned int scaling_strength_map, unsigned int inst);
+
+bool mod_power_abm_set_strength(struct mod_power *mod_power,
+               unsigned int strength,
+               unsigned int inst);

 bool mod_power_set_psr_event(struct mod_power *mod_power,
                struct dc_stream_state *stream, bool set_event,
diff --git a/drivers/gpu/drm/amd/display/modules/power/power_abm.c 
b/drivers/gpu/drm/amd/display/modules/power/power_abm.c
index b9447cb7485b..5b972f04bf7a 100644
--- a/drivers/gpu/drm/amd/display/modules/power/power_abm.c
+++ b/drivers/gpu/drm/amd/display/modules/power/power_abm.c
@@ -1453,6 +1453,76 @@ bool mod_power_is_abm_active(struct mod_power *mod_power,
        return is_active;
 }

+bool mod_power_is_abm_supported(struct mod_power *mod_power,
+               unsigned int inst)
+{
+       struct core_power *core_power = NULL;
+       struct dc *dc = NULL;
+
+       if (mod_power == NULL)
+               return false;
+
+       core_power = MOD_POWER_TO_CORE(mod_power);
+       dc = core_power->dc;
+
+       // It's only implemented on dmcub.
+       if (dc->ctx->dmub_srv) {
+               if (!dmub_is_abm_supported(dc->res_pool, inst))
+                       return false;
+       } else
+               return false;
+
+       return true;
+}
+
+bool mod_power_abm_set_event(struct mod_power *mod_power,
+               unsigned int full_screen, unsigned int trans_info,
+               unsigned int hdr_mode, unsigned int scaling_enable,
+               unsigned int scaling_strength_map, unsigned int inst)
+{
+       struct core_power *core_power = NULL;
+       struct dc *dc = NULL;
+
+       if (mod_power == NULL)
+               return false;
+
+       core_power = MOD_POWER_TO_CORE(mod_power);
+       dc = core_power->dc;
+
+       // It's only implemented on dmcub.
+       if (dc->ctx->dmub_srv) {
+               if (!dmub_set_abm_event(dc->res_pool, full_screen, trans_info,
+                               hdr_mode, scaling_enable, scaling_strength_map, 
inst))
+                       return false;
+       } else
+               return false;
+
+       return true;
+}
+
+bool mod_power_abm_set_strength(struct mod_power *mod_power,
+               unsigned int strength,
+               unsigned int inst)
+{
+       struct core_power *core_power = NULL;
+       struct dc *dc = NULL;
+
+       if (mod_power == NULL)
+               return false;
+
+       core_power = MOD_POWER_TO_CORE(mod_power);
+       dc = core_power->dc;
+
+       // It's only implemented on dmcub.
+       if (dc->ctx->dmub_srv) {
+               if (!dmub_set_abm_strength(dc->res_pool, strength, inst))
+                       return false;
+       } else
+               return false;
+
+       return true;
+}
+
 static void fill_backlight_transform_table(struct dmcu_iram_parameters params,
                struct iram_table_v_2 *table)
 {
@@ -1990,6 +2060,62 @@ bool dmub_init_abm_config(struct resource_pool *res_pool,
        return result;
 }

+bool dmub_is_abm_supported(struct resource_pool *res_pool, unsigned int inst)
+{
+
+       if (res_pool->abm == NULL && res_pool->multiple_abms[inst] == NULL)
+               return false;
+
+       return true;
+}
+
+bool dmub_set_abm_event(struct resource_pool *res_pool,
+               unsigned int full_screen, unsigned int trans_info,
+               unsigned int hdr_mode, unsigned int scaling_enable, unsigned 
int scaling_strength_map,
+               unsigned int inst)
+{
+       bool result = false;
+
+       if (res_pool->abm == NULL && res_pool->multiple_abms[inst] == NULL)
+               return false;
+
+       if (res_pool->multiple_abms[inst]) {
+               if (res_pool->multiple_abms[inst]->funcs->set_abm_event)
+                       result = 
res_pool->multiple_abms[inst]->funcs->set_abm_event(
+                               res_pool->multiple_abms[inst], full_screen, 
trans_info,
+                                       hdr_mode, scaling_enable, 
scaling_strength_map, inst);
+       } else {
+               if (res_pool->abm->funcs->set_abm_event)
+                       result = res_pool->abm->funcs->set_abm_event(
+                                       res_pool->abm, full_screen, trans_info,
+                                       hdr_mode, scaling_enable, 
scaling_strength_map, inst);
+       }
+
+       return result;
+}
+
+bool dmub_set_abm_strength(struct resource_pool *res_pool,
+       unsigned int strength,
+       unsigned int inst)
+{
+       bool result = false;
+
+       if (res_pool->abm == NULL && res_pool->multiple_abms[inst] == NULL)
+               return false;
+
+       if (res_pool->multiple_abms[inst]) {
+               if (res_pool->multiple_abms[inst]->funcs->set_abm_level)
+                       result = 
res_pool->multiple_abms[inst]->funcs->set_abm_level(
+                               res_pool->multiple_abms[inst], strength);
+       } else {
+               if (res_pool->abm->funcs->set_abm_level)
+                       result = res_pool->abm->funcs->set_abm_level(
+                                       res_pool->abm, strength);
+       }
+
+       return result;
+}
+
 bool dmcu_load_iram(struct dmcu *dmcu,
        struct dmcu_iram_parameters params)
 {
diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.h 
b/drivers/gpu/drm/amd/display/modules/power/power_helpers.h
index 600da3e33126..548c8ff6ddb4 100644
--- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.h
+++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.h
@@ -146,6 +146,16 @@ bool dmub_init_abm_config(struct resource_pool *res_pool,
                struct dmcu_iram_parameters params,
                unsigned int inst);

+bool dmub_is_abm_supported(struct resource_pool *res_pool,
+               unsigned int inst);
+bool dmub_set_abm_event(struct resource_pool *res_pool,
+               unsigned int full_screen, unsigned int trans_info,
+               unsigned int hdr_mode, unsigned int scaling_enable,
+               unsigned int scaling_strength_map, unsigned int inst);
+bool dmub_set_abm_strength(struct resource_pool *res_pool,
+               unsigned int strength,
+               unsigned int inst);
+
 void init_replay_config(struct dc_link *link, struct replay_config *pr_config);
 void set_replay_coasting_vtotal(struct dc_link *link,
        enum replay_coasting_vtotal_type type,
--
2.55.0

Reply via email to