]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/amd/display: Initial support for SmartMux
authorAurabindo Pillai <aurabindo.pillai@amd.com>
Fri, 2 May 2025 13:51:04 +0000 (09:51 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 15 Jul 2025 18:07:53 +0000 (14:07 -0400)
SmartMux is a mechanism to switch the GPU being used for scanout in a
hybrid configuration. This is used for devices with an eDP and two GPUs.
This is only valid when the system has a physical switch (Multiplexer)
in the board to switch between the two GPUs.

When a graphically intensive workload like a game is being run, the
system can be switch the active display to the dGPU, so that we can
avoid copying the buffer from dGPU to APU for scanout. This helps with
latency and FPS. When power consumption is preferred, the system can be
switched to the APU.

Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
Signed-off-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
Signed-off-by: Ivan Lipski <ivan.lipski@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
20 files changed:
drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile
drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dalsmc.h
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30m_clk_mgr.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30m_clk_mgr.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30m_clk_mgr_smu_msg.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30m_clk_mgr_smu_msg.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dc.h
drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h
drivers/gpu/drm/amd/display/dc/link/link_dpms.c
drivers/gpu/drm/amd/display/dc/link/link_factory.c
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h
drivers/gpu/drm/amd/display/modules/power/power_helpers.h

index d9955c5d2e5ed59d0ae3105d7e56a9adbe2bde3d..60021671b386af2cc4549c7d473eee95d4575af1 100644 (file)
@@ -112,7 +112,7 @@ AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN21)
 ###############################################################################
 # DCN30
 ###############################################################################
-CLK_MGR_DCN30 = dcn30_clk_mgr.o dcn30_clk_mgr_smu_msg.o
+CLK_MGR_DCN30 = dcn30_clk_mgr.o dcn30_clk_mgr_smu_msg.o dcn30m_clk_mgr.o dcn30m_clk_mgr_smu_msg.o
 
 AMD_DAL_CLK_MGR_DCN30 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn30/,$(CLK_MGR_DCN30))
 
index 4c3e58c730b11c23af96e05e5f3df319f32ecf07..33b9d36619ff8bd54e7777452e4ec3978010bf91 100644 (file)
@@ -67,7 +67,7 @@ int clk_mgr_helper_get_active_display_cnt(
                if (dc_state_get_stream_subvp_type(context, stream) == SUBVP_PHANTOM)
                        continue;
 
-               if (!stream->dpms_off || (stream_status && stream_status->plane_count))
+               if (!stream->dpms_off || dc->is_switch_in_progress_dest || (stream_status && stream_status->plane_count))
                        display_count++;
        }
 
index fa09c594fd36d3957cb489406bd6dfe2fe05da9c..06da346769658d5858ecc773b80b3554b2dda8ad 100644 (file)
@@ -56,6 +56,7 @@
 #define DALSMC_MSG_SetDisplayRefreshFromMall      0xF
 #define DALSMC_MSG_SetExternalClientDfCstateAllow 0x10
 #define DALSMC_MSG_BacoAudioD3PME                 0x11
-#define DALSMC_Message_Count                      0x12
+#define DALSMC_MSG_SmartAccess                    0x12
+#define DALSMC_Message_Count                      0x13
 
 #endif
index 8083a553c60e888e148439dc3305adc879a9d3ea..ef77fcd164ed35375f298e03b2033b383441a706 100644 (file)
@@ -30,6 +30,7 @@
 #include "dce100/dce_clk_mgr.h"
 #include "dcn30/dcn30_clk_mgr.h"
 #include "dml/dcn30/dcn30_fpu.h"
+#include "dcn30/dcn30m_clk_mgr.h"
 #include "reg_helper.h"
 #include "core_types.h"
 #include "dm_helpers.h"
