]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/amd/display: Add new SMART POWER OLED interfaces
authorIan Chen <ian.chen@amd.com>
Tue, 13 May 2025 08:38:35 +0000 (16:38 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 12 Nov 2025 02:54:15 +0000 (21:54 -0500)
[why && how]
To optimize power consumption on certain OLED LED panels
by sending MaxCLL per frame to TCON

Reviewed-by: Aric Cyr <aric.cyr@amd.com>
Signed-off-by: Ian Chen <ian.chen@amd.com>
Signed-off-by: Fangzhi Zuo <jerry.zuo@amd.com>
Tested-by: Dan 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

index 5e79962c5f2bd4e566e2cb95fe31167502ffc08d..3999b583506685da77e09b3b6c74d7dc84f7689a 100644 (file)
@@ -5977,6 +5977,95 @@ bool dc_process_dmub_aux_transfer_async(struct dc *dc,
        return true;
 }
 
+bool dc_smart_power_oled_enable(const struct dc_link *link, bool enable, uint16_t peak_nits,
+                       uint8_t debug_control, uint16_t fixed_CLL, uint32_t triggerline)
+{
+       bool status = false;
+       struct dc *dc = link->ctx->dc;
+       union dmub_rb_cmd cmd;
+       uint8_t otg_inst = 0;
+       unsigned int panel_inst = 0;
+       struct pipe_ctx *pipe_ctx = NULL;
+       struct resource_context *res_ctx = &link->ctx->dc->current_state->res_ctx;
+       int i = 0;
+
+       // get panel_inst
+       if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
+               return status;
+
+       // get otg_inst
+       for (i = 0; i < MAX_PIPES; i++) {
+               if (res_ctx &&
+                       res_ctx->pipe_ctx[i].stream &&
+                       res_ctx->pipe_ctx[i].stream->link &&
+                       res_ctx->pipe_ctx[i].stream->link == link &&
+                       res_ctx->pipe_ctx[i].stream->link->connector_signal == SIGNAL_TYPE_EDP) {
+                       pipe_ctx = &res_ctx->pipe_ctx[i];
+                       //TODO: refactor for multi edp support
+                       break;
+               }
+       }
+
+       if (pipe_ctx)
+               otg_inst = pipe_ctx->stream_res.tg->inst;
+
+       // fill in cmd
+       memset(&cmd, 0, sizeof(cmd));
+
+       cmd.smart_power_oled_enable.header.type = DMUB_CMD__SMART_POWER_OLED;
+       cmd.smart_power_oled_enable.header.sub_type = DMUB_CMD__SMART_POWER_OLED_ENABLE;
+       cmd.smart_power_oled_enable.header.payload_bytes =
+               sizeof(struct dmub_rb_cmd_smart_power_oled_enable_data) - sizeof(struct dmub_cmd_header);
+       cmd.smart_power_oled_enable.header.ret_status = 1;
+       cmd.smart_power_oled_enable.data.enable = enable;
+       cmd.smart_power_oled_enable.data.panel_inst = panel_inst;
+       cmd.smart_power_oled_enable.data.peak_nits = peak_nits;
+       cmd.smart_power_oled_enable.data.otg_inst = otg_inst;
+       cmd.smart_power_oled_enable.data.digfe_inst = link->link_enc->preferred_engine;
+       cmd.smart_power_oled_enable.data.digbe_inst = link->link_enc->transmitter;
+
+       cmd.smart_power_oled_enable.data.debugcontrol = debug_control;
+       cmd.smart_power_oled_enable.data.triggerline = triggerline;
+       cmd.smart_power_oled_enable.data.fixed_max_cll = fixed_CLL;
+
+       // send cmd
+       status = dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
+
+       return status;
+}
+
+bool dc_smart_power_oled_get_max_cll(const struct dc_link *link, unsigned int *pCurrent_MaxCLL)
+{
+       struct dc *dc = link->ctx->dc;
+       union dmub_rb_cmd cmd;
+       bool status = false;
+       unsigned int panel_inst = 0;
+
+       // get panel_inst
+       if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
+               return status;
+
+       // fill in cmd
+       memset(&cmd, 0, sizeof(cmd));
+
+       cmd.smart_power_oled_getmaxcll.header.type = DMUB_CMD__SMART_POWER_OLED;
+       cmd.smart_power_oled_getmaxcll.header.sub_type = DMUB_CMD__SMART_POWER_OLED_GETMAXCLL;
+       cmd.smart_power_oled_getmaxcll.header.payload_bytes = sizeof(cmd.smart_power_oled_getmaxcll.data);
+       cmd.smart_power_oled_getmaxcll.header.ret_status = 1;
+
+       cmd.smart_power_oled_getmaxcll.data.input.panel_inst = panel_inst;
+
+       // send cmd and wait for reply
+       status = dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY);
+
+       if (status)
+               *pCurrent_MaxCLL = cmd.smart_power_oled_getmaxcll.data.output.current_max_cll;
+       else
+               *pCurrent_MaxCLL = 0;
+
+       return status;
+}
+
 uint8_t get_link_index_from_dpia_port_index(const struct dc *dc,
                                            uint8_t dpia_port_index)
 {
index 29805428fe93773215d0f74845bd013a63acab0a..6b9e510b1ed52390e63261c97d3a9d5eb8bf3356 100644 (file)
@@ -2719,6 +2719,13 @@ bool dc_process_dmub_aux_transfer_async(struct dc *dc,
                                uint32_t link_index,
                                struct aux_payload *payload);
 
+/*
+ * smart power OLED Interfaces
+ */
+bool dc_smart_power_oled_enable(const struct dc_link *link, bool enable, uint16_t peak_nits,
+       uint8_t debug_control, uint16_t fixed_CLL, uint32_t triggerline);
+bool dc_smart_power_oled_get_max_cll(const struct dc_link *link, unsigned int *pCurrent_MaxCLL);
+
 /* Get dc link index from dpia port index */
 uint8_t get_link_index_from_dpia_port_index(const struct dc *dc,
                                uint8_t dpia_port_index);