summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/display
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2026-01-19 06:53:41 +1000
committerDave Airlie <airlied@redhat.com>2026-01-19 06:54:46 +1000
commitc098b1aa2fa60fad42df8a1a6250099329e33311 (patch)
tree59f8067c25de3a4e6bde2fb3bc067b6df2798ff1 /drivers/gpu/drm/amd/display
parent971c2b68bddb87f4929e66cd4563fca78b722210 (diff)
parent6a681cd9034587fe3550868bacfbd639d1c6891f (diff)
downloadlinux-next-c098b1aa2fa60fad42df8a1a6250099329e33311.tar.gz
linux-next-c098b1aa2fa60fad42df8a1a6250099329e33311.zip
Merge tag 'amd-drm-next-6.20-2026-01-16' of https://gitlab.freedesktop.org/agd5f/linux into drm-next
amd-drm-next-6.20-2026-01-16: amdgpu: - SR-IOV fixes - Rework SMU mailbox handling - Drop MMIO_REMAP domain - UserQ fixes - MES cleanups - Panel Replay updates - HDMI fixes - Backlight fixes - SMU 14.x fixes - SMU 15 updates amdkfd: - Fix a memory leak - Fixes for systems with non-4K pages - LDS/Scratch cleanup - MES process eviction fix Signed-off-by: Dave Airlie <airlied@redhat.com> From: Alex Deucher <alexander.deucher@amd.com> Link: https://patch.msgid.link/20260116202609.23107-1-alexander.deucher@amd.com
Diffstat (limited to 'drivers/gpu/drm/amd/display')
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c91
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h6
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c25
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c9
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc.c49
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c9
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_dp_types.h34
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_hw_types.h6
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_types.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c13
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c52
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/link_service.h12
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/Makefile2
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c7
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_detection.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_dpms.c8
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_factory.c19
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c49
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c43
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c343
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.h38
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c297
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h10
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c11
-rw-r--r--drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h54
-rw-r--r--drivers/gpu/drm/amd/display/include/dpcd_defs.h30
35 files changed, 796 insertions, 451 deletions
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 06b97029001b..cb13a2b0de62 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -1137,7 +1137,7 @@ static int amdgpu_dm_audio_component_get_eld(struct device *kdev, int port,
mutex_unlock(&adev->dm.audio_lock);
- DRM_DEBUG_KMS("Get ELD : idx=%d ret=%d en=%d\n", port, ret, *enabled);
+ drm_dbg_kms(adev_to_drm(adev), "Get ELD : idx=%d ret=%d en=%d\n", port, ret, *enabled);
return ret;
}
@@ -1231,7 +1231,7 @@ static void amdgpu_dm_audio_eld_notify(struct amdgpu_device *adev, int pin)
struct drm_audio_component *acomp = adev->dm.audio_component;
if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) {
- DRM_DEBUG_KMS("Notify ELD: %d\n", pin);
+ drm_dbg_kms(adev_to_drm(adev), "Notify ELD: %d\n", pin);
acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
pin, -1);
@@ -2377,7 +2377,7 @@ static int load_dmcu_fw(struct amdgpu_device *adev)
}
if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) {
- DRM_DEBUG_KMS("dm: DMCU firmware not supported on direct or SMU loading\n");
+ drm_dbg_kms(adev_to_drm(adev), "dm: DMCU firmware not supported on direct or SMU loading\n");
return 0;
}
@@ -2385,7 +2385,7 @@ static int load_dmcu_fw(struct amdgpu_device *adev)
"%s", fw_name_dmcu);
if (r == -ENODEV) {
/* DMCU firmware is not necessary, so don't raise a fuss if it's missing */
- DRM_DEBUG_KMS("dm: DMCU firmware not found\n");
+ drm_dbg_kms(adev_to_drm(adev), "dm: DMCU firmware not found\n");
adev->dm.fw_dmcu = NULL;
return 0;
}
@@ -2409,7 +2409,7 @@ static int load_dmcu_fw(struct amdgpu_device *adev)
adev->dm.dmcu_fw_version = le32_to_cpu(hdr->header.ucode_version);
- DRM_DEBUG_KMS("PSP loading DMCU firmware\n");
+ drm_dbg_kms(adev_to_drm(adev), "PSP loading DMCU firmware\n");
return 0;
}
@@ -4157,7 +4157,7 @@ static void schedule_hpd_rx_offload_work(struct amdgpu_device *adev, struct hpd_
offload_work->adev = adev;
queue_work(offload_wq->wq, &offload_work->work);
- DRM_DEBUG_KMS("queue work to handle hpd_rx offload work");
+ drm_dbg_kms(adev_to_drm(adev), "queue work to handle hpd_rx offload work");
}
static void handle_hpd_rx_irq(void *param)
@@ -4986,7 +4986,7 @@ static void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm,
caps->min_input_signal < 0 ||
spread > AMDGPU_DM_DEFAULT_MAX_BACKLIGHT ||
spread < AMDGPU_DM_MIN_SPREAD) {
- DRM_DEBUG_KMS("DM: Invalid backlight caps: min=%d, max=%d\n",
+ drm_dbg_kms(adev_to_drm(dm->adev), "DM: Invalid backlight caps: min=%d, max=%d\n",
caps->min_input_signal, caps->max_input_signal);
caps->caps_valid = false;
}
@@ -5279,6 +5279,8 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector)
struct amdgpu_dm_backlight_caps *caps;
char bl_name[16];
int min, max;
+ int real_brightness;
+ int init_brightness;
if (aconnector->bl_idx == -1)
return;
@@ -5303,6 +5305,8 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector)
} else
props.brightness = props.max_brightness = MAX_BACKLIGHT_LEVEL;
+ init_brightness = props.brightness;
+
if (caps->data_points && !(amdgpu_dc_debug_mask & DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE)) {
drm_info(drm, "Using custom brightness curve\n");
props.scale = BACKLIGHT_SCALE_NON_LINEAR;
@@ -5321,8 +5325,20 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector)
if (IS_ERR(dm->backlight_dev[aconnector->bl_idx])) {
drm_err(drm, "DM: Backlight registration failed!\n");
dm->backlight_dev[aconnector->bl_idx] = NULL;
- } else
+ } else {
+ /*
+ * dm->brightness[x] can be inconsistent just after startup until
+ * ops.get_brightness is called.
+ */
+ real_brightness =
+ amdgpu_dm_backlight_ops.get_brightness(dm->backlight_dev[aconnector->bl_idx]);
+
+ if (real_brightness != init_brightness) {
+ dm->actual_brightness[aconnector->bl_idx] = real_brightness;
+ dm->brightness[aconnector->bl_idx] = real_brightness;
+ }
drm_dbg_driver(drm, "DM: Registered Backlight device: %s\n", bl_name);
+ }
}
static int initialize_plane(struct amdgpu_display_manager *dm,
@@ -5515,7 +5531,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
}
break;
default:
- DRM_DEBUG_KMS("Unsupported DCN IP version for outbox: 0x%X\n",
+ drm_dbg_kms(adev_to_drm(adev), "Unsupported DCN IP version for outbox: 0x%X\n",
amdgpu_ip_version(adev, DCE_HWIP, 0));
}
@@ -5639,7 +5655,8 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
if (psr_feature_enabled) {
amdgpu_dm_set_psr_caps(link);
- drm_info(adev_to_drm(adev), "PSR support %d, DC PSR ver %d, sink PSR ver %d DPCD caps 0x%x su_y_granularity %d\n",
+ drm_info(adev_to_drm(adev), "%s: PSR support %d, DC PSR ver %d, sink PSR ver %d DPCD caps 0x%x su_y_granularity %d\n",
+ aconnector->base.name,
link->psr_settings.psr_feature_enabled,
link->psr_settings.psr_version,
link->dpcd_caps.psr_info.psr_version,
@@ -6417,7 +6434,8 @@ ffu:
&flip_addrs->dirty_rect_count, true);
}
-static void update_stream_scaling_settings(const struct drm_display_mode *mode,
+static void update_stream_scaling_settings(struct drm_device *dev,
+ const struct drm_display_mode *mode,
const struct dm_connector_state *dm_state,
struct dc_stream_state *stream)
{
@@ -6467,8 +6485,8 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode,
stream->src = src;
stream->dst = dst;
- DRM_DEBUG_KMS("Destination Rectangle x:%d y:%d width:%d height:%d\n",
- dst.x, dst.y, dst.width, dst.height);
+ drm_dbg_kms(dev, "Destination Rectangle x:%d y:%d width:%d height:%d\n",
+ dst.x, dst.y, dst.width, dst.height);
}
@@ -7356,7 +7374,7 @@ create_stream_for_sink(struct drm_connector *connector,
apply_dsc_policy_for_stream(aconnector, sink, stream, &dsc_caps);
#endif
- update_stream_scaling_settings(&mode, dm_state, stream);
+ update_stream_scaling_settings(dev, &mode, dm_state, stream);
fill_audio_info(
&stream->audio_info,
@@ -8091,7 +8109,7 @@ create_validate_stream_for_sink(struct drm_connector *connector,
dc_result = dm_validate_stream_and_context(adev->dm.dc, stream);
if (dc_result != DC_OK) {
- DRM_DEBUG_KMS("Pruned mode %d x %d (clk %d) %s %s -- %s\n",
+ drm_dbg_kms(connector->dev, "Pruned mode %d x %d (clk %d) %s %s -- %s\n",
drm_mode->hdisplay,
drm_mode->vdisplay,
drm_mode->clock,
@@ -8443,7 +8461,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
drm_dp_atomic_find_time_slots(state, mst_mgr, mst_port,
dm_new_connector_state->pbn);
if (dm_new_connector_state->vcpi_slots < 0) {
- DRM_DEBUG_ATOMIC("failed finding vcpi slots: %d\n", (int)dm_new_connector_state->vcpi_slots);
+ drm_dbg_atomic(connector->dev, "failed finding vcpi slots: %d\n", (int)dm_new_connector_state->vcpi_slots);
return dm_new_connector_state->vcpi_slots;
}
return 0;
@@ -8943,9 +8961,18 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
mutex_init(&aconnector->hpd_lock);
mutex_init(&aconnector->handle_mst_msg_ready);
- aconnector->hdmi_hpd_debounce_delay_ms = AMDGPU_DM_HDMI_HPD_DEBOUNCE_MS;
- INIT_DELAYED_WORK(&aconnector->hdmi_hpd_debounce_work, hdmi_hpd_debounce_work);
- aconnector->hdmi_prev_sink = NULL;
+ /*
+ * If HDMI HPD debounce delay is set, use the minimum between selected
+ * value and AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS
+ */
+ if (amdgpu_hdmi_hpd_debounce_delay_ms) {
+ aconnector->hdmi_hpd_debounce_delay_ms = min(amdgpu_hdmi_hpd_debounce_delay_ms,
+ AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS);
+ INIT_DELAYED_WORK(&aconnector->hdmi_hpd_debounce_work, hdmi_hpd_debounce_work);
+ aconnector->hdmi_prev_sink = NULL;
+ } else {
+ aconnector->hdmi_hpd_debounce_delay_ms = 0;
+ }
/*
* configure support HPD hot plug connector_>polled default value is 0
@@ -9627,7 +9654,7 @@ static void update_freesync_state_on_stream(
new_stream->allow_freesync = mod_freesync_get_freesync_enabled(&vrr_params);
if (new_crtc_state->freesync_vrr_info_changed)
- DRM_DEBUG_KMS("VRR packet update: crtc=%u enabled=%d state=%d",
+ drm_dbg_kms(adev_to_drm(adev), "VRR packet update: crtc=%u enabled=%d state=%d",
new_crtc_state->base.crtc->base.id,
(int)new_crtc_state->base.vrr_enabled,
(int)vrr_params.state);
@@ -10893,7 +10920,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
stream_update.stream = dm_new_crtc_state->stream;
if (scaling_changed) {
- update_stream_scaling_settings(&dm_new_con_state->base.crtc->mode,
+ update_stream_scaling_settings(dev, &dm_new_con_state->base.crtc->mode,
dm_new_con_state, dm_new_crtc_state->stream);
stream_update.src = dm_new_crtc_state->stream->src;
@@ -11573,7 +11600,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
dc_stream_retain(new_stream);
- DRM_DEBUG_ATOMIC("Enabling DRM crtc: %d\n",
+ drm_dbg_atomic(adev_to_drm(adev), "Enabling DRM crtc: %d\n",
crtc->base.id);
if (dc_state_add_stream(
@@ -11612,7 +11639,7 @@ skip_modeset:
/* Scaling or underscan settings */
if (is_scaling_state_different(dm_old_conn_state, dm_new_conn_state) ||
drm_atomic_crtc_needs_modeset(new_crtc_state))
- update_stream_scaling_settings(
+ update_stream_scaling_settings(adev_to_drm(adev),
&new_crtc_state->mode, dm_new_conn_state, dm_new_crtc_state->stream);
/* ABM settings */
@@ -11803,14 +11830,14 @@ static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc,
if (fb->width > new_acrtc->max_cursor_width ||
fb->height > new_acrtc->max_cursor_height) {
- DRM_DEBUG_ATOMIC("Bad cursor FB size %dx%d\n",
+ drm_dbg_atomic(adev_to_drm(adev), "Bad cursor FB size %dx%d\n",
new_plane_state->fb->width,
new_plane_state->fb->height);
return -EINVAL;
}
if (new_plane_state->src_w != fb->width << 16 ||
new_plane_state->src_h != fb->height << 16) {
- DRM_DEBUG_ATOMIC("Cropping not supported for cursor plane\n");
+ drm_dbg_atomic(adev_to_drm(adev), "Cropping not supported for cursor plane\n");
return -EINVAL;
}
@@ -11818,7 +11845,7 @@ static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc,
pitch = fb->pitches[0] / fb->format->cpp[0];
if (fb->width != pitch) {
- DRM_DEBUG_ATOMIC("Cursor FB width %d doesn't match pitch %d",
+ drm_dbg_atomic(adev_to_drm(adev), "Cursor FB width %d doesn't match pitch %d",
fb->width, pitch);
return -EINVAL;
}
@@ -11830,7 +11857,7 @@ static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc,
/* FB pitch is supported by cursor plane */
break;
default:
- DRM_DEBUG_ATOMIC("Bad cursor FB pitch %d px\n", pitch);
+ drm_dbg_atomic(adev_to_drm(adev), "Bad cursor FB pitch %d px\n", pitch);
return -EINVAL;
}
@@ -11848,7 +11875,7 @@ static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc,
AMDGPU_TILING_GET(afb->tiling_flags, MICRO_TILE_MODE) == 0;
}
if (!linear) {
- DRM_DEBUG_ATOMIC("Cursor FB not linear");
+ drm_dbg_atomic(adev_to_drm(adev), "Cursor FB not linear");
return -EINVAL;
}
}
@@ -11875,7 +11902,7 @@ static int dm_check_native_cursor_state(struct drm_crtc *new_plane_crtc,
new_acrtc = to_amdgpu_crtc(new_plane_crtc);
if (new_plane_state->src_x != 0 || new_plane_state->src_y != 0) {
- DRM_DEBUG_ATOMIC("Cropping not supported for cursor plane\n");
+ drm_dbg_atomic(new_plane_crtc->dev, "Cropping not supported for cursor plane\n");
return -EINVAL;
}
@@ -11974,7 +12001,7 @@ static int dm_update_plane_state(struct dc *dc,
if (!dm_old_crtc_state->stream)
return 0;
- DRM_DEBUG_ATOMIC("Disabling DRM plane: %d on DRM crtc %d\n",
+ drm_dbg_atomic(old_plane_crtc->dev, "Disabling DRM plane: %d on DRM crtc %d\n",
plane->base.id, old_plane_crtc->base.id);
ret = dm_atomic_get_state(state, &dm_state);
@@ -12027,7 +12054,7 @@ static int dm_update_plane_state(struct dc *dc,
goto out;
}
- DRM_DEBUG_ATOMIC("Enabling DRM plane: %d on DRM crtc %d\n",
+ drm_dbg_atomic(new_plane_crtc->dev, "Enabling DRM plane: %d on DRM crtc %d\n",
plane->base.id, new_plane_crtc->base.id);
ret = fill_dc_plane_attributes(
@@ -13119,7 +13146,7 @@ static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector,
amd_vsdb->version == HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3) {
vsdb_info->replay_mode = (amd_vsdb->feature_caps & AMD_VSDB_VERSION_3_FEATURECAP_REPLAYMODE) ? true : false;
vsdb_info->amd_vsdb_version = HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3;
- DRM_DEBUG_KMS("Panel supports Replay Mode: %d\n", vsdb_info->replay_mode);
+ drm_dbg_kms(aconnector->base.dev, "Panel supports Replay Mode: %d\n", vsdb_info->replay_mode);
return true;
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index ab363f2f6d47..115efd8ec68b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -59,7 +59,10 @@
#define AMDGPU_HDR_MULT_DEFAULT (0x100000000LL)
-#define AMDGPU_DM_HDMI_HPD_DEBOUNCE_MS 1500
+/*
+ * Maximum HDMI HPD debounce delay in milliseconds
+ */
+#define AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS 5000
/*
#include "include/amdgpu_dal_power_if.h"
#include "amdgpu_dm_irq.h"
@@ -815,6 +818,7 @@ struct amdgpu_dm_connector {
int sr_skip_count;
bool disallow_edp_enter_psr;
+ bool disallow_edp_enter_replay;
/* Record progress status of mst*/
uint8_t mst_status;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
index 327b20055729..5851f2d55dde 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
@@ -32,6 +32,7 @@
#include "dc.h"
#include "amdgpu_securedisplay.h"
#include "amdgpu_dm_psr.h"
+#include "amdgpu_dm_replay.h"
static const char *const pipe_crc_sources[] = {
"none",
@@ -502,6 +503,7 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc,
{
struct amdgpu_device *adev = drm_to_adev(crtc->dev);
struct dc_stream_state *stream_state = dm_crtc_state->stream;
+ struct amdgpu_dm_connector *aconnector = NULL;
bool enable = amdgpu_dm_is_valid_crc_source(source);
int ret = 0;
@@ -509,11 +511,22 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc,
if (!stream_state)
return -EINVAL;
+ /* Get connector from stream */
+ aconnector = (struct amdgpu_dm_connector *)stream_state->dm_stream_context;
+
mutex_lock(&adev->dm.dc_lock);
- /* For PSR1, check that the panel has exited PSR */
- if (stream_state->link->psr_settings.psr_version < DC_PSR_VERSION_SU_1)
- amdgpu_dm_psr_wait_disable(stream_state);
+
+ if (enable) {
+ /* For PSR1, check that the panel has exited PSR */
+ if (stream_state->link->psr_settings.psr_version < DC_PSR_VERSION_SU_1)
+ amdgpu_dm_psr_wait_disable(stream_state);
+
+ /* Set flag to disallow enter replay when CRC source is enabled */
+ if (aconnector)
+ aconnector->disallow_edp_enter_replay = true;
+ amdgpu_dm_replay_disable(stream_state);
+ }
/* Enable or disable CRTC CRC generation */
if (dm_is_crc_source_crtc(source) || source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE) {
@@ -536,6 +549,12 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc,
DYN_EXPANSION_AUTO);
}
+ if (!enable) {
+ /* Clear flag to allow enter replay when CRC source is disabled */
+ if (aconnector)
+ aconnector->disallow_edp_enter_replay = false;
+ }
+
unlock:
mutex_unlock(&adev->dm.dc_lock);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c
index da94e3544b65..8c150b001105 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c
@@ -154,14 +154,21 @@ bool amdgpu_dm_replay_enable(struct dc_stream_state *stream, bool wait)
{
bool replay_active = true;
struct dc_link *link = NULL;
+ struct amdgpu_dm_connector *aconnector = NULL;
if (stream == NULL)
return false;
+ /* Check if replay is disabled by connector flag */
+ aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
+ if (!aconnector || aconnector->disallow_edp_enter_replay) {
+ return false;
+ }
+
link = stream->link;
if (link) {
- link->dc->link_srv->edp_setup_replay(link, stream);
+ link->dc->link_srv->dp_setup_replay(link, stream);
link->dc->link_srv->edp_set_coasting_vtotal(link, stream->timing.v_total, 0);
DRM_DEBUG_DRIVER("Enabling replay...\n");
link->dc->link_srv->edp_set_replay_allow_active(link, &replay_active, wait, false, NULL);
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 57f6a4c8afff..aba5ad2a7a33 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -7246,6 +7246,14 @@ static bool update_planes_and_stream_prepare_v3_intermediate_seamless(
);
}
+static void transition_countdown_init(struct dc *dc)
+{
+ dc->check_config.transition_countdown_to_steady_state =
+ dc->debug.num_fast_flips_to_steady_state_override ?
+ dc->debug.num_fast_flips_to_steady_state_override :
+ NUM_FAST_FLIPS_TO_STEADY_STATE;
+}
+
static bool update_planes_and_stream_prepare_v3(
struct dc_update_scratch_space *scratch
)
@@ -7305,9 +7313,17 @@ static bool update_planes_and_stream_prepare_v3(
);
if (seamless) {
scratch->flow = UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS;
+ if (scratch->dc->check_config.deferred_transition_state)
+ /* reset countdown as steady state not reached */
+ transition_countdown_init(scratch->dc);
return true;
}
+ if (!scratch->dc->debug.disable_deferred_minimal_transitions) {
+ scratch->dc->check_config.deferred_transition_state = true;
+ transition_countdown_init(scratch->dc);
+ }
+
scratch->intermediate_context = create_minimal_transition_state(
scratch->dc,
scratch->new_context,
@@ -7351,7 +7367,8 @@ static bool update_planes_and_stream_prepare_v3(
static void update_planes_and_stream_execute_v3_commit(
const struct dc_update_scratch_space *scratch,
bool intermediate_update,
- bool intermediate_context
+ bool intermediate_context,
+ bool use_stream_update
)
{
commit_planes_for_stream(
@@ -7359,7 +7376,7 @@ static void update_planes_and_stream_execute_v3_commit(
intermediate_update ? scratch->intermediate_updates : scratch->surface_updates,
intermediate_update ? scratch->intermediate_count : scratch->surface_count,
scratch->stream,
- intermediate_context ? NULL : scratch->stream_update,
+ use_stream_update ? scratch->stream_update : NULL,
intermediate_context ? UPDATE_TYPE_FULL : scratch->update_type,
// `dc->current_state` only used in `NO_NEW_CONTEXT`, where it is equal to `new_context`
intermediate_context ? scratch->intermediate_context : scratch->new_context
@@ -7385,15 +7402,16 @@ static void update_planes_and_stream_execute_v3(
case UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FULL:
case UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS:
- update_planes_and_stream_execute_v3_commit(scratch, false, false);
+ update_planes_and_stream_execute_v3_commit(scratch, false, false, true);
break;
case UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_NEW:
- update_planes_and_stream_execute_v3_commit(scratch, false, true);
+ update_planes_and_stream_execute_v3_commit(scratch, false, true,
+ scratch->dc->check_config.deferred_transition_state);
break;
case UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_CURRENT:
- update_planes_and_stream_execute_v3_commit(scratch, true, true);
+ update_planes_and_stream_execute_v3_commit(scratch, true, true, false);
break;
case UPDATE_V3_FLOW_INVALID:
@@ -7402,13 +7420,6 @@ static void update_planes_and_stream_execute_v3(
}
}
-static void update_planes_and_stream_cleanup_v3_new_context(
- struct dc_update_scratch_space *scratch
-)
-{
- swap_and_release_current_context(scratch->dc, scratch->new_context, scratch->stream);
-}
-
static void update_planes_and_stream_cleanup_v3_release_minimal(
struct dc_update_scratch_space *scratch,
bool backup
@@ -7439,17 +7450,23 @@ static bool update_planes_and_stream_cleanup_v3(
switch (scratch->flow) {
case UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FAST:
case UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FULL:
- // No cleanup required
+ if (scratch->dc->check_config.transition_countdown_to_steady_state)
+ scratch->dc->check_config.transition_countdown_to_steady_state--;
break;
case UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS:
- update_planes_and_stream_cleanup_v3_new_context(scratch);
+ swap_and_release_current_context(scratch->dc, scratch->new_context, scratch->stream);
break;
case UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_NEW:
update_planes_and_stream_cleanup_v3_intermediate(scratch, false);
- scratch->flow = UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS;
- return true;
+ if (scratch->dc->check_config.deferred_transition_state) {
+ dc_state_release(scratch->new_context);
+ } else {
+ scratch->flow = UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS;
+ return true;
+ }
+ break;
case UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_CURRENT:
update_planes_and_stream_cleanup_v3_intermediate(scratch, true);
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c
index a8d7228907c2..7bb4504889be 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c
@@ -493,24 +493,24 @@ bool dc_link_get_replay_state(const struct dc_link *link, uint64_t *state)
bool dc_link_set_pr_enable(struct dc_link *link, bool enable)
{
- return link->dc->link_srv->edp_pr_enable(link, enable);
+ return link->dc->link_srv->dp_pr_enable(link, enable);
}
bool dc_link_update_pr_state(struct dc_link *link,
struct dmub_cmd_pr_update_state_data *update_state_data)
{
- return link->dc->link_srv->edp_pr_update_state(link, update_state_data);
+ return link->dc->link_srv->dp_pr_update_state(link, update_state_data);
}
bool dc_link_set_pr_general_cmd(struct dc_link *link,
struct dmub_cmd_pr_general_cmd_data *general_cmd_data)
{
- return link->dc->link_srv->edp_pr_set_general_cmd(link, general_cmd_data);
+ return link->dc->link_srv->dp_pr_set_general_cmd(link, general_cmd_data);
}
bool dc_link_get_pr_state(const struct dc_link *link, uint64_t *state)
{
- return link->dc->link_srv->edp_pr_get_state(link, state);
+ return link->dc->link_srv->dp_pr_get_state(link, state);
}
bool dc_link_wait_for_t12(struct dc_link *link)
@@ -549,4 +549,3 @@ void dc_link_get_alpm_support(struct dc_link *link,
{
link->dc->link_srv->edp_get_alpm_support(link, auxless_support, auxwake_support);
}
-
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 69fa7fc02fa8..fc3dd1054710 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -63,7 +63,7 @@ struct dcn_dsc_reg_state;
struct dcn_optc_reg_state;
struct dcn_dccg_reg_state;
-#define DC_VER "3.2.364"
+#define DC_VER "3.2.365"
/**
* MAX_SURFACES - representative of the upper bound of surfaces that can be piped to a single CRTC
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
index 602655dd1323..2dc6ae6b5bea 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
@@ -999,6 +999,7 @@ void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv)
DC_LOG_DEBUG(" is_traceport_en : %d", dc_dmub_srv->dmub->debug.is_traceport_en);
DC_LOG_DEBUG(" is_cw0_en : %d", dc_dmub_srv->dmub->debug.is_cw0_enabled);
DC_LOG_DEBUG(" is_cw6_en : %d", dc_dmub_srv->dmub->debug.is_cw6_enabled);
+ DC_LOG_DEBUG(" is_pwait : %d", dc_dmub_srv->dmub->debug.is_pwait);
}
static bool dc_dmub_should_update_cursor_data(struct pipe_ctx *pipe_ctx)
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
index 273610d85438..5e3646b7550c 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
@@ -1167,6 +1167,25 @@ union dpcd_panel_replay_capability_supported {
unsigned char raw;
};
+union dpcd_panel_replay_capability {
+ struct {
+ unsigned char RESERVED :2;
+ unsigned char DSC_DECODE_NOT_SUPPORTED :1;
+ unsigned char ASYNC_VIDEO_TIMING_NOT_SUPPORTED :1;
+ unsigned char DSC_CRC_OF_MULTI_SU_SUPPORTED :1;
+ unsigned char PR_SU_GRANULARITY_NEEDED :1;
+ unsigned char SU_Y_GRANULARITY_EXT_CAP_SUPPORTED :1;
+ unsigned char LINK_OFF_SUPPORTED_IN_PR_ACTIVE :1;
+ } bits;
+ unsigned char raw;
+};
+
+struct dpcd_panel_replay_selective_update_info {
+ uint16_t pr_su_x_granularity;
+ uint8_t pr_su_y_granularity;
+ uint16_t pr_su_y_granularity_extended_caps;
+};
+
enum dpcd_downstream_port_max_bpc {
DOWN_STREAM_MAX_8BPC = 0,
DOWN_STREAM_MAX_10BPC,
@@ -1290,7 +1309,9 @@ struct dpcd_caps {
struct edp_psr_info psr_info;
struct replay_info pr_info;
- union dpcd_panel_replay_capability_supported pr_caps_supported;
+ union dpcd_panel_replay_capability_supported vesa_replay_caps_supported;
+ union dpcd_panel_replay_capability vesa_replay_caps;
+ struct dpcd_panel_replay_selective_update_info vesa_replay_su_info;
uint16_t edp_oled_emission_rate;
union dp_receive_port0_cap receive_port0_cap;
/* Indicates the number of SST links supported by MSO (Multi-Stream Output) */
@@ -1402,6 +1423,17 @@ union dpcd_sink_active_vtotal_control_mode {
unsigned char raw;
};
+union pr_error_status {
+ struct {
+ unsigned char LINK_CRC_ERROR :1;
+ unsigned char RFB_STORAGE_ERROR :1;
+ unsigned char VSC_SDP_ERROR :1;
+ unsigned char ASSDP_MISSING_ERROR :1;
+ unsigned char RESERVED :4;
+ } bits;
+ unsigned char raw;
+};
+
union psr_error_status {
struct {
unsigned char LINK_CRC_ERROR :1;
diff --git a/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h b/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h
index b015e80672ec..fcd3ab4b0045 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h
@@ -41,7 +41,7 @@
/* kHZ*/
#define DP_ADAPTOR_DVI_MAX_TMDS_CLK 165000
/* kHZ*/
-#define DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK 165000
+#define DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK 340000
struct dp_hdmi_dongle_signature_data {
int8_t id[15];/* "DP-HDMI ADAPTOR"*/
diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
index 667852517246..cfa569a7bff1 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
@@ -491,6 +491,12 @@ struct dc_cursor_position {
* for each plane.
*/
bool translate_by_source;
+
+ /**
+ * @use_viewport_for_clip: Use viewport position for clip_x calculation
+ * instead of clip_rect. Required to protect against clip being overwritten
+ */
+ bool use_viewport_for_clip;
};
struct dc_cursor_mi_param {
diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h
index b3b785f1897d..bb1387233bd8 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_types.h
@@ -1101,7 +1101,6 @@ enum replay_FW_Message_type {
Replay_Set_Residency_Frameupdate_Timer,
Replay_Set_Pseudo_VTotal,
Replay_Disabled_Adaptive_Sync_SDP,
- Replay_Set_Version,
Replay_Set_General_Cmd,
};
@@ -1224,6 +1223,8 @@ struct replay_settings {
uint32_t replay_desync_error_fail_count;
/* The frame skip number dal send to DMUB */
uint16_t frame_skip_number;
+ /* Current Panel Replay event */
+ uint32_t replay_events;
};
/* To split out "global" and "per-panel" config settings.
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c
index 5bfa2b0d2afd..7116fdd4c7ec 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c
@@ -69,7 +69,7 @@ bool dmub_hw_lock_mgr_does_link_require_lock(const struct dc *dc, const struct d
if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1)
return true;
- if (link->replay_settings.replay_feature_enabled)
+ if (link->replay_settings.replay_feature_enabled && dc_is_embedded_signal(link->connector_signal))
return true;
if (link->psr_settings.psr_version == DC_PSR_VERSION_1) {
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c
index cf1372aaff6c..fd8244c94687 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c
@@ -387,19 +387,6 @@ static void dmub_replay_send_cmd(struct dmub_replay *dmub,
cmd.replay_disabled_adaptive_sync_sdp.data.force_disabled =
cmd_element->disabled_adaptive_sync_sdp_data.force_disabled;
break;
- case Replay_Set_Version:
- //Header
- cmd.replay_set_version.header.sub_type =
- DMUB_CMD__REPLAY_SET_VERSION;
- cmd.replay_set_version.header.payload_bytes =
- sizeof(struct dmub_rb_cmd_replay_set_version) -
- sizeof(struct dmub_cmd_header);
- //Cmd Body
- cmd.replay_set_version.replay_set_version_data.panel_inst =
- cmd_element->version_data.panel_inst;
- cmd.replay_set_version.replay_set_version_data.version =
- cmd_element->version_data.version;
- break;
case Replay_Set_General_Cmd:
//Header
cmd.replay_set_general_cmd.header.sub_type =
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
index fa62e40a9858..8a23763ca98e 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
@@ -3666,7 +3666,11 @@ void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx)
int y_plane = pipe_ctx->plane_state->dst_rect.y;
int x_pos = pos_cpy.x;
int y_pos = pos_cpy.y;
- int clip_x = pipe_ctx->plane_state->clip_rect.x;
+ bool is_primary_plane = (pipe_ctx->plane_state->layer_index == 0);
+
+ int clip_x = (pos_cpy.use_viewport_for_clip && is_primary_plane &&
+ !odm_combine_on && !pipe_split_on && param.viewport.x != 0)
+ ? param.viewport.x : pipe_ctx->plane_state->clip_rect.x;
int clip_width = pipe_ctx->plane_state->clip_rect.width;
if ((pipe_ctx->top_pipe != NULL) || (pipe_ctx->bottom_pipe != NULL)) {
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
index 1271bf55dac3..2675d7dca586 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
@@ -1727,3 +1727,55 @@ void dcn35_program_cursor_offload_now(struct dc *dc, const struct pipe_ctx *pipe
{
dc_dmub_srv_program_cursor_now(dc, pipe);
}
+
+static void disable_link_output_symclk_on_tx_off(struct dc_link *link, enum dp_link_encoding link_encoding)
+{
+ struct dc *dc = link->ctx->dc;
+ struct pipe_ctx *pipe_ctx = NULL;
+ uint8_t i;
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
+ if (pipe_ctx->stream && pipe_ctx->stream->link == link && pipe_ctx->top_pipe == NULL) {
+ pipe_ctx->clock_source->funcs->program_pix_clk(
+ pipe_ctx->clock_source,
+ &pipe_ctx->stream_res.pix_clk_params,
+ link_encoding,
+ &pipe_ctx->pll_settings);
+ break;
+ }
+ }
+}
+
+void dcn35_disable_link_output(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal)
+{
+ struct dc *dc = link->ctx->dc;
+ const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
+ struct dmcu *dmcu = dc->res_pool->dmcu;
+
+ if (signal == SIGNAL_TYPE_EDP &&
+ link->dc->hwss.edp_backlight_control &&
+ !link->skip_implict_edp_power_control)
+ link->dc->hwss.edp_backlight_control(link, false);
+ else if (dmcu != NULL && dmcu->funcs->lock_phy)
+ dmcu->funcs->lock_phy(dmcu);
+
+ if (dc_is_tmds_signal(signal) && link->phy_state.symclk_ref_cnts.otg > 0) {
+ disable_link_output_symclk_on_tx_off(link, DP_UNKNOWN_ENCODING);
+ link->phy_state.symclk_state = SYMCLK_ON_TX_OFF;
+ } else {
+ link_hwss->disable_link_output(link, link_res, signal);
+ link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
+ }
+ /*
+ * Add the logic to extract BOTH power up and power down sequences
+ * from enable/disable link output and only call edp panel control
+ * in enable_link_dp and disable_link_dp once.
+ */
+ if (dmcu != NULL && dmcu->funcs->unlock_phy)
+ dmcu->funcs->unlock_phy(dmcu);
+
+ dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
index 1ff41dba556c..e3459546a908 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
@@ -108,5 +108,8 @@ void dcn35_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe
void dcn35_notify_cursor_offload_drr_update(struct dc *dc, struct dc_state *context,
const struct dc_stream_state *stream);
void dcn35_program_cursor_offload_now(struct dc *dc, const struct pipe_ctx *pipe);
+void dcn35_disable_link_output(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal);
#endif /* __DC_HWSS_DCN35_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
index 5a66c9db2670..81bd36f3381d 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
@@ -113,7 +113,7 @@ static const struct hw_sequencer_funcs dcn35_funcs = {
.enable_lvds_link_output = dce110_enable_lvds_link_output,
.enable_tmds_link_output = dce110_enable_tmds_link_output,
.enable_dp_link_output = dce110_enable_dp_link_output,
- .disable_link_output = dcn32_disable_link_output,
+ .disable_link_output = dcn35_disable_link_output,
.z10_restore = dcn35_z10_restore,
.z10_save_init = dcn31_z10_save_init,
.set_disp_pattern_generator = dcn30_set_disp_pattern_generator,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
index b7593b886dc6..22c1d5e68420 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
@@ -287,6 +287,8 @@ void dcn401_init_hw(struct dc *dc)
for (i = 0; i < dc->link_count; i++) {
struct dc_link *link = dc->links[i];
+ if (link->ep_type != DISPLAY_ENDPOINT_PHY)
+ continue;
if (link->link_enc->funcs->is_dig_enabled &&
link->link_enc->funcs->is_dig_enabled(link->link_enc) &&
hws->funcs.power_down) {
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
index 500a601e99b5..1e6ffd86a4c0 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
@@ -333,6 +333,7 @@ struct dccg_funcs {
void (*set_ref_dscclk)(struct dccg *dccg, uint32_t dsc_inst);
void (*dccg_root_gate_disable_control)(struct dccg *dccg, uint32_t pipe_idx, uint32_t disable_clock_gating);
void (*dccg_read_reg_state)(struct dccg *dccg, struct dcn_dccg_reg_state *dccg_reg_state);
+ void (*dccg_enable_global_fgcg)(struct dccg *dccg, bool enable);
};
#endif //__DAL_DCCG_H__
diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_service.h b/drivers/gpu/drm/amd/display/dc/inc/link_service.h
index 4b092a9ee4c6..57bb82e94942 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/link_service.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/link_service.h
@@ -283,8 +283,6 @@ struct link_service {
bool (*edp_set_replay_allow_active)(struct dc_link *dc_link,
const bool *enable, bool wait, bool force_static,
const unsigned int *power_opts);
- bool (*edp_setup_replay)(struct dc_link *link,
- const struct dc_stream_state *stream);
bool (*edp_send_replay_cmd)(struct dc_link *link,
enum replay_FW_Message_type msg,
union dmub_replay_cmd_set *cmd_data);
@@ -304,10 +302,12 @@ struct link_service {
bool (*edp_receiver_ready_T9)(struct dc_link *link);
bool (*edp_receiver_ready_T7)(struct dc_link *link);
bool (*edp_power_alpm_dpcd_enable)(struct dc_link *link, bool enable);
- bool (*edp_pr_enable)(struct dc_link *link, bool enable);
- bool (*edp_pr_update_state)(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data);
- bool (*edp_pr_set_general_cmd)(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data);
- bool (*edp_pr_get_state)(const struct dc_link *link, uint64_t *state);
+ bool (*dp_setup_replay)(struct dc_link *link, const struct dc_stream_state *stream);
+ bool (*dp_pr_get_panel_inst)(const struct dc *dc, const struct dc_link *link, unsigned int *inst_out);
+ bool (*dp_pr_enable)(struct dc_link *link, bool enable);
+ bool (*dp_pr_update_state)(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data);
+ bool (*dp_pr_set_general_cmd)(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data);
+ bool (*dp_pr_get_state)(const struct dc_link *link, uint64_t *state);
void (*edp_set_panel_power)(struct dc_link *link, bool powerOn);
diff --git a/drivers/gpu/drm/amd/display/dc/link/Makefile b/drivers/gpu/drm/amd/display/dc/link/Makefile
index 84c7af5fa589..84dace27daf7 100644
--- a/drivers/gpu/drm/amd/display/dc/link/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/link/Makefile
@@ -56,7 +56,7 @@ LINK_PROTOCOLS = link_hpd.o link_ddc.o link_dpcd.o link_dp_dpia.o \
link_dp_training.o link_dp_training_8b_10b.o link_dp_training_128b_132b.o \
link_dp_training_dpia.o link_dp_training_auxless.o \
link_dp_training_fixed_vs_pe_retimer.o link_dp_phy.o link_dp_capability.o \
-link_edp_panel_control.o link_dp_irq_handler.o link_dp_dpia_bw.o
+link_edp_panel_control.o link_dp_panel_replay.o link_dp_irq_handler.o link_dp_dpia_bw.o
AMD_DAL_LINK_PROTOCOLS = $(addprefix $(AMDDALPATH)/dc/link/protocols/, \
$(LINK_PROTOCOLS))
diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c
index 5a547d41d4a1..693d852b1c40 100644
--- a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c
+++ b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c
@@ -70,6 +70,7 @@ static void dp_retrain_link_dp_test(struct dc_link *link,
struct dc_state *state = link->dc->current_state;
struct dc_stream_update stream_update = { 0 };
bool dpms_off = false;
+ bool needs_divider_update = false;
bool was_hpo_acquired = resource_is_hpo_acquired(link->dc->current_state);
bool is_hpo_acquired;
uint8_t count;
@@ -79,6 +80,10 @@ static void dp_retrain_link_dp_test(struct dc_link *link,
int num_streams_on_link = 0;
struct dc *dc = (struct dc *)link->dc;
+ needs_divider_update = (link->dc->link_srv->dp_get_encoding_format(link_setting) !=
+ link->dc->link_srv->dp_get_encoding_format((const struct dc_link_settings *) &link->cur_link_settings))
+ || link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA;
+
udelay(100);
link_get_master_pipes_with_dpms_on(link, state, &count, pipes);
@@ -95,7 +100,7 @@ static void dp_retrain_link_dp_test(struct dc_link *link,
pipes[i]->stream_res.tg->funcs->disable_crtc(pipes[i]->stream_res.tg);
}
- if (link->dc->res_pool->funcs->update_dc_state_for_encoder_switch) {
+ if (needs_divider_update && link->dc->res_pool->funcs->update_dc_state_for_encoder_switch) {
link->dc->res_pool->funcs->update_dc_state_for_encoder_switch(link,
link_setting, count,
*pipes, &audio_output[0]);
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c
index f24365395cd9..578509e8d0e2 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c
+++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c
@@ -335,7 +335,7 @@ static void query_dp_dual_mode_adaptor(
/* Assume we have no valid DP passive dongle connected */
*dongle = DISPLAY_DONGLE_NONE;
- sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK;
+ sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_DVI_MAX_TMDS_CLK;
/* Read DP-HDMI dongle I2c (no response interpreted as DP-DVI dongle)*/
if (!i2c_read(
@@ -391,6 +391,8 @@ static void query_dp_dual_mode_adaptor(
}
}
+ if (is_valid_hdmi_signature)
+ sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK;
if (is_type2_dongle) {
uint32_t max_tmds_clk =
@@ -993,7 +995,7 @@ static bool detect_link_and_local_sink(struct dc_link *link,
(link->dpcd_sink_ext_caps.bits.oled == 1)) {
dpcd_set_source_specific_data(link);
msleep(post_oui_delay);
- set_default_brightness(link);
+ set_default_brightness_aux(link);
}
return true;
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
index 323cc0b3c09a..91742bde4dc2 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
+++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
@@ -46,6 +46,7 @@
#include "protocols/link_dp_capability.h"
#include "protocols/link_dp_training.h"
#include "protocols/link_edp_panel_control.h"
+#include "protocols/link_dp_panel_replay.h"
#include "protocols/link_dp_dpia_bw.h"
#include "dm_helpers.h"
@@ -2061,7 +2062,7 @@ static enum dc_status enable_link_dp(struct dc_state *state,
skip_video_pattern = false;
if (stream->sink_patches.oled_optimize_display_on)
- set_default_brightness(link);
+ set_default_brightness_aux(link);
if (perform_link_training_with_retries(link_settings,
skip_video_pattern,
@@ -2087,7 +2088,7 @@ static enum dc_status enable_link_dp(struct dc_state *state,
link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1 ||
link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1) {
if (!stream->sink_patches.oled_optimize_display_on) {
- set_default_brightness(link);
+ set_default_brightness_aux(link);
if (link->dpcd_sink_ext_caps.bits.oled == 1)
msleep(bl_oled_enable_delay);
edp_backlight_enable_aux(link, true);
@@ -2529,6 +2530,9 @@ void link_set_dpms_on(
link_set_dsc_enable(pipe_ctx, true);
}
+ if (link->replay_settings.config.replay_supported && !dc_is_embedded_signal(link->connector_signal))
+ dp_setup_replay(link, stream);
+
status = enable_link(state, pipe_ctx);
if (status != DC_OK) {
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c b/drivers/gpu/drm/amd/display/dc/link/link_factory.c
index 923517715651..5fbcf04c6251 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c
+++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c
@@ -41,6 +41,7 @@
#include "protocols/link_dp_phy.h"
#include "protocols/link_dp_training.h"
#include "protocols/link_edp_panel_control.h"
+#include "protocols/link_dp_panel_replay.h"
#include "protocols/link_hpd.h"
#include "gpio_service_interface.h"
#include "atomfirmware.h"
@@ -214,7 +215,6 @@ static void construct_link_service_edp_panel_control(struct link_service *link_s
link_srv->edp_get_replay_state = edp_get_replay_state;
link_srv->edp_set_replay_allow_active = edp_set_replay_allow_active;
- link_srv->edp_setup_replay = edp_setup_replay;
link_srv->edp_send_replay_cmd = edp_send_replay_cmd;
link_srv->edp_set_coasting_vtotal = edp_set_coasting_vtotal;
link_srv->edp_replay_residency = edp_replay_residency;
@@ -228,13 +228,21 @@ static void construct_link_service_edp_panel_control(struct link_service *link_s
link_srv->edp_receiver_ready_T9 = edp_receiver_ready_T9;
link_srv->edp_receiver_ready_T7 = edp_receiver_ready_T7;
link_srv->edp_power_alpm_dpcd_enable = edp_power_alpm_dpcd_enable;
- link_srv->edp_pr_enable = edp_pr_enable;
- link_srv->edp_pr_update_state = edp_pr_update_state;
- link_srv->edp_pr_set_general_cmd = edp_pr_set_general_cmd;
- link_srv->edp_pr_get_state = edp_pr_get_state;
link_srv->edp_set_panel_power = edp_set_panel_power;
}
+/* link dp panel replay implements DP panel replay functionality.
+ */
+static void construct_link_service_dp_panel_replay(struct link_service *link_srv)
+{
+ link_srv->dp_setup_replay = dp_setup_replay;
+ link_srv->dp_pr_get_panel_inst = dp_pr_get_panel_inst;
+ link_srv->dp_pr_enable = dp_pr_enable;
+ link_srv->dp_pr_update_state = dp_pr_update_state;
+ link_srv->dp_pr_set_general_cmd = dp_pr_set_general_cmd;
+ link_srv->dp_pr_get_state = dp_pr_get_state;
+}
+
/* link dp cts implements dp compliance test automation protocols and manual
* testing interfaces for debugging and certification purpose.
*/
@@ -287,6 +295,7 @@ static void construct_link_service(struct link_service *link_srv)
construct_link_service_dp_phy_or_dpia(link_srv);
construct_link_service_dp_irq_handler(link_srv);
construct_link_service_edp_panel_control(link_srv);
+ construct_link_service_dp_panel_replay(link_srv);
construct_link_service_dp_cts(link_srv);
construct_link_service_dp_trace(link_srv);
}
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
index 54c417928b61..cdc7587cf0b6 100644
--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
@@ -1593,6 +1593,41 @@ static bool dpcd_read_sink_ext_caps(struct dc_link *link)
return true;
}
+static void retrieve_vesa_replay_su_info(struct dc_link *link)
+{
+ uint8_t dpcd_data = 0;
+
+ core_link_read_dpcd(link,
+ DP_PR_SU_X_GRANULARITY_LOW,
+ &dpcd_data,
+ sizeof(dpcd_data));
+ link->dpcd_caps.vesa_replay_su_info.pr_su_x_granularity = dpcd_data;
+
+ core_link_read_dpcd(link,
+ DP_PR_SU_X_GRANULARITY_HIGH,
+ &dpcd_data,
+ sizeof(dpcd_data));
+ link->dpcd_caps.vesa_replay_su_info.pr_su_x_granularity |= (dpcd_data << 8);
+
+ core_link_read_dpcd(link,
+ DP_PR_SU_Y_GRANULARITY,
+ &dpcd_data,
+ sizeof(dpcd_data));
+ link->dpcd_caps.vesa_replay_su_info.pr_su_y_granularity = dpcd_data;
+
+ core_link_read_dpcd(link,
+ DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_LOW,
+ &dpcd_data,
+ sizeof(dpcd_data));
+ link->dpcd_caps.vesa_replay_su_info.pr_su_y_granularity_extended_caps = dpcd_data;
+
+ core_link_read_dpcd(link,
+ DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_HIGH,
+ &dpcd_data,
+ sizeof(dpcd_data));
+ link->dpcd_caps.vesa_replay_su_info.pr_su_y_granularity_extended_caps |= (dpcd_data << 8);
+}
+
enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link)
{
uint8_t lttpr_dpcd_data[10] = {0};
@@ -2094,8 +2129,16 @@ static bool retrieve_link_cap(struct dc_link *link)
core_link_read_dpcd(link,
DP_PANEL_REPLAY_CAPABILITY_SUPPORT,
- &link->dpcd_caps.pr_caps_supported.raw,
- sizeof(link->dpcd_caps.pr_caps_supported.raw));
+ &link->dpcd_caps.vesa_replay_caps_supported.raw,
+ sizeof(link->dpcd_caps.vesa_replay_caps_supported.raw));
+
+ core_link_read_dpcd(link,
+ DP_PANEL_REPLAY_CAPABILITY,
+ &link->dpcd_caps.vesa_replay_caps.raw,
+ sizeof(link->dpcd_caps.vesa_replay_caps.raw));
+
+ /* Read VESA Panel Replay Selective Update caps */
+ retrieve_vesa_replay_su_info(link);
/* Read DP tunneling information. */
status = dpcd_get_tunneling_device_data(link);
@@ -2167,7 +2210,7 @@ void detect_edp_sink_caps(struct dc_link *link)
link->dpcd_caps.set_power_state_capable_edp =
(general_edp_cap & DP_EDP_SET_POWER_CAP) ? true : false;
- set_default_brightness(link);
+ set_default_brightness_aux(link);
core_link_read_dpcd(link, DP_EDP_DPCD_REV,
&link->dpcd_caps.edp_rev,
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c
index 4b01ab0a5a7f..cc18a3bebef2 100644
--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c
@@ -34,10 +34,12 @@
#include "link_dp_training.h"
#include "link_dp_capability.h"
#include "link_edp_panel_control.h"
+#include "link_dp_panel_replay.h"
#include "link/accessories/link_dp_trace.h"
#include "link/link_dpms.h"
#include "dm_helpers.h"
#include "link_dp_dpia_bw.h"
+#include "link_dp_panel_replay.h"
#define DC_LOGGER \
link->ctx->logger
@@ -185,6 +187,42 @@ static bool handle_hpd_irq_psr_sink(struct dc_link *link)
return false;
}
+static void handle_hpd_irq_vesa_replay_sink(struct dc_link *link)
+{
+ union pr_error_status pr_error_status = {0};
+
+ if (!link->replay_settings.replay_feature_enabled ||
+ link->replay_settings.config.replay_version != DC_VESA_PANEL_REPLAY)
+ return;
+
+ dm_helpers_dp_read_dpcd(
+ link->ctx,
+ link,
+ DP_PR_ERROR_STATUS,
+ &pr_error_status.raw,
+ sizeof(pr_error_status.raw));
+
+ if (pr_error_status.bits.LINK_CRC_ERROR ||
+ pr_error_status.bits.RFB_STORAGE_ERROR ||
+ pr_error_status.bits.VSC_SDP_ERROR ||
+ pr_error_status.bits.ASSDP_MISSING_ERROR) {
+
+ /* Acknowledge and clear error bits */
+ dm_helpers_dp_write_dpcd(
+ link->ctx,
+ link,
+ DP_PR_ERROR_STATUS, /*DpcdAddress_PR_Error_Status*/
+ &pr_error_status.raw,
+ sizeof(pr_error_status.raw));
+
+ /* Replay error, disable and re-enable Replay */
+ if (link->replay_settings.replay_allow_active) {
+ dp_pr_enable(link, false);
+ dp_pr_enable(link, true);
+ }
+ }
+}
+
static void handle_hpd_irq_replay_sink(struct dc_link *link)
{
union dpcd_replay_configuration replay_configuration = {0};
@@ -196,6 +234,11 @@ static void handle_hpd_irq_replay_sink(struct dc_link *link)
if (!link->replay_settings.replay_feature_enabled)
return;
+ if (link->replay_settings.config.replay_version != DC_FREESYNC_REPLAY) {
+ handle_hpd_irq_vesa_replay_sink(link);
+ return;
+ }
+
while (retries < 10) {
ret = dm_helpers_dp_read_dpcd(
link->ctx,
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c
new file mode 100644
index 000000000000..be441851d876
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright 2025 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 "link_dp_panel_replay.h"
+#include "link_edp_panel_control.h"
+#include "link_dpcd.h"
+#include "dm_helpers.h"
+#include "dc/dc_dmub_srv.h"
+#include "dce/dmub_replay.h"
+
+#define DC_LOGGER \
+ link->ctx->logger
+
+#define DP_SINK_PR_ENABLE_AND_CONFIGURATION 0x37B
+
+static bool dp_setup_panel_replay(struct dc_link *link, const struct dc_stream_state *stream)
+{
+ /* To-do: Setup Replay */
+ struct dc *dc;
+ struct dmub_replay *replay;
+ int i;
+ unsigned int panel_inst;
+ struct replay_context replay_context = { 0 };
+ unsigned int lineTimeInNs = 0;
+
+ union panel_replay_enable_and_configuration_1 pr_config_1 = { 0 };
+ union panel_replay_enable_and_configuration_2 pr_config_2 = { 0 };
+
+ union dpcd_alpm_configuration alpm_config;
+
+ replay_context.controllerId = CONTROLLER_ID_UNDEFINED;
+
+ if (!link)
+ return false;
+
+ //Clear Panel Replay enable & config
+ dm_helpers_dp_write_dpcd(link->ctx, link,
+ DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1,
+ (uint8_t *)&(pr_config_1.raw), sizeof(uint8_t));
+
+ dm_helpers_dp_write_dpcd(link->ctx, link,
+ DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2,
+ (uint8_t *)&(pr_config_2.raw), sizeof(uint8_t));
+
+ if (!(link->replay_settings.config.replay_supported))
+ return false;
+
+ dc = link->ctx->dc;
+
+ //not sure should keep or not
+ replay = dc->res_pool->replay;
+
+ if (!replay)
+ return false;
+
+ if (!dp_pr_get_panel_inst(dc, link, &panel_inst))
+ return false;
+
+ replay_context.aux_inst = link->ddc->ddc_pin->hw_info.ddc_channel;
+ replay_context.digbe_inst = link->link_enc->transmitter;
+ replay_context.digfe_inst = link->link_enc->preferred_engine;
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ if (dc->current_state->res_ctx.pipe_ctx[i].stream
+ == stream) {
+ /* dmcu -1 for all controller id values,
+ * therefore +1 here
+ */
+ replay_context.controllerId =
+ dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg->inst + 1;
+ break;
+ }
+ }
+
+ lineTimeInNs =
+ ((stream->timing.h_total * 1000000) /
+ (stream->timing.pix_clk_100hz / 10)) + 1;
+
+ replay_context.line_time_in_ns = lineTimeInNs;
+
+ link->replay_settings.replay_feature_enabled = dp_pr_copy_settings(link, &replay_context);
+
+ if (link->replay_settings.replay_feature_enabled) {
+ if (dc_is_embedded_signal(link->connector_signal)) {
+ pr_config_1.bits.PANEL_REPLAY_ENABLE = 1;
+ pr_config_1.bits.PANEL_REPLAY_CRC_ENABLE = 1;
+ pr_config_1.bits.IRQ_HPD_ASSDP_MISSING = 1;
+ pr_config_1.bits.IRQ_HPD_VSCSDP_UNCORRECTABLE_ERROR = 1;
+ pr_config_1.bits.IRQ_HPD_RFB_ERROR = 1;
+ pr_config_1.bits.IRQ_HPD_ACTIVE_FRAME_CRC_ERROR = 1;
+ pr_config_1.bits.PANEL_REPLAY_SELECTIVE_UPDATE_ENABLE = 1;
+ pr_config_1.bits.PANEL_REPLAY_EARLY_TRANSPORT_ENABLE = 1;
+ } else {
+ pr_config_1.bits.PANEL_REPLAY_ENABLE = 1;
+ }
+
+ pr_config_2.bits.SINK_REFRESH_RATE_UNLOCK_GRANTED = 0;
+
+ if (link->dpcd_caps.vesa_replay_caps.bits.SU_Y_GRANULARITY_EXT_CAP_SUPPORTED)
+ pr_config_2.bits.SU_Y_GRANULARITY_EXT_VALUE_ENABLED = 1;
+
+ pr_config_2.bits.SU_REGION_SCAN_LINE_CAPTURE_INDICATION = 0;
+
+ dm_helpers_dp_write_dpcd(link->ctx, link,
+ DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1,
+ (uint8_t *)&(pr_config_1.raw), sizeof(uint8_t));
+
+ dm_helpers_dp_write_dpcd(link->ctx, link,
+ DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2,
+ (uint8_t *)&(pr_config_2.raw), sizeof(uint8_t));
+
+ //ALPM Setup
+ memset(&alpm_config, 0, sizeof(alpm_config));
+ alpm_config.bits.ENABLE = link->replay_settings.config.alpm_mode != DC_ALPM_UNSUPPORTED ? 1 : 0;
+
+ if (link->replay_settings.config.alpm_mode == DC_ALPM_AUXLESS) {
+ alpm_config.bits.ALPM_MODE_SEL = 1;
+ alpm_config.bits.ACDS_PERIOD_DURATION = 1;
+ }
+
+ dm_helpers_dp_write_dpcd(
+ link->ctx,
+ link,
+ DP_RECEIVER_ALPM_CONFIG,
+ &alpm_config.raw,
+ sizeof(alpm_config.raw));
+ }
+
+ return true;
+}
+
+
+bool dp_pr_get_panel_inst(const struct dc *dc,
+ const struct dc_link *link,
+ unsigned int *inst_out)
+{
+ if (dc_is_embedded_signal(link->connector_signal)) {
+ /* TODO: just get edp link panel inst for now, fix it */
+ return dc_get_edp_link_panel_inst(dc, link, inst_out);
+ } else if (dc_is_dp_sst_signal(link->connector_signal)) {
+ /* TODO: just set to 1 for now, fix it */
+ *inst_out = 1;
+ return true;
+ }
+
+ return false;
+}
+
+bool dp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream)
+{
+ if (!link)
+ return false;
+ if (link->replay_settings.config.replay_version == DC_VESA_PANEL_REPLAY)
+ return dp_setup_panel_replay(link, stream);
+ else if (link->replay_settings.config.replay_version == DC_FREESYNC_REPLAY)
+ return edp_setup_freesync_replay(link, stream);
+ else
+ return false;
+}
+
+bool dp_pr_enable(struct dc_link *link, bool enable)
+{
+ struct dc *dc = link->ctx->dc;
+ unsigned int panel_inst = 0;
+ union dmub_rb_cmd cmd;
+
+ if (!dp_pr_get_panel_inst(dc, link, &panel_inst))
+ return false;
+
+ if (link->replay_settings.replay_allow_active != enable) {
+ //for sending PR enable commands to DMUB
+ memset(&cmd, 0, sizeof(cmd));
+
+ cmd.pr_enable.header.type = DMUB_CMD__PR;
+ cmd.pr_enable.header.sub_type = DMUB_CMD__PR_ENABLE;
+ cmd.pr_enable.header.payload_bytes = sizeof(struct dmub_cmd_pr_enable_data);
+ cmd.pr_enable.data.panel_inst = panel_inst;
+ cmd.pr_enable.data.enable = enable ? 1 : 0;
+
+ dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
+
+ link->replay_settings.replay_allow_active = enable;
+ }
+ return true;
+}
+
+bool dp_pr_copy_settings(struct dc_link *link, struct replay_context *replay_context)
+{
+ struct dc *dc = link->ctx->dc;
+ unsigned int panel_inst = 0;
+ union dmub_rb_cmd cmd;
+ struct pipe_ctx *pipe_ctx = NULL;
+
+ if (!dp_pr_get_panel_inst(dc, link, &panel_inst))
+ return false;
+
+ for (unsigned int i = 0; i < MAX_PIPES; i++) {
+ if (dc->current_state->res_ctx.pipe_ctx[i].stream &&
+ dc->current_state->res_ctx.pipe_ctx[i].stream->link &&
+ dc->current_state->res_ctx.pipe_ctx[i].stream->link == link &&
+ dc_is_dp_sst_signal(dc->current_state->res_ctx.pipe_ctx[i].stream->link->connector_signal)) {
+ pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
+ /* todo: need update for MST */
+ break;
+ }
+ }
+
+ if (!pipe_ctx)
+ return false;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.pr_copy_settings.header.type = DMUB_CMD__PR;
+ cmd.pr_copy_settings.header.sub_type = DMUB_CMD__PR_COPY_SETTINGS;
+ cmd.pr_copy_settings.header.payload_bytes = sizeof(struct dmub_cmd_pr_copy_settings_data);
+ cmd.pr_copy_settings.data.panel_inst = panel_inst;
+ // HW inst
+ cmd.pr_copy_settings.data.aux_inst = replay_context->aux_inst;
+ cmd.pr_copy_settings.data.digbe_inst = replay_context->digbe_inst;
+ cmd.pr_copy_settings.data.digfe_inst = replay_context->digfe_inst;
+ if (pipe_ctx->plane_res.dpp)
+ cmd.pr_copy_settings.data.dpp_inst = pipe_ctx->plane_res.dpp->inst;
+ else
+ cmd.pr_copy_settings.data.dpp_inst = 0;
+ if (pipe_ctx->stream_res.tg)
+ cmd.pr_copy_settings.data.otg_inst = pipe_ctx->stream_res.tg->inst;
+ else
+ cmd.pr_copy_settings.data.otg_inst = 0;
+
+ cmd.pr_copy_settings.data.dpphy_inst = link->link_enc->transmitter;
+
+ cmd.pr_copy_settings.data.line_time_in_ns = replay_context->line_time_in_ns;
+ cmd.pr_copy_settings.data.flags.bitfields.fec_enable_status = (link->fec_state == dc_link_fec_enabled);
+ cmd.pr_copy_settings.data.flags.bitfields.dsc_enable_status = (pipe_ctx->stream->timing.flags.DSC == 1);
+ cmd.pr_copy_settings.data.debug.u32All = link->replay_settings.config.debug_flags;
+
+ cmd.pr_copy_settings.data.su_granularity_needed = link->dpcd_caps.vesa_replay_caps.bits.PR_SU_GRANULARITY_NEEDED;
+ cmd.pr_copy_settings.data.su_x_granularity = link->dpcd_caps.vesa_replay_su_info.pr_su_x_granularity;
+ cmd.pr_copy_settings.data.su_y_granularity = link->dpcd_caps.vesa_replay_su_info.pr_su_y_granularity;
+ cmd.pr_copy_settings.data.su_y_granularity_extended_caps =
+ link->dpcd_caps.vesa_replay_su_info.pr_su_y_granularity_extended_caps;
+
+ if (pipe_ctx->stream->timing.dsc_cfg.num_slices_v > 0)
+ cmd.pr_copy_settings.data.dsc_slice_height = (pipe_ctx->stream->timing.v_addressable +
+ pipe_ctx->stream->timing.v_border_top + pipe_ctx->stream->timing.v_border_bottom) /
+ pipe_ctx->stream->timing.dsc_cfg.num_slices_v;
+
+ dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
+ return true;
+}
+
+bool dp_pr_update_state(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data)
+{
+ struct dc *dc = link->ctx->dc;
+ unsigned int panel_inst = 0;
+ union dmub_rb_cmd cmd;
+
+ if (!dp_pr_get_panel_inst(dc, link, &panel_inst))
+ return false;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.pr_update_state.header.type = DMUB_CMD__PR;
+ cmd.pr_update_state.header.sub_type = DMUB_CMD__PR_UPDATE_STATE;
+ cmd.pr_update_state.header.payload_bytes = sizeof(struct dmub_cmd_pr_update_state_data);
+ cmd.pr_update_state.data.panel_inst = panel_inst;
+
+ memcpy(&cmd.pr_update_state.data, update_state_data, sizeof(struct dmub_cmd_pr_update_state_data));
+
+ dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
+ return true;
+}
+
+bool dp_pr_set_general_cmd(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data)
+{
+ struct dc *dc = link->ctx->dc;
+ unsigned int panel_inst = 0;
+ union dmub_rb_cmd cmd;
+
+ if (!dp_pr_get_panel_inst(dc, link, &panel_inst))
+ return false;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.pr_general_cmd.header.type = DMUB_CMD__PR;
+ cmd.pr_general_cmd.header.sub_type = DMUB_CMD__PR_GENERAL_CMD;
+ cmd.pr_general_cmd.header.payload_bytes = sizeof(struct dmub_cmd_pr_general_cmd_data);
+ cmd.pr_general_cmd.data.panel_inst = panel_inst;
+
+ memcpy(&cmd.pr_general_cmd.data, general_cmd_data, sizeof(struct dmub_cmd_pr_general_cmd_data));
+
+ dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
+ return true;
+}
+
+bool dp_pr_get_state(const struct dc_link *link, uint64_t *state)
+{
+ const struct dc *dc = link->ctx->dc;
+ unsigned int panel_inst = 0;
+ uint32_t retry_count = 0;
+ uint32_t replay_state = 0;
+
+ if (!dp_pr_get_panel_inst(dc, link, &panel_inst))
+ return false;
+
+ do {
+ // Send gpint command and wait for ack
+ if (!dc_wake_and_execute_gpint(dc->ctx, DMUB_GPINT__GET_REPLAY_STATE, panel_inst,
+ &replay_state, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) {
+ // Return invalid state when GPINT times out
+ replay_state = PR_STATE_INVALID;
+ }
+ /* Copy 32-bit result into 64-bit output */
+ *state = replay_state;
+ } while (++retry_count <= 1000 && *state == PR_STATE_INVALID);
+
+ // Assert if max retry hit
+ if (retry_count >= 1000 && *state == PR_STATE_INVALID) {
+ ASSERT(0);
+ /* To-do: Add retry fail log */
+ }
+
+ return true;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.h
new file mode 100644
index 000000000000..5522d5911fd1
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2025 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 __DC_LINK_DP_PANEL_REPLAY_H__
+#define __DC_LINK_DP_PANEL_REPLAY_H__
+
+#include "link_service.h"
+
+bool dp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream);
+bool dp_pr_get_panel_inst(const struct dc *dc, const struct dc_link *link, unsigned int *inst_out);
+bool dp_pr_enable(struct dc_link *link, bool enable);
+bool dp_pr_copy_settings(struct dc_link *link, struct replay_context *replay_context);
+bool dp_pr_update_state(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data);
+bool dp_pr_set_general_cmd(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data);
+bool dp_pr_get_state(const struct dc_link *link, uint64_t *state);
+
+#endif /* __DC_LINK_DP_PANEL_REPLAY_H__ */ \ No newline at end of file
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
index d6e91da72ef8..cb4129c0937a 100644
--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
@@ -50,11 +50,6 @@ static const uint8_t DP_VGA_LVDS_CONVERTER_ID_2[] = "sivarT";
/* Nutmeg */
static const uint8_t DP_VGA_LVDS_CONVERTER_ID_3[] = "dnomlA";
-static const unsigned int pwr_default_min_brightness_millinits = 1000;
-static const unsigned int pwr_default_sdr_brightness_millinits = 270000;
-static const unsigned int pwr_default_min_backlight_pwm = 0xC0C;
-static const unsigned int pwr_default_max_backlight_pwm = 0xFFFF;
-
void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode)
{
union dpcd_edp_config edp_config_set;
@@ -313,7 +308,7 @@ static bool read_default_bl_aux(struct dc_link *link, uint32_t *backlight_millin
return true;
}
-bool set_default_brightness(struct dc_link *link)
+bool set_default_brightness_aux(struct dc_link *link)
{
uint32_t default_backlight;
@@ -324,23 +319,8 @@ bool set_default_brightness(struct dc_link *link)
if (default_backlight < 1000 || default_backlight > 5000000)
default_backlight = 150000;
- if (link->backlight_control_type == BACKLIGHT_CONTROL_VESA_AUX &&
- link->dc->caps.dmub_caps.aux_backlight_support) {
- struct set_backlight_level_params backlight_level_params = { 0 };
-
- backlight_level_params.aux_inst = link->ddc->ddc_pin->hw_info.ddc_channel;
- backlight_level_params.control_type = BACKLIGHT_CONTROL_VESA_AUX;
- backlight_level_params.backlight_pwm_u16_16 = default_backlight;
- backlight_level_params.transition_time_in_ms = 0;
- // filled in the driver BL default values
- backlight_level_params.min_luminance = pwr_default_min_brightness_millinits;
- backlight_level_params.max_luminance = pwr_default_sdr_brightness_millinits;
- backlight_level_params.min_backlight_pwm = pwr_default_min_backlight_pwm;
- backlight_level_params.max_backlight_pwm = pwr_default_max_backlight_pwm;
- return edp_set_backlight_level(link, &backlight_level_params);
- } else
- return edp_set_backlight_level_nits(link, true,
- default_backlight, 0);
+ return edp_set_backlight_level_nits(link, true,
+ default_backlight, 0);
}
return false;
}
@@ -1003,116 +983,8 @@ bool edp_get_replay_state(const struct dc_link *link, uint64_t *state)
return true;
}
-static bool edp_setup_panel_replay(struct dc_link *link, const struct dc_stream_state *stream)
-{
- /* To-do: Setup Replay */
- struct dc *dc;
- struct dmub_replay *replay;
- int i;
- unsigned int panel_inst;
- struct replay_context replay_context = { 0 };
- unsigned int lineTimeInNs = 0;
-
- union panel_replay_enable_and_configuration_1 pr_config_1 = { 0 };
- union panel_replay_enable_and_configuration_2 pr_config_2 = { 0 };
-
- union dpcd_alpm_configuration alpm_config;
-
- replay_context.controllerId = CONTROLLER_ID_UNDEFINED;
-
- if (!link)
- return false;
-
- //Clear Panel Replay enable & config
- dm_helpers_dp_write_dpcd(link->ctx, link,
- DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1,
- (uint8_t *)&(pr_config_1.raw), sizeof(uint8_t));
-
- dm_helpers_dp_write_dpcd(link->ctx, link,
- DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2,
- (uint8_t *)&(pr_config_2.raw), sizeof(uint8_t));
-
- if (!(link->replay_settings.config.replay_supported))
- return false;
-
- dc = link->ctx->dc;
-
- //not sure should keep or not
- replay = dc->res_pool->replay;
-
- if (!replay)
- return false;
-
- if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
- return false;
-
- replay_context.aux_inst = link->ddc->ddc_pin->hw_info.ddc_channel;
- replay_context.digbe_inst = link->link_enc->transmitter;
- replay_context.digfe_inst = link->link_enc->preferred_engine;
-
- for (i = 0; i < MAX_PIPES; i++) {
- if (dc->current_state->res_ctx.pipe_ctx[i].stream
- == stream) {
- /* dmcu -1 for all controller id values,
- * therefore +1 here
- */
- replay_context.controllerId =
- dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg->inst + 1;
- break;
- }
- }
-
- lineTimeInNs =
- ((stream->timing.h_total * 1000000) /
- (stream->timing.pix_clk_100hz / 10)) + 1;
-
- replay_context.line_time_in_ns = lineTimeInNs;
-
- link->replay_settings.replay_feature_enabled = edp_pr_copy_settings(link, &replay_context);
-
- if (link->replay_settings.replay_feature_enabled) {
- pr_config_1.bits.PANEL_REPLAY_ENABLE = 1;
- pr_config_1.bits.PANEL_REPLAY_CRC_ENABLE = 1;
- pr_config_1.bits.IRQ_HPD_ASSDP_MISSING = 1;
- pr_config_1.bits.IRQ_HPD_VSCSDP_UNCORRECTABLE_ERROR = 1;
- pr_config_1.bits.IRQ_HPD_RFB_ERROR = 1;
- pr_config_1.bits.IRQ_HPD_ACTIVE_FRAME_CRC_ERROR = 1;
- pr_config_1.bits.PANEL_REPLAY_SELECTIVE_UPDATE_ENABLE = 1;
- pr_config_1.bits.PANEL_REPLAY_EARLY_TRANSPORT_ENABLE = 1;
-
- pr_config_2.bits.SINK_REFRESH_RATE_UNLOCK_GRANTED = 0;
- pr_config_2.bits.SU_Y_GRANULARITY_EXT_VALUE_ENABLED = 0;
- pr_config_2.bits.SU_REGION_SCAN_LINE_CAPTURE_INDICATION = 0;
-
- dm_helpers_dp_write_dpcd(link->ctx, link,
- DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1,
- (uint8_t *)&(pr_config_1.raw), sizeof(uint8_t));
-
- dm_helpers_dp_write_dpcd(link->ctx, link,
- DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2,
- (uint8_t *)&(pr_config_2.raw), sizeof(uint8_t));
-
- //ALPM Setup
- memset(&alpm_config, 0, sizeof(alpm_config));
- alpm_config.bits.ENABLE = link->replay_settings.config.alpm_mode != DC_ALPM_UNSUPPORTED ? 1 : 0;
-
- if (link->replay_settings.config.alpm_mode == DC_ALPM_AUXLESS) {
- alpm_config.bits.ALPM_MODE_SEL = 1;
- alpm_config.bits.ACDS_PERIOD_DURATION = 1;
- }
-
- dm_helpers_dp_write_dpcd(
- link->ctx,
- link,
- DP_RECEIVER_ALPM_CONFIG,
- &alpm_config.raw,
- sizeof(alpm_config.raw));
- }
-
- return true;
-}
-static bool edp_setup_freesync_replay(struct dc_link *link, const struct dc_stream_state *stream)
+bool edp_setup_freesync_replay(struct dc_link *link, const struct dc_stream_state *stream)
{
/* To-do: Setup Replay */
struct dc *dc;
@@ -1208,17 +1080,6 @@ static bool edp_setup_freesync_replay(struct dc_link *link, const struct dc_stre
return true;
}
-bool edp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream)
-{
- if (!link)
- return false;
- if (link->replay_settings.config.replay_version == DC_VESA_PANEL_REPLAY)
- return edp_setup_panel_replay(link, stream);
- else if (link->replay_settings.config.replay_version == DC_FREESYNC_REPLAY)
- return edp_setup_freesync_replay(link, stream);
- else
- return false;
-}
/*
* This is general Interface for Replay to set an 32 bit variable to dmub
@@ -1323,156 +1184,6 @@ bool edp_set_replay_power_opt_and_coasting_vtotal(struct dc_link *link,
return true;
}
-bool edp_pr_enable(struct dc_link *link, bool enable)
-{
- struct dc *dc = link->ctx->dc;
- unsigned int panel_inst = 0;
- union dmub_rb_cmd cmd;
-
- if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
- return false;
-
- if (link->replay_settings.replay_allow_active != enable) {
- //for sending PR enable commands to DMUB
- memset(&cmd, 0, sizeof(cmd));
-
- cmd.pr_enable.header.type = DMUB_CMD__PR;
- cmd.pr_enable.header.sub_type = DMUB_CMD__PR_ENABLE;
- cmd.pr_enable.header.payload_bytes = sizeof(struct dmub_cmd_pr_enable_data);
- cmd.pr_enable.data.panel_inst = panel_inst;
- cmd.pr_enable.data.enable = enable ? 1 : 0;
-
- dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
-
- link->replay_settings.replay_allow_active = enable;
- }
- return true;
-}
-
-bool edp_pr_copy_settings(struct dc_link *link, struct replay_context *replay_context)
-{
- struct dc *dc = link->ctx->dc;
- unsigned int panel_inst = 0;
- union dmub_rb_cmd cmd;
- struct pipe_ctx *pipe_ctx = NULL;
-
- if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
- return false;
-
- for (unsigned int i = 0; i < MAX_PIPES; i++) {
- if (dc->current_state->res_ctx.pipe_ctx[i].stream &&
- dc->current_state->res_ctx.pipe_ctx[i].stream->link &&
- dc->current_state->res_ctx.pipe_ctx[i].stream->link == link &&
- dc->current_state->res_ctx.pipe_ctx[i].stream->link->connector_signal == SIGNAL_TYPE_EDP) {
- pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
- //TODO: refactor for multi edp support
- break;
- }
- }
-
- if (!pipe_ctx)
- return false;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.pr_copy_settings.header.type = DMUB_CMD__PR;
- cmd.pr_copy_settings.header.sub_type = DMUB_CMD__PR_COPY_SETTINGS;
- cmd.pr_copy_settings.header.payload_bytes = sizeof(struct dmub_cmd_pr_copy_settings_data);
- cmd.pr_copy_settings.data.panel_inst = panel_inst;
- // HW inst
- cmd.pr_copy_settings.data.aux_inst = replay_context->aux_inst;
- cmd.pr_copy_settings.data.digbe_inst = replay_context->digbe_inst;
- cmd.pr_copy_settings.data.digfe_inst = replay_context->digfe_inst;
- if (pipe_ctx->plane_res.dpp)
- cmd.pr_copy_settings.data.dpp_inst = pipe_ctx->plane_res.dpp->inst;
- else
- cmd.pr_copy_settings.data.dpp_inst = 0;
- if (pipe_ctx->stream_res.tg)
- cmd.pr_copy_settings.data.otg_inst = pipe_ctx->stream_res.tg->inst;
- else
- cmd.pr_copy_settings.data.otg_inst = 0;
-
- cmd.pr_copy_settings.data.dpphy_inst = link->link_enc->transmitter;
-
- cmd.pr_copy_settings.data.line_time_in_ns = replay_context->line_time_in_ns;
- cmd.pr_copy_settings.data.flags.bitfields.fec_enable_status = (link->fec_state == dc_link_fec_enabled);
- cmd.pr_copy_settings.data.flags.bitfields.dsc_enable_status = (pipe_ctx->stream->timing.flags.DSC == 1);
- cmd.pr_copy_settings.data.debug.u32All = link->replay_settings.config.debug_flags;
-
- dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
- return true;
-}
-
-bool edp_pr_update_state(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data)
-{
- struct dc *dc = link->ctx->dc;
- unsigned int panel_inst = 0;
- union dmub_rb_cmd cmd;
-
- if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
- return false;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.pr_update_state.header.type = DMUB_CMD__PR;
- cmd.pr_update_state.header.sub_type = DMUB_CMD__PR_UPDATE_STATE;
- cmd.pr_update_state.header.payload_bytes = sizeof(struct dmub_cmd_pr_update_state_data);
- cmd.pr_update_state.data.panel_inst = panel_inst;
-
- memcpy(&cmd.pr_update_state.data, update_state_data, sizeof(struct dmub_cmd_pr_update_state_data));
-
- dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
- return true;
-}
-
-bool edp_pr_set_general_cmd(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data)
-{
- struct dc *dc = link->ctx->dc;
- unsigned int panel_inst = 0;
- union dmub_rb_cmd cmd;
-
- if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
- return false;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.pr_general_cmd.header.type = DMUB_CMD__PR;
- cmd.pr_general_cmd.header.sub_type = DMUB_CMD__PR_GENERAL_CMD;
- cmd.pr_general_cmd.header.payload_bytes = sizeof(struct dmub_cmd_pr_general_cmd_data);
- cmd.pr_general_cmd.data.panel_inst = panel_inst;
-
- memcpy(&cmd.pr_general_cmd.data, general_cmd_data, sizeof(struct dmub_cmd_pr_general_cmd_data));
-
- dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
- return true;
-}
-
-bool edp_pr_get_state(const struct dc_link *link, uint64_t *state)
-{
- const struct dc *dc = link->ctx->dc;
- unsigned int panel_inst = 0;
- uint32_t retry_count = 0;
- uint32_t replay_state = 0;
-
- if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
- return false;
-
- do {
- // Send gpint command and wait for ack
- if (!dc_wake_and_execute_gpint(dc->ctx, DMUB_GPINT__GET_REPLAY_STATE, panel_inst,
- &replay_state, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) {
- // Return invalid state when GPINT times out
- replay_state = PR_STATE_INVALID;
- }
- /* Copy 32-bit result into 64-bit output */
- *state = replay_state;
- } while (++retry_count <= 1000 && *state == PR_STATE_INVALID);
-
- // Assert if max retry hit
- if (retry_count >= 1000 && *state == PR_STATE_INVALID) {
- ASSERT(0);
- /* To-do: Add retry fail log */
- }
-
- return true;
-}
static struct abm *get_abm_from_stream_res(const struct dc_link *link)
{
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h
index fd63b5d0f948..8fdb76d9953e 100644
--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h
@@ -29,7 +29,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(struct dc_link *link);
+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);
@@ -54,8 +54,6 @@ bool edp_set_sink_vtotal_in_psr_active(const struct dc_link *link,
void edp_get_psr_residency(const struct dc_link *link, uint32_t *residency, enum psr_residency_mode mode);
bool edp_set_replay_allow_active(struct dc_link *dc_link, const bool *enable,
bool wait, bool force_static, const unsigned int *power_opts);
-bool edp_setup_replay(struct dc_link *link,
- const struct dc_stream_state *stream);
bool edp_send_replay_cmd(struct dc_link *link,
enum replay_FW_Message_type msg,
union dmub_replay_cmd_set *cmd_data);
@@ -75,11 +73,7 @@ void edp_add_delay_for_T9(struct dc_link *link);
bool edp_receiver_ready_T9(struct dc_link *link);
bool edp_receiver_ready_T7(struct dc_link *link);
bool edp_power_alpm_dpcd_enable(struct dc_link *link, bool enable);
-bool edp_pr_enable(struct dc_link *link, bool enable);
-bool edp_pr_copy_settings(struct dc_link *link, struct replay_context *replay_context);
-bool edp_pr_update_state(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data);
-bool edp_pr_set_general_cmd(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data);
-bool edp_pr_get_state(const struct dc_link *link, uint64_t *state);
+bool edp_setup_freesync_replay(struct dc_link *link, const struct dc_stream_state *stream);
void edp_set_panel_power(struct dc_link *link, bool powerOn);
void edp_set_panel_assr(struct dc_link *link, struct pipe_ctx *pipe_ctx,
enum dp_panel_mode *panel_mode, bool enable);
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c
index 0d667b54ccf8..e853ea110310 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c
@@ -2250,12 +2250,15 @@ enum dc_status dcn31_update_dc_state_for_encoder_switch(struct dc_link *link,
int i;
#if defined(CONFIG_DRM_AMD_DC_FP)
- for (i = 0; i < state->stream_count; i++)
- if (state->streams[i] && state->streams[i]->link && state->streams[i]->link == link)
- link->dc->hwss.calculate_pix_rate_divider((struct dc *)link->dc, state, state->streams[i]);
+ if (link->dc->hwss.calculate_pix_rate_divider) {
+ for (i = 0; i < state->stream_count; i++)
+ if (state->streams[i] && state->streams[i]->link && state->streams[i]->link == link)
+ link->dc->hwss.calculate_pix_rate_divider((struct dc *)link->dc, state, state->streams[i]);
+ }
for (i = 0; i < pipe_count; i++) {
- link->dc->res_pool->funcs->build_pipe_pix_clk_params(&pipes[i]);
+ if (link->dc->res_pool->funcs->build_pipe_pix_clk_params)
+ link->dc->res_pool->funcs->build_pipe_pix_clk_params(&pipes[i]);
// Setup audio
if (pipes[i].stream_res.audio != NULL)
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 6c599559c5da..9d0852760e78 100644
--- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
+++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
@@ -1091,7 +1091,10 @@ union dmub_fw_boot_options {
uint32_t lower_hbr3_phy_ssc: 1; /**< 1 to lower hbr3 phy ssc to 0.125 percent */
uint32_t override_hbr3_pll_vco: 1; /**< 1 to override the hbr3 pll vco to 0 */
uint32_t disable_dpia_bw_allocation: 1; /**< 1 to disable the USB4 DPIA BW allocation */
- uint32_t reserved : 4; /**< reserved */
+ uint32_t bootcrc_en_at_preos: 1; /**< 1 to run the boot time crc during warm/cold boot*/
+ uint32_t bootcrc_en_at_S0i3: 1; /**< 1 to run the boot time crc during S0i3 boot*/
+ uint32_t bootcrc_boot_mode: 1; /**< 1 for S0i3 resume and 0 for Warm/cold boot*/
+ uint32_t reserved : 1; /**< reserved */
} bits; /**< boot bits */
uint32_t all; /**< 32-bit access to bits */
};
@@ -2638,7 +2641,7 @@ union dmub_fams2_global_feature_config {
uint32_t enable_visual_confirm: 1;
uint32_t allow_delay_check_mode: 2;
uint32_t legacy_method_no_fams2 : 1;
- uint32_t reserved: 23;
+ uint32_t reserved : 23;
} bits;
uint32_t all;
};
@@ -4335,10 +4338,6 @@ enum dmub_cmd_replay_type {
*/
DMUB_CMD__REPLAY_DISABLED_ADAPTIVE_SYNC_SDP = 8,
/**
- * Set version
- */
- DMUB_CMD__REPLAY_SET_VERSION = 9,
- /**
* Set Replay General command.
*/
DMUB_CMD__REPLAY_SET_GENERAL_CMD = 16,
@@ -4379,6 +4378,7 @@ enum dmub_cmd_replay_general_subtype {
REPLAY_GENERAL_CMD_UPDATE_ERROR_STATUS,
REPLAY_GENERAL_CMD_SET_LOW_RR_ACTIVATE,
REPLAY_GENERAL_CMD_VIDEO_CONFERENCING,
+ REPLAY_GENERAL_CMD_SET_CONTINUOUSLY_RESYNC,
};
struct dmub_alpm_auxless_data {
@@ -4506,40 +4506,6 @@ enum replay_version {
};
/**
- * Data passed from driver to FW in a DMUB_CMD___SET_REPLAY_VERSION command.
- */
-struct dmub_cmd_replay_set_version_data {
- /**
- * Panel Instance.
- * Panel instance to identify which psr_state to use
- * Currently the support is only for 0 or 1
- */
- uint8_t panel_inst;
- /**
- * Replay version that FW should implement.
- */
- enum replay_version version;
- /**
- * Explicit padding to 4 byte boundary.
- */
- uint8_t pad[3];
-};
-
-/**
- * Definition of a DMUB_CMD__REPLAY_SET_VERSION command.
- */
-struct dmub_rb_cmd_replay_set_version {
- /**
- * Command header.
- */
- struct dmub_cmd_header header;
- /**
- * Data passed from driver to FW in a DMUB_CMD__REPLAY_SET_VERSION command.
- */
- struct dmub_cmd_replay_set_version_data replay_set_version_data;
-};
-
-/**
* Definition of a DMUB_CMD__REPLAY_COPY_SETTINGS command.
*/
struct dmub_rb_cmd_replay_copy_settings {
@@ -4930,10 +4896,6 @@ union dmub_replay_cmd_set {
*/
struct dmub_cmd_replay_disabled_adaptive_sync_sdp_data disabled_adaptive_sync_sdp_data;
/**
- * Definition of DMUB_CMD__REPLAY_SET_VERSION command data.
- */
- struct dmub_cmd_replay_set_version_data version_data;
- /**
* Definition of DMUB_CMD__REPLAY_SET_GENERAL_CMD command data.
*/
struct dmub_cmd_replay_set_general_cmd_data set_general_cmd_data;
@@ -7020,10 +6982,6 @@ union dmub_rb_cmd {
* Definition of a DMUB_CMD__IDLE_OPT_SET_DC_POWER_STATE command.
*/
struct dmub_rb_cmd_idle_opt_set_dc_power_state idle_opt_set_dc_power_state;
- /**
- * Definition of a DMUB_CMD__REPLAY_SET_VERSION command.
- */
- struct dmub_rb_cmd_replay_set_version replay_set_version;
/*
* Definition of a DMUB_CMD__REPLAY_COPY_SETTINGS command.
*/
diff --git a/drivers/gpu/drm/amd/display/include/dpcd_defs.h b/drivers/gpu/drm/amd/display/include/dpcd_defs.h
index 8445c540f042..7d8359a7d99d 100644
--- a/drivers/gpu/drm/amd/display/include/dpcd_defs.h
+++ b/drivers/gpu/drm/amd/display/include/dpcd_defs.h
@@ -37,6 +37,21 @@
#ifndef DP_PANEL_REPLAY_CAPABILITY // can remove this once the define gets into linux drm_dp_helper.h
#define DP_PANEL_REPLAY_CAPABILITY 0x0b1
#endif /* DP_PANEL_REPLAY_CAPABILITY */
+#ifndef DP_PR_SU_X_GRANULARITY_LOW // can remove this once the define gets into linux drm_dp_helper.h
+#define DP_PR_SU_X_GRANULARITY_LOW 0x0b2
+#endif /* DP_PR_SU_X_GRANULARITY_LOW */
+#ifndef DP_PR_SU_X_GRANULARITY_HIGH // can remove this once the define gets into linux drm_dp_helper.h
+#define DP_PR_SU_X_GRANULARITY_HIGH 0x0b3
+#endif /* DP_PR_SU_X_GRANULARITY_HIGH */
+#ifndef DP_PR_SU_Y_GRANULARITY // can remove this once the define gets into linux drm_dp_helper.h
+#define DP_PR_SU_Y_GRANULARITY 0x0b4
+#endif /* DP_PR_SU_Y_GRANULARITY */
+#ifndef DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_LOW // can remove this once the define gets into linux drm_dp_helper.h
+#define DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_LOW 0x0b5
+#endif /* DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_LOW */
+#ifndef DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_HIGH // can remove this once the define gets into linux drm_dp_helper.h
+#define DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_HIGH 0x0b6
+#endif /* DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_HIGH */
#ifndef DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1 // can remove this once the define gets into linux drm_dp_helper.h
#define DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1 0x1b0
#endif /* DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1 */
@@ -46,6 +61,21 @@
#ifndef DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2 // can remove this once the define gets into linux drm_dp_helper.h
#define DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2 0x1b1
#endif /* DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2 */
+#ifndef DP_PR_ERROR_STATUS // can remove this once the define gets into linux drm_dp_helper.h
+#define DP_PR_ERROR_STATUS 0x2020 /* DP 2.0 */
+#endif /* DP_PR_ERROR_STATUS */
+#ifndef DP_PR_LINK_CRC_ERROR // can remove this once the define gets into linux drm_dp_helper.h
+#define DP_PR_LINK_CRC_ERROR (1 << 0)
+#endif /* DP_PR_LINK_CRC_ERROR */
+#ifndef DP_PR_RFB_STORAGE_ERROR // can remove this once the define gets into linux drm_dp_helper.h
+#define DP_PR_RFB_STORAGE_ERROR (1 << 1)
+#endif /* DP_PR_RFB_STORAGE_ERROR */
+#ifndef DP_PR_VSC_SDP_UNCORRECTABLE_ERROR // can remove this once the define gets into linux drm_dp_helper.h
+#define DP_PR_VSC_SDP_UNCORRECTABLE_ERROR (1 << 2) /* eDP 1.4 */
+#endif /* DP_PR_VSC_SDP_UNCORRECTABLE_ERROR */
+#ifndef DP_PR_ASSDP_MISSING_ERROR // can remove this once the define gets into linux drm_dp_helper.h
+#define DP_PR_ASSDP_MISSING_ERROR (1 << 3) /* eDP 1.5 */
+#endif /* DP_PR_ASSDP_MISSING_ERROR */
enum dpcd_revision {
DPCD_REV_10 = 0x10,