summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/display
diff options
context:
space:
mode:
authorReza Amini <reza.amini@amd.com>2023-06-26 14:50:01 -0400
committerAlex Deucher <alexander.deucher@amd.com>2023-07-18 11:16:23 -0400
commitda915efaa213a33451965db1314a75a39219df65 (patch)
tree57ef91ed396b54c8ddc0b01a90d3b49e26947c48 /drivers/gpu/drm/amd/display
parent085f7bd955129191d38314a5189c1c27ae014faa (diff)
downloadlinux-stable-da915efaa213a33451965db1314a75a39219df65.tar.gz
linux-stable-da915efaa213a33451965db1314a75a39219df65.tar.bz2
linux-stable-da915efaa213a33451965db1314a75a39219df65.zip
drm/amd/display: ABM pause toggle
[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>
Diffstat (limited to 'drivers/gpu/drm/amd/display')
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc.c53
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc.h7
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c28
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c46
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.h6
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/abm.h6
-rw-r--r--drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h131
7 files changed, 277 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 4284a3609e98..5d29b0aa6056 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -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;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index d265ef8543c8..ec7edb7087b4 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -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,
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 2fb9572ce25d..d3e6544022b7 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c
@@ -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,
};
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c
index 39da73eba86e..592a8f7a1c6d 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c
@@ -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;
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.h b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.h
index 00b4e268768e..853564d7f471 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.h
+++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.h
@@ -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,
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 d2190a3320f6..33db15d69f23 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h
@@ -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,
diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
index af1f50742371..15fea2bcb34a 100644
--- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
+++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
@@ -144,6 +144,96 @@
#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;