@@ -498,7 +499,8 @@ static struct clk_mgr_funcs dcn3_funcs = {
                .are_clock_states_equal = dcn3_are_clock_states_equal,
                .enable_pme_wa = dcn3_enable_pme_wa,
                .notify_link_rate_change = dcn30_notify_link_rate_change,
-               .is_smu_present = dcn3_is_smu_present
+               .is_smu_present = dcn3_is_smu_present,
+               .set_smartmux_switch = dcn30m_set_smartmux_switch
 };
 
 static void dcn3_init_clocks_fpga(struct clk_mgr *clk_mgr)
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30m_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30m_clk_mgr.c
new file mode 100644 (file)
index 0000000..8e8a11c
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2019 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "clk_mgr_internal.h"
+#include "dcn30/dcn30m_clk_mgr.h"
+#include "dcn30m_clk_mgr_smu_msg.h"
+
+
+uint32_t dcn30m_set_smartmux_switch(struct clk_mgr *clk_mgr_base, uint32_t pins_to_set)
+{
+       struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
+
+       return dcn30m_smu_set_smart_mux_switch(clk_mgr, pins_to_set);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30m_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30m_clk_mgr.h
new file mode 100644 (file)
index 0000000..757985b
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2019 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DCN30M_CLK_MGR_H__
+#define __DCN30M_CLK_MGR_H__
+
+uint32_t dcn30m_set_smartmux_switch(struct clk_mgr *clk_mgr_base, uint32_t pins_to_set);
+
+#endif //__DCN30M_CLK_MGR_H__
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30m_clk_mgr_smu_msg.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30m_clk_mgr_smu_msg.c
new file mode 100644 (file)
index 0000000..0dd0583
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2020 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dcn30m_clk_mgr_smu_msg.h"
+
+#include "clk_mgr_internal.h"
+#include "reg_helper.h"
+#include "dm_helpers.h"
+
+#include "dalsmc.h"
+
+#define mmDAL_MSG_REG  0x1628A
+#define mmDAL_ARG_REG  0x16273
+#define mmDAL_RESP_REG 0x16274
+
+#define REG(reg_name) \
+       mm ## reg_name
+
+#include "logger_types.h"
+#undef DC_LOGGER
+#define DC_LOGGER \
+       CTX->logger
+#define smu_print(str, ...) {DC_LOG_SMU(str, ##__VA_ARGS__); }
+
+
+/*
+ * Function to be used instead of REG_WAIT macro because the wait ends when
+ * the register is NOT EQUAL to zero, and because the translation in msg_if.h
+ * won't work with REG_WAIT.
+ */
+static uint32_t dcn30m_smu_wait_for_response(struct clk_mgr_internal *clk_mgr,
+       unsigned int delay_us, unsigned int max_retries)
+{
+       uint32_t reg = 0;
+
+       do {
+               reg = REG_READ(DAL_RESP_REG);
+               if (reg)
+                       break;
+
+               if (delay_us >= 1000)
+                       msleep(delay_us/1000);
+               else if (delay_us > 0)
+                       udelay(delay_us);
+       } while (max_retries--);
+
+       /* handle DALSMC_Result_CmdRejectedBusy? */
+
+       /* Log? */
+
+       return reg;
+}
+
+static bool dcn30m_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr,
+       uint32_t msg_id, uint32_t param_in, uint32_t *param_out)
+{
+       uint32_t result;
+       /* Wait for response register to be ready */
+       dcn30m_smu_wait_for_response(clk_mgr, 10, 200000);
+
+       /* Clear response register */
+       REG_WRITE(DAL_RESP_REG, 0);
+
+       /* Set the parameter register for the SMU message */
+       REG_WRITE(DAL_ARG_REG, param_in);
+
+       /* Trigger the message transaction by writing the message ID */
+       REG_WRITE(DAL_MSG_REG, msg_id);
+
+       result = dcn30m_smu_wait_for_response(clk_mgr, 10, 200000);
+
+       if (IS_SMU_TIMEOUT(result))
+               dm_helpers_smu_timeout(CTX, msg_id, param_in, 10 * 200000);
+
+       /* Wait for response */
+       if (result == DALSMC_Result_OK) {
+               if (param_out)
+                       *param_out = REG_READ(DAL_ARG_REG);
+
+               return true;
+       }
+
+       return false;
+}
+
+uint32_t dcn30m_smu_set_smart_mux_switch(struct clk_mgr_internal *clk_mgr, uint32_t pins_to_set)
+{
+       uint32_t response = 0;
+
+       smu_print("SMU Set SmartMux Switch: switch_dgpu = %d\n", pins_to_set);
+
+       dcn30m_smu_send_msg_with_param(clk_mgr,
+                       DALSMC_MSG_SmartAccess, pins_to_set, &response);
+
+       return response;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30m_clk_mgr_smu_msg.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30m_clk_mgr_smu_msg.h
new file mode 100644 (file)
index 0000000..8a59a47
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2020 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef DAL_DC_DCN30M_CLK_MGR_SMU_MSG_H_
+#define DAL_DC_DCN30M_CLK_MGR_SMU_MSG_H_
+
+#include "core_types.h"
+
+struct clk_mgr_internal;
+
+uint32_t     dcn30m_smu_set_smart_mux_switch(struct clk_mgr_internal *clk_mgr, uint32_t pins_to_set);
+#endif /* DAL_DC_DCN30M_CLK_MGR_SMU_MSG_H_ */
index 7014b8d000bbd79da256805c8cef87b289a20aa4..ec4e80e5b6eb22522343365fc9cabbdbc821c3ea 100644 (file)
@@ -427,6 +427,32 @@ void get_hdr_visual_confirm_color(
        }
 }
 
