drm/amd/display: ABM pause toggle
authorReza Amini <reza.amini@amd.com>
Mon, 26 Jun 2023 18:50:01 +0000 (14:50 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 18 Jul 2023 15:16:23 +0000 (11:16 -0400)
[why]
Allow ABM states to be transferred across display
adapters for smooth display transitions.

[how]
We call DMUB to pause and get ABM states. We
transfer data to other gpu, and deliver data and
ask ABM to un-pause.

Reviewed-by: Harry Vanzylldejong <harry.vanzylldejong@amd.com>
Acked-by: Alan Liu <haoping.liu@amd.com>
Signed-off-by: Reza Amini <reza.amini@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/dc.h
drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c
drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c
drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.h
drivers/gpu/drm/amd/display/dc/inc/hw/abm.h
drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h

index 4284a36..5d29b0a 100644 (file)
@@ -5276,3 +5276,56 @@ void dc_notify_vsync_int_state(struct dc *dc, struct dc_stream_state *stream, bo
        if (pipe->stream_res.abm && pipe->stream_res.abm->funcs->set_abm_pause)
                pipe->stream_res.abm->funcs->set_abm_pause(pipe->stream_res.abm, !enable, i, pipe->stream_res.tg->inst);
 }
+
+/*****************************************************************************
+ *  dc_abm_save_restore() - Interface to DC for save+pause and restore+un-pause
+ *                          ABM
+ *  @dc: dc structure
+ *     @stream: stream where vsync int state changed
+ *  @pData: abm hw states
+ *
+ ****************************************************************************/
+bool dc_abm_save_restore(
+               struct dc *dc,
+               struct dc_stream_state *stream,
+               struct abm_save_restore *pData)
+{
+       int i;
+       int edp_num;
+       struct pipe_ctx *pipe = NULL;
+       struct dc_link *link = stream->sink->link;
+       struct dc_link *edp_links[MAX_NUM_EDP];
+
+
+       /*find primary pipe associated with stream*/
+       for (i = 0; i < MAX_PIPES; i++) {
+               pipe = &dc->current_state->res_ctx.pipe_ctx[i];
+
+               if (pipe->stream == stream && pipe->stream_res.tg)
+                       break;
+       }
+
+       if (i == MAX_PIPES) {
+               ASSERT(0);
+               return false;
+       }
+
+       dc_get_edp_links(dc, edp_links, &edp_num);
+
+       /* Determine panel inst */
+       for (i = 0; i < edp_num; i++)
+               if (edp_links[i] == link)
+                       break;
+
+       if (i == edp_num)
+               return false;
+
+       if (pipe->stream_res.abm &&
+               pipe->stream_res.abm->funcs->save_restore)
+               return pipe->stream_res.abm->funcs->save_restore(
+                               pipe->stream_res.abm,
+                               i,
+                               pData);
+       return false;
+}
+
index d265ef8..ec7edb7 100644 (file)
@@ -40,6 +40,8 @@
 #include "inc/hw/dmcu.h"
 #include "dml/display_mode_lib.h"
 
+struct abm_save_restore;
+
 /* forward declaration */
 struct aux_payload;
 struct set_config_cmd_payload;
@@ -2244,6 +2246,11 @@ void dc_z10_save_init(struct dc *dc);
 bool dc_is_dmub_outbox_supported(struct dc *dc);
 bool dc_enable_dmub_notifications(struct dc *dc);
 
+bool dc_abm_save_restore(
+               struct dc *dc,
+               struct dc_stream_state *stream,
+               struct abm_save_restore *pData);
+
 void dc_enable_dmub_outbox(struct dc *dc);
 
 bool dc_process_dmub_aux_transfer_async(struct dc *dc,
index 2fb9572..d3e6544 100644 (file)
@@ -27,6 +27,7 @@
 #include "dmub_abm_lcd.h"
 #include "dc.h"
 #include "core_types.h"
+#include "dmub_cmd.h"
 
 #define TO_DMUB_ABM(abm)\
        container_of(abm, struct dce_abm, base)
@@ -118,6 +119,32 @@ static bool dmub_abm_set_pause_ex(struct abm *abm, bool pause, unsigned int pane
        return ret;
 }
 
+/*****************************************************************************
+ *  dmub_abm_save_restore_ex() - calls dmub_abm_save_restore for preserving DMUB's
+ *                              Varibright states for LCD only. OLED is TBD
+ *  @abm: used to check get dc context
+ *  @panel_inst: panel instance index
+ *  @pData: contains command to pause/un-pause abm and abm parameters
+ *
+ *
+ ***************************************************************************/
+static bool dmub_abm_save_restore_ex(
+               struct abm *abm,
+               unsigned int panel_inst,
+               struct abm_save_restore *pData)
+{
+       bool ret = false;
+       unsigned int feature_support;
+       struct dc_context *dc = abm->ctx;
+
+       feature_support = abm_feature_support(abm, panel_inst);
+
+       if (feature_support == ABM_LCD_SUPPORT)
+               ret = dmub_abm_save_restore(dc, panel_inst, pData);
+
+       return ret;
+}
+
 static bool dmub_abm_set_pipe_ex(struct abm *abm, uint32_t otg_inst, uint32_t option, uint32_t panel_inst)
 {
        bool ret = false;
@@ -155,6 +182,7 @@ static const struct abm_funcs abm_funcs = {
        .get_target_backlight = dmub_abm_get_target_backlight_ex,
        .init_abm_config = dmub_abm_init_config_ex,
        .set_abm_pause = dmub_abm_set_pause_ex,
+       .save_restore = dmub_abm_save_restore_ex,
        .set_pipe_ex = dmub_abm_set_pipe_ex,
        .set_backlight_level_pwm = dmub_abm_set_backlight_level_pwm_ex,
 };
index 39da73e..592a8f7 100644 (file)
@@ -208,6 +208,52 @@ bool dmub_abm_set_pause(struct abm *abm, bool pause, unsigned int panel_inst, un
        return true;
 }
 
+
+/*****************************************************************************
+ *  dmub_abm_save_restore() - dmub interface for abm save+pause and restore+
+ *                           un-pause
+ *  @dc: dc context
+ *  @panel_inst: panel instance index
+ *  @pData: contains command to pause/un-pause abm and exchange abm parameters
+ *
+ *  When called Pause will get abm data and store in pData, and un-pause will
+ *  set/apply abm data stored in pData.
+ *
+ *****************************************************************************/
+bool dmub_abm_save_restore(
+               struct dc_context *dc,
+               unsigned int panel_inst,
+               struct abm_save_restore *pData)
+{
+       union dmub_rb_cmd cmd;
+       uint8_t panel_mask = 0x01 << panel_inst;
+       unsigned int bytes = sizeof(struct abm_save_restore);
+
+       // TODO: Optimize by only reading back final 4 bytes
+       dmub_flush_buffer_mem(&dc->dmub_srv->dmub->scratch_mem_fb);
+
+       // Copy iramtable into cw7
+       memcpy(dc->dmub_srv->dmub->scratch_mem_fb.cpu_addr, (void *)pData, bytes);
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.abm_save_restore.header.type = DMUB_CMD__ABM;
+       cmd.abm_save_restore.header.sub_type = DMUB_CMD__ABM_SAVE_RESTORE;
+
+       cmd.abm_save_restore.abm_init_config_data.src.quad_part = dc->dmub_srv->dmub->scratch_mem_fb.gpu_addr;
+       cmd.abm_save_restore.abm_init_config_data.bytes = bytes;
+       cmd.abm_save_restore.abm_init_config_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1;
+       cmd.abm_save_restore.abm_init_config_data.panel_mask = panel_mask;
+
+       cmd.abm_save_restore.header.payload_bytes = sizeof(struct dmub_rb_cmd_abm_save_restore);
+
+       dm_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
+
+       // Copy iramtable data into local structure
+       memcpy((void *)pData, dc->dmub_srv->dmub->scratch_mem_fb.cpu_addr, bytes);
+
+       return true;
+}
+
 bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t option, uint32_t panel_inst)
 {
        union dmub_rb_cmd cmd;
index 00b4e26..853564d 100644 (file)
@@ -28,6 +28,8 @@
 
 #include "abm.h"
 
+struct abm_save_restore;
+
 void dmub_abm_init(struct abm *abm, uint32_t backlight);
 bool dmub_abm_set_level(struct abm *abm, uint32_t level, uint8_t panel_mask);
 unsigned int dmub_abm_get_current_backlight(struct abm *abm);
@@ -38,6 +40,10 @@ void dmub_abm_init_config(struct abm *abm,
        unsigned int inst);
 
 bool dmub_abm_set_pause(struct abm *abm, bool pause, unsigned int panel_inst, unsigned int stream_inst);
+bool dmub_abm_save_restore(
+               struct dc_context *dc,
+               unsigned int panel_inst,
+               struct abm_save_restore *pData);
 bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t option, uint32_t panel_inst);
 bool dmub_abm_set_backlight_level(struct abm *abm,
                unsigned int backlight_pwm_u16_16,
index d2190a3..33db15d 100644 (file)
@@ -27,6 +27,8 @@
 
 #include "dm_services_types.h"
 
+struct abm_save_restore;
+
 struct abm {
        struct dc_context *ctx;
        const struct abm_funcs *funcs;
@@ -55,6 +57,10 @@ struct abm_funcs {
                        unsigned int bytes,
                        unsigned int inst);
        bool (*set_abm_pause)(struct abm *abm, bool pause, unsigned int panel_inst, unsigned int otg_inst);
+       bool (*save_restore)(
+                       struct abm *abm,
+                       unsigned int panel_inst,
+                       struct abm_save_restore *pData);
        bool (*set_pipe_ex)(struct abm *abm,
                        unsigned int otg_inst,
                        unsigned int option,
index af1f507..15fea2b 100644 (file)
 #define PHYSICAL_ADDRESS_LOC union large_integer
 #endif
 
+#define ABM_NUM_OF_ACE_SEGMENTS         5
+
+union abm_flags {
+       struct {
+               /**
+                * @abm_enabled: indicates if abm is enabled.
+                */
+               unsigned int abm_enabled : 1;
+
+               /**
+                * @disable_abm_requested: indicates if driver has requested abm to be disabled.
+                */
+               unsigned int disable_abm_requested : 1;
+
+               /**
+                * @disable_abm_immediately: indicates if driver has requested abm to be disabled immediately.
+                */
+               unsigned int disable_abm_immediately : 1;
+
+               /**
+                * @disable_abm_immediate_keep_gain: indicates if driver has requested abm
+                * to be disabled immediately and keep gain.
+                */
+               unsigned int disable_abm_immediate_keep_gain : 1;
+
+               /**
+                * @fractional_pwm: indicates if fractional duty cycle for backlight pwm is enabled.
+                */
+               unsigned int fractional_pwm : 1;
+
+               /**
+                * @abm_gradual_bl_change: indicates if algorithm has completed gradual adjustment
+                * of user backlight level.
+                */
+               unsigned int abm_gradual_bl_change : 1;
+       } bitfields;
+
+       unsigned int u32all;
+};
+
+struct abm_save_restore {
+       /**
+        * @flags: Misc. ABM flags.
+        */
+       union abm_flags flags;
+
+       /**
+        * @pause: true:  pause ABM and get state
+        *         false: un-pause ABM after setting state
+        */
+       uint32_t pause;
+
+       /**
+        * @next_ace_slope: Next ACE slopes to be programmed in HW (u3.13)
+        */
+       uint32_t next_ace_slope[ABM_NUM_OF_ACE_SEGMENTS];
+
+       /**
+        * @next_ace_thresh: Next ACE thresholds to be programmed in HW (u10.6)
+        */
+       uint32_t next_ace_thresh[ABM_NUM_OF_ACE_SEGMENTS];
+
+       /**
+        * @next_ace_offset: Next ACE offsets to be programmed in HW (u10.6)
+        */
+       uint32_t next_ace_offset[ABM_NUM_OF_ACE_SEGMENTS];
+
+
+       /**
+        * @knee_threshold: Current x-position of ACE knee (u0.16).
+        */
+       uint32_t knee_threshold;
+       /**
+        * @current_gain: Current backlight reduction (u16.16).
+        */
+       uint32_t current_gain;
+       /**
+        * @curr_bl_level: Current actual backlight level converging to target backlight level.
+        */
+       uint16_t curr_bl_level;
+
+       /**
+        * @curr_user_bl_level: Current nominal backlight level converging to level requested by user.
+        */
+       uint16_t curr_user_bl_level;
+
+};
+
+
+
 /**
  * OS/FW agnostic memcpy
  */
@@ -2672,6 +2762,12 @@ enum dmub_cmd_abm_type {
         * unregister vertical interrupt after steady state is reached
         */
        DMUB_CMD__ABM_PAUSE     = 6,
+
+       /**
+        * * Save and Restore ABM state. On save we save parameters, and
+        * on restore we update state with passed in data.
+        */
+       DMUB_CMD__ABM_SAVE_RESTORE      = 7,
 };
 
 /**
@@ -3072,6 +3168,36 @@ struct dmub_rb_cmd_abm_pause {
 };
 
 /**
+ * Definition of a DMUB_CMD__ABM_SAVE_RESTORE command.
+ */
+struct dmub_rb_cmd_abm_save_restore {
+       /**
+        * Command header.
+        */
+       struct dmub_cmd_header header;
+
+       /**
+        * OTG hw instance
+        */
+       uint8_t otg_inst;
+
+       /**
+        * Enable or disable ABM pause
+        */
+       uint8_t freeze;
+
+       /**
+        * Explicit padding to 4 byte boundary.
+        */
+       uint8_t debug;
+
+       /**
+        * Data passed from driver to FW in a DMUB_CMD__ABM_INIT_CONFIG command.
+        */
+       struct dmub_cmd_abm_init_config_data abm_init_config_data;
+};
+
+/**
  * Data passed from driver to FW in a DMUB_CMD__QUERY_FEATURE_CAPS command.
  */
 struct dmub_cmd_query_feature_caps_data {
@@ -3509,6 +3635,11 @@ union dmub_rb_cmd {
        struct dmub_rb_cmd_abm_pause abm_pause;
 
        /**
+        * Definition of a DMUB_CMD__ABM_SAVE_RESTORE command.
+        */
+       struct dmub_rb_cmd_abm_save_restore abm_save_restore;
+
+       /**
         * Definition of a DMUB_CMD__DP_AUX_ACCESS command.
         */
        struct dmub_rb_cmd_dp_aux_access dp_aux_access;