+/* Visual Confirm color definition for Smart Mux */
+void get_smartmux_visual_confirm_color(
+       struct dc *dc,
+       struct tg_color *color)
+{
+       uint32_t color_value = MAX_TG_COLOR_VALUE;
+
+       const struct tg_color sm_ver_colors[5] = {
+                       {0, 0, 0},                                      /* SMUX_MUXCONTROL_UNSUPPORTED - Black */
+                       {0, MAX_TG_COLOR_VALUE, 0},                     /* SMUX_MUXCONTROL_v10 - Green */
+                       {0, MAX_TG_COLOR_VALUE, MAX_TG_COLOR_VALUE},    /* SMUX_MUXCONTROL_v15 - Cyan */
+                       {MAX_TG_COLOR_VALUE, MAX_TG_COLOR_VALUE, 0},    /* SMUX_MUXCONTROL_MDM - Yellow */
+                       {MAX_TG_COLOR_VALUE, 0, MAX_TG_COLOR_VALUE},    /* SMUX_MUXCONTROL_vUNKNOWN - Magenta*/
+       };
+
+       if (dc->caps.is_apu) {
+               /* APU driving the eDP */
+               *color = sm_ver_colors[dc->config.smart_mux_version];
+       } else {
+               /* dGPU driving the eDP - red */
+               color->color_r_cr = color_value;
+               color->color_g_y = 0;
+               color->color_b_cb = 0;
+       }
+}
+
 /* Visual Confirm color definition for VABC */
 void get_vabc_visual_confirm_color(
        struct pipe_ctx *pipe_ctx,
index b4fe5859fa5f09a1569457557cb92e378e75c670..59c07756130d5abeff9f1d0af8a86758ef493c4d 100644 (file)
@@ -505,6 +505,7 @@ struct dc_config {
        bool use_spl;
        bool prefer_easf;
        bool use_pipe_ctx_sync_logic;
+       int smart_mux_version;
        bool ignore_dpref_ss;
        bool enable_mipi_converter_optimization;
        bool use_default_clock_table;
@@ -541,6 +542,7 @@ enum visual_confirm {
        VISUAL_CONFIRM_SWAPCHAIN = 6,
        VISUAL_CONFIRM_FAMS = 7,
        VISUAL_CONFIRM_SWIZZLE = 9,
+       VISUAL_CONFIRM_SMARTMUX_DGPU = 10,
        VISUAL_CONFIRM_REPLAY = 12,
        VISUAL_CONFIRM_SUBVP = 14,
        VISUAL_CONFIRM_MCLK_SWITCH = 16,
@@ -1639,6 +1641,8 @@ struct dc_scratch_space {
 
        struct gpio *hpd_gpio;
        enum dc_link_fec_state fec_state;
+       bool is_dds;
+       bool is_display_mux_present;
        bool link_powered_externally;   // Used to bypass hardware sequencing delays when panel is powered down forcibly
 
        struct dc_panel_config panel_config;
@@ -1693,6 +1697,10 @@ struct dc {
 
        /* Require to maintain clocks and bandwidth for UEFI enabled HW */
 
+       /* For eDP to know the switching state of SmartMux */
+       bool is_switch_in_progress_orig;
+       bool is_switch_in_progress_dest;
+
        /* FBC compressor */
        struct compressor *fbc_compressor;
 
index 252e862449a2c53dcd55073f2d3b142de16591d3..4ea13d0bf815e251c6551c53fdc8d5fbb3eeb702 100644 (file)
@@ -1686,6 +1686,19 @@ enum dc_status dce110_apply_single_controller_ctx_to_hw(
        if (dc_is_dp_signal(pipe_ctx->stream->signal))
                dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_OTG);
 
+       /* Temporary workaround to perform DSC programming ahead of stream enablement
+        * for smartmux/SPRS
+        * TODO: Remove SmartMux/SPRS checks once movement of DSC programming is generalized
+        */
+       if (pipe_ctx->stream->timing.flags.DSC) {
+               if ((pipe_ctx->stream->signal == SIGNAL_TYPE_EDP &&
+                       ((link->dc->config.smart_mux_version && link->dc->is_switch_in_progress_dest)
+                       || link->is_dds || link->skip_implict_edp_power_control)) &&
+                       (dc_is_dp_signal(pipe_ctx->stream->signal) ||
+                       dc_is_virtual_signal(pipe_ctx->stream->signal)))
+                       dc->link_srv->set_dsc_enable(pipe_ctx, true);
+       }
+
        if (!stream->dpms_off)
                dc->link_srv->set_dpms_on(context, pipe_ctx);
 
@@ -1927,6 +1940,13 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
 
                                can_apply_edp_fast_boot = dc_validate_boot_timing(dc,
                                        edp_stream->sink, &edp_stream->timing);
+
+                               // For Mux-platform, the default value is false.
+                               // Disable fast boot during mux switching.
+                               // The flag would be clean after switching done.
+                               if (dc->is_switch_in_progress_dest && edp_link->is_dds)
+                                       can_apply_edp_fast_boot = false;
+
                                edp_stream->apply_edp_fast_boot_optimization = can_apply_edp_fast_boot;
                                if (can_apply_edp_fast_boot) {
                                        DC_LOG_EVENT_LINK_TRAINING("eDP fast boot Enable\n");
@@ -1970,6 +1990,10 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
        if (edp_with_sink_num)
                edp_link_with_sink = edp_links_with_sink[0];
 
+       // During a mux switch, powering down the HW blocks and then enabling
+       // the link via a DPCD SET_POWER write causes a brief flash
+       keep_edp_vdd_on |= dc->is_switch_in_progress_dest;
+
        if (!can_apply_edp_fast_boot && !can_apply_seamless_boot) {
                if (edp_link_with_sink && !keep_edp_vdd_on) {
                        /*turn off backlight before DP_blank and encoder powered down*/
index 5ba3999991b095639df440538d1a935414bcefaf..8ba934b83957b87e9cad4739343afe244eb32c80 100644 (file)
@@ -562,6 +562,19 @@ static void dcn31_reset_back_end_for_pipe(
        else if (pipe_ctx->stream_res.audio)
                dc->hwss.disable_audio_stream(pipe_ctx);
 
+       /* Temporary workaround to perform DSC programming ahead of pipe reset
+        * for smartmux/SPRS
+        * TODO: Remove SmartMux/SPRS checks once movement of DSC programming is generalized
+        */
+       if (pipe_ctx->stream->timing.flags.DSC) {
+               if ((pipe_ctx->stream->signal == SIGNAL_TYPE_EDP &&
+                       ((link->dc->config.smart_mux_version && link->dc->is_switch_in_progress_dest)
+                       || link->is_dds || link->skip_implict_edp_power_control)) &&
+                       (dc_is_dp_signal(pipe_ctx->stream->signal) ||
+                       dc_is_virtual_signal(pipe_ctx->stream->signal)))
+                       dc->link_srv->set_dsc_enable(pipe_ctx, false);
+       }
+
        /* free acquired resources */
        if (pipe_ctx->stream_res.audio) {
                /*disable az_endpoint*/
index 3a0795045bc61397277d65d4683706d15d144395..9df8030e37f79a898d0f4a1b9f2b1a44954a433d 100644 (file)
@@ -502,6 +502,9 @@ void get_hdr_visual_confirm_color(
 void get_mpctree_visual_confirm_color(
                struct pipe_ctx *pipe_ctx,
                struct tg_color *color);
+void get_smartmux_visual_confirm_color(
+       struct dc *dc,
+       struct tg_color *color);
 void get_vabc_visual_confirm_color(
        struct pipe_ctx *pipe_ctx,
        struct tg_color *color);
index 7d66e62b6be66fb4098626dd9d6921532175b92e..2c9a4a12bd8a7f6956adad50a9d8773044c323d2 100644 (file)
@@ -337,6 +337,8 @@ struct clk_mgr_funcs {
 
        bool (*is_dc_mode_present)(struct clk_mgr *clk_mgr);
 
+       uint32_t (*set_smartmux_switch)(struct clk_mgr *clk_mgr, uint32_t pins_to_set);
+
        unsigned int (*get_max_clock_khz)(struct clk_mgr *clk_mgr_base, enum clk_type clk_type);
 };
 
index bd51b279ad1484e911a2ab1fabe39445b1ce0fbb..8c8682f743d6fd28817e23804a1a9e855a5632d4 100644 (file)
@@ -140,7 +140,7 @@ void link_blank_dp_stream(struct dc_link *link, bool hw_init)
                                }
                }
 
-               if (((!link->wa_flags.dp_keep_receiver_powered) || hw_init) &&
+               if (((!dc->is_switch_in_progress_dest) && ((!link->wa_flags.dp_keep_receiver_powered) || hw_init)) &&
                        (link->type != dc_connection_none))
                        dpcd_write_rx_power_ctrl(link, false);
        }
@@ -2537,6 +2537,14 @@ void link_set_dpms_on(
                                !pipe_ctx->next_odm_pipe) {
                pipe_ctx->stream->dpms_off = false;
                update_psp_stream_config(pipe_ctx, false);
+
+               if (link->is_dds) {
+                       uint32_t post_oui_delay = 30; // 30ms
+
+                       dpcd_set_source_specific_data(link);
+                       msleep(post_oui_delay);
+               }
+
                return;
        }
 
@@ -2629,6 +2637,15 @@ void link_set_dpms_on(
                        dp_is_128b_132b_signal(pipe_ctx))
                update_sst_payload(pipe_ctx, true);
 
+       /* Corruption was observed on systems with display mux when stream gets
+        * enabled after the mux switch. Having a small delay between link
+        * training and stream unblank resolves the corruption issue.
+        * This is workaround.
+        */
+       if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP &&
+                       link->is_display_mux_present)
+               msleep(20);
+
        dc->hwss.unblank_stream(pipe_ctx,
                &pipe_ctx->stream->link->cur_link_settings);
 
index c5f4e803be842aada38506cead200237ecb69e1b..de1143dbbd25f83b15b25dcfc0455852371b8cc5 100644 (file)
@@ -539,10 +539,16 @@ static bool construct_phy(struct dc_link *link,
 
                break;
        case CONNECTOR_ID_EDP:
+               // If smartmux is supported, only create the link on the primary eDP.
+               // Dual eDP is not supported with smartmux.
+               if (!(!link->dc->config.smart_mux_version || dc_ctx->dc_edp_id_count == 0))
+                       goto create_fail;
+
                link->connector_signal = SIGNAL_TYPE_EDP;
 
                if (link->hpd_gpio) {
-                       if (!link->dc->config.allow_edp_hotplug_detection)
+                       if (!link->dc->config.allow_edp_hotplug_detection
+                               && !is_smartmux_suported(link))
                                link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
 
                        switch (link->dc->config.allow_edp_hotplug_detection) {
index 0f965380a9b4b926d38d937db08cf77d9d5e4f04..651926e547b9046edf89065fba0eb6d0626b2334 100644 (file)
@@ -1388,6 +1388,21 @@ void dpcd_set_source_specific_data(struct dc_link *link)
                struct dpcd_amd_signature amd_signature = {0};
                struct dpcd_amd_device_id amd_device_id = {0};
 
+               if (link->is_dds) {
+                       uint8_t dpcd_dp_edp_backlight_mode = 0;
+
+                       /*
+                        * Write 0 to bits 0:1 for dp_edp_backlight_mode_set register
+                        * if platform is DDS
+                        */
+                       core_link_read_dpcd(link, DP_EDP_BACKLIGHT_MODE_SET_REGISTER,
+                               &dpcd_dp_edp_backlight_mode, sizeof(uint8_t));
+                       dpcd_dp_edp_backlight_mode &= ~0x3;
+
+                       core_link_write_dpcd(link, DP_EDP_BACKLIGHT_MODE_SET_REGISTER,
+                               &dpcd_dp_edp_backlight_mode, sizeof(uint8_t));
+               }
+
                amd_device_id.device_id_byte1 =
                                (uint8_t)(link->ctx->asic_id.chip_id);
                amd_device_id.device_id_byte2 =
@@ -1543,6 +1558,10 @@ static bool dpcd_read_sink_ext_caps(struct dc_link *link)
                return false;
 
        link->dpcd_sink_ext_caps.raw = dpcd_data;
+       if (link->is_dds && !link->dpcd_sink_ext_caps.bits.oled) {
+               link->dpcd_sink_ext_caps.raw = 0;
+               return false;
+       }
 
        if (core_link_read_dpcd(link, DP_EDP_GENERAL_CAP_2, &edp_general_cap2, 1) != DC_OK)
                return false;
index a4258b5b77be88339c7931218981c6c61b5cc3ff..e7927b8f5ba35170adfaaa35580c0fe6a521b42d 100644 (file)
@@ -161,6 +161,9 @@ bool edp_set_backlight_level_nits(struct dc_link *link,
                        link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
                return false;
 
+       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) {
@@ -243,6 +246,8 @@ bool edp_get_backlight_level_nits(struct dc_link *link,
                        link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
                return false;
 
+       if (link->is_dds)
+               return false;
        if (!core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_CURRENT_PEAK,
                        dpcd_backlight_get.raw,
                        sizeof(union dpcd_source_backlight_get)))
@@ -269,6 +274,8 @@ bool edp_backlight_enable_aux(struct dc_link *link, bool enable)
                link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
                return false;
 
+       if (link->is_dds)
+               return true;
        if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_ENABLE,
                &backlight_enable, 1) != DC_OK)
                return false;
@@ -1194,6 +1201,16 @@ int edp_get_target_backlight_pwm(const struct dc_link *link)
        return (int) abm->funcs->get_target_backlight(abm);
 }
 
+bool is_smartmux_suported(struct dc_link *link)
+{
+       if (link->dc->caps.is_apu)
+               return false;
+       if (!link->dc->config.smart_mux_version)
+               return false;
+
+       return true;
+}
+
 static void edp_set_assr_enable(const struct dc *pDC, struct dc_link *link,
                struct link_resource *link_res, bool enable)
 {
index bcfa6ac5d4e7b6e1a2528ec423246321a6cdbda7..4a475d5b9dde77d140c86328119a71ed59c14a89 100644 (file)
@@ -30,6 +30,7 @@
 enum dp_panel_mode dp_get_panel_mode(struct dc_link *link);
 void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode);
 bool set_default_brightness_aux(struct dc_link *link);
+bool is_smartmux_suported(struct dc_link *link);
 void edp_panel_backlight_power_on(struct dc_link *link, bool wait_for_hpd);
 int edp_get_backlight_level(const struct dc_link *link);
 bool edp_get_backlight_level_nits(struct dc_link *link,
index 758a8aa31fbe81c909476e6cb0caab326f654ae9..391209a3bf29842bafe90be23f335a765b8db113 100644 (file)
@@ -79,4 +79,6 @@ bool psr_su_set_dsc_slice_height(struct dc *dc, struct dc_link *link,
 bool fill_custom_backlight_caps(unsigned int config_no,
                struct dm_acpi_atif_backlight_caps *caps);
 void reset_replay_dsync_error_count(struct dc_link *link);
+void change_replay_to_psr(struct dc_link *link);
+void change_psr_to_replay(struct dc_link *link);
 #endif /* MODULES_POWER_POWER_HELPERS_H_ */