Merge tag 'amd-drm-next-6.9-2024-02-19' of https://gitlab.freedesktop.org/agd5f/linux...
[linux-2.6-microblaze.git] / drivers / gpu / drm / amd / display / amdgpu_dm / amdgpu_dm.c
index 6cda5b5..47338a8 100644 (file)
@@ -67,6 +67,7 @@
 #include "amdgpu_dm_debugfs.h"
 #endif
 #include "amdgpu_dm_psr.h"
+#include "amdgpu_dm_replay.h"
 
 #include "ivsrcid/ivsrcid_vislands30.h"
 
@@ -1938,17 +1939,15 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev)
                adev->dm.hdcp_workqueue = NULL;
        }
 
-       if (adev->dm.dc)
+       if (adev->dm.dc) {
                dc_deinit_callbacks(adev->dm.dc);
-
-       if (adev->dm.dc)
                dc_dmub_srv_destroy(&adev->dm.dc->ctx->dmub_srv);
-
-       if (dc_enable_dmub_notifications(adev->dm.dc)) {
-               kfree(adev->dm.dmub_notify);
-               adev->dm.dmub_notify = NULL;
-               destroy_workqueue(adev->dm.delayed_hpd_wq);
-               adev->dm.delayed_hpd_wq = NULL;
+               if (dc_enable_dmub_notifications(adev->dm.dc)) {
+                       kfree(adev->dm.dmub_notify);
+                       adev->dm.dmub_notify = NULL;
+                       destroy_workqueue(adev->dm.delayed_hpd_wq);
+                       adev->dm.delayed_hpd_wq = NULL;
+               }
        }
 
        if (adev->dm.dmub_bo)
@@ -1956,7 +1955,7 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev)
                                      &adev->dm.dmub_bo_gpu_addr,
                                      &adev->dm.dmub_bo_cpu_addr);
 
-       if (adev->dm.hpd_rx_offload_wq) {
+       if (adev->dm.hpd_rx_offload_wq && adev->dm.dc) {
                for (i = 0; i < adev->dm.dc->caps.max_links; i++) {
                        if (adev->dm.hpd_rx_offload_wq[i].wq) {
                                destroy_workqueue(adev->dm.hpd_rx_offload_wq[i].wq);
@@ -2121,6 +2120,17 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev)
        const struct dmcub_firmware_header_v1_0 *hdr;
        enum dmub_asic dmub_asic;
        enum dmub_status status;
+       static enum dmub_window_memory_type window_memory_type[DMUB_WINDOW_TOTAL] = {
+               DMUB_WINDOW_MEMORY_TYPE_FB,             //DMUB_WINDOW_0_INST_CONST
+               DMUB_WINDOW_MEMORY_TYPE_FB,             //DMUB_WINDOW_1_STACK
+               DMUB_WINDOW_MEMORY_TYPE_FB,             //DMUB_WINDOW_2_BSS_DATA
+               DMUB_WINDOW_MEMORY_TYPE_FB,             //DMUB_WINDOW_3_VBIOS
+               DMUB_WINDOW_MEMORY_TYPE_FB,             //DMUB_WINDOW_4_MAILBOX
+               DMUB_WINDOW_MEMORY_TYPE_FB,             //DMUB_WINDOW_5_TRACEBUFF
+               DMUB_WINDOW_MEMORY_TYPE_FB,             //DMUB_WINDOW_6_FW_STATE
+               DMUB_WINDOW_MEMORY_TYPE_FB,             //DMUB_WINDOW_7_SCRATCH_MEM
+               DMUB_WINDOW_MEMORY_TYPE_FB,             //DMUB_WINDOW_SHARED_STATE
+       };
        int r;
 
        switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
@@ -2218,7 +2228,7 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev)
                adev->dm.dmub_fw->data +
                le32_to_cpu(hdr->header.ucode_array_offset_bytes) +
                PSP_HEADER_BYTES;
-       region_params.is_mailbox_in_inbox = false;
+       region_params.window_memory_type = window_memory_type;
 
        status = dmub_srv_calc_region_info(dmub_srv, &region_params,
                                           &region_info);
@@ -2246,6 +2256,7 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev)
        memory_params.cpu_fb_addr = adev->dm.dmub_bo_cpu_addr;
        memory_params.gpu_fb_addr = adev->dm.dmub_bo_gpu_addr;
        memory_params.region_info = &region_info;
+       memory_params.window_memory_type = window_memory_type;
 
        adev->dm.dmub_fb_info =
                kzalloc(sizeof(*adev->dm.dmub_fb_info), GFP_KERNEL);
@@ -4399,6 +4410,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
        enum dc_connection_type new_connection_type = dc_connection_none;
        const struct dc_plane_cap *plane;
        bool psr_feature_enabled = false;
+       bool replay_feature_enabled = false;
        int max_overlay = dm->dc->caps.max_slave_planes;
 
        dm->display_indexes_num = dm->dc->caps.max_streams;
@@ -4510,6 +4522,23 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
                }
        }
 
+       /* Determine whether to enable Replay support by default. */
+       if (!(amdgpu_dc_debug_mask & DC_DISABLE_REPLAY)) {
+               switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
+               case IP_VERSION(3, 1, 4):
+               case IP_VERSION(3, 1, 5):
+               case IP_VERSION(3, 1, 6):
+               case IP_VERSION(3, 2, 0):
+               case IP_VERSION(3, 2, 1):
+               case IP_VERSION(3, 5, 0):
+                       replay_feature_enabled = true;
+                       break;
+               default:
+                       replay_feature_enabled = amdgpu_dc_feature_mask & DC_REPLAY_MASK;
+                       break;
+               }
+       }
+
        /* loops over all connectors on the board */
        for (i = 0; i < link_cnt; i++) {
                struct dc_link *link = NULL;
@@ -4578,6 +4607,11 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
                                amdgpu_dm_update_connector_after_detect(aconnector);
                                setup_backlight_device(dm, aconnector);
 
+                               /* Disable PSR if Replay can be enabled */
+                               if (replay_feature_enabled)
+                                       if (amdgpu_dm_set_replay_caps(link, aconnector))
+                                               psr_feature_enabled = false;
+
                                if (psr_feature_enabled)
                                        amdgpu_dm_set_psr_caps(link);
 
@@ -5219,6 +5253,7 @@ static void fill_dc_dirty_rects(struct drm_plane *plane,
                                struct drm_plane_state *new_plane_state,
                                struct drm_crtc_state *crtc_state,
                                struct dc_flip_addrs *flip_addrs,
+                               bool is_psr_su,
                                bool *dirty_regions_changed)
 {
        struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state);
@@ -5243,6 +5278,10 @@ static void fill_dc_dirty_rects(struct drm_plane *plane,
        num_clips = drm_plane_get_damage_clips_count(new_plane_state);
        clips = drm_plane_get_damage_clips(new_plane_state);
 
+       if (num_clips && (!amdgpu_damage_clips || (amdgpu_damage_clips < 0 &&
+                                                  is_psr_su)))
+               goto ffu;
+
        if (!dm_crtc_state->mpo_requested) {
                if (!num_clips || num_clips > DC_MAX_DIRTY_RECTS)
                        goto ffu;
@@ -6194,7 +6233,9 @@ create_stream_for_sink(struct drm_connector *connector,
                if (recalculate_timing) {
                        freesync_mode = get_highest_refresh_rate_mode(aconnector, false);
                        drm_mode_copy(&saved_mode, &mode);
+                       saved_mode.picture_aspect_ratio = mode.picture_aspect_ratio;
                        drm_mode_copy(&mode, freesync_mode);
+                       mode.picture_aspect_ratio = saved_mode.picture_aspect_ratio;
                } else {
                        decide_crtc_timing_for_drm_display_mode(
                                        &mode, preferred_mode, scale);
@@ -6402,10 +6443,82 @@ int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector,
        return ret;
 }
 
+/**
+ * DOC: panel power savings
+ *
+ * The display manager allows you to set your desired **panel power savings**
+ * level (between 0-4, with 0 representing off), e.g. using the following::
+ *
+ *   # echo 3 > /sys/class/drm/card0-eDP-1/amdgpu/panel_power_savings
+ *
+ * Modifying this value can have implications on color accuracy, so tread
+ * carefully.
+ */
+
+static ssize_t panel_power_savings_show(struct device *device,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct drm_connector *connector = dev_get_drvdata(device);
+       struct drm_device *dev = connector->dev;
+       u8 val;
+
+       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+       val = to_dm_connector_state(connector->state)->abm_level ==
+               ABM_LEVEL_IMMEDIATE_DISABLE ? 0 :
+               to_dm_connector_state(connector->state)->abm_level;
+       drm_modeset_unlock(&dev->mode_config.connection_mutex);
+
+       return sysfs_emit(buf, "%u\n", val);
+}
+
+static ssize_t panel_power_savings_store(struct device *device,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count)
+{
+       struct drm_connector *connector = dev_get_drvdata(device);
+       struct drm_device *dev = connector->dev;
+       long val;
+       int ret;
+
+       ret = kstrtol(buf, 0, &val);
+
+       if (ret)
+               return ret;
+
+       if (val < 0 || val > 4)
+               return -EINVAL;
+
+       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+       to_dm_connector_state(connector->state)->abm_level = val ?:
+               ABM_LEVEL_IMMEDIATE_DISABLE;
+       drm_modeset_unlock(&dev->mode_config.connection_mutex);
+
+       drm_kms_helper_hotplug_event(dev);
+
+       return count;
+}
+
+static DEVICE_ATTR_RW(panel_power_savings);
+
+static struct attribute *amdgpu_attrs[] = {
+       &dev_attr_panel_power_savings.attr,
+       NULL
+};
+
+static const struct attribute_group amdgpu_group = {
+       .name = "amdgpu",
+       .attrs = amdgpu_attrs
+};
+
 static void amdgpu_dm_connector_unregister(struct drm_connector *connector)
 {
        struct amdgpu_dm_connector *amdgpu_dm_connector = to_amdgpu_dm_connector(connector);
 
+       if (connector->connector_type == DRM_MODE_CONNECTOR_eDP &&
+           amdgpu_dm_abm_level < 0)
+               sysfs_remove_group(&connector->kdev->kobj, &amdgpu_group);
+
        drm_dp_aux_unregister(&amdgpu_dm_connector->dm_dp_aux.aux);
 }
 
@@ -6467,9 +6580,12 @@ void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector)
                state->vcpi_slots = 0;
                state->pbn = 0;
 
-               if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
-                       state->abm_level = amdgpu_dm_abm_level ?:
-                               ABM_LEVEL_IMMEDIATE_DISABLE;
+               if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+                       if (amdgpu_dm_abm_level <= 0)
+                               state->abm_level = ABM_LEVEL_IMMEDIATE_DISABLE;
+                       else
+                               state->abm_level = amdgpu_dm_abm_level;
+               }
 
                __drm_atomic_helper_connector_reset(connector, &state->base);
        }
@@ -6507,6 +6623,14 @@ amdgpu_dm_connector_late_register(struct drm_connector *connector)
                to_amdgpu_dm_connector(connector);
        int r;
 
+       if (connector->connector_type == DRM_MODE_CONNECTOR_eDP &&
+           amdgpu_dm_abm_level < 0) {
+               r = sysfs_create_group(&connector->kdev->kobj,
+                                      &amdgpu_group);
+               if (r)
+                       return r;
+       }
+
        amdgpu_dm_register_backlight_device(amdgpu_dm_connector);
 
        if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
@@ -7530,7 +7654,8 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
        aconnector->base.state->max_requested_bpc = aconnector->base.state->max_bpc;
 
        if (connector_type == DRM_MODE_CONNECTOR_eDP &&
-           (dc_is_dmcu_initialized(adev->dm.dc) || adev->dm.dc->ctx->dmub_srv)) {
+           (dc_is_dmcu_initialized(adev->dm.dc) ||
+            adev->dm.dc->ctx->dmub_srv) && amdgpu_dm_abm_level < 0) {
                drm_object_attach_property(&aconnector->base.base,
                                adev->mode_info.abm_level_property, 0);
        }
@@ -8298,6 +8423,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                        fill_dc_dirty_rects(plane, old_plane_state,
                                            new_plane_state, new_crtc_state,
                                            &bundle->flip_addrs[planes_count],
+                                           acrtc_state->stream->link->psr_settings.psr_version ==
+                                           DC_PSR_VERSION_SU_1,
                                            &dirty_rects_changed);
 
                        /*
@@ -8526,10 +8653,22 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                        dm_update_pflip_irq_state(drm_to_adev(dev),
                                                  acrtc_attach);
 
-               if ((acrtc_state->update_type > UPDATE_TYPE_FAST) &&
-                               acrtc_state->stream->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED &&
-                               !acrtc_state->stream->link->psr_settings.psr_feature_enabled)
-                       amdgpu_dm_link_setup_psr(acrtc_state->stream);
+               if (acrtc_state->update_type > UPDATE_TYPE_FAST) {
+                       if (acrtc_state->stream->link->replay_settings.config.replay_supported &&
+                                       !acrtc_state->stream->link->replay_settings.replay_feature_enabled) {
+                               struct amdgpu_dm_connector *aconn =
+                                       (struct amdgpu_dm_connector *)acrtc_state->stream->dm_stream_context;
+                               amdgpu_dm_link_setup_replay(acrtc_state->stream->link, aconn);
+                       } else if (acrtc_state->stream->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED &&
+                                       !acrtc_state->stream->link->psr_settings.psr_feature_enabled) {
+
+                               struct amdgpu_dm_connector *aconn = (struct amdgpu_dm_connector *)
+                                       acrtc_state->stream->dm_stream_context;
+
+                               if (!aconn->disallow_edp_enter_psr)
+                                       amdgpu_dm_link_setup_psr(acrtc_state->stream);
+                       }
+               }
 
                /* Decrement skip count when PSR is enabled and we're doing fast updates. */
                if (acrtc_state->update_type == UPDATE_TYPE_FAST &&
@@ -8556,6 +8695,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                            !amdgpu_dm_crc_window_is_activated(acrtc_state->base.crtc) &&
 #endif
                            !acrtc_state->stream->link->psr_settings.psr_allow_active &&
+                           !aconn->disallow_edp_enter_psr &&
                            (timestamp_ns -
                            acrtc_state->stream->link->psr_settings.psr_dirty_rects_change_timestamp_ns) >
                            500000000)
@@ -8818,11 +8958,12 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state,
                }
        } /* for_each_crtc_in_state() */
 
-       /* if there mode set or reset, disable eDP PSR */
+       /* if there mode set or reset, disable eDP PSR, Replay */
        if (mode_set_reset_required) {
                if (dm->vblank_control_workqueue)
                        flush_workqueue(dm->vblank_control_workqueue);
 
+               amdgpu_dm_replay_disable_all(dm);
                amdgpu_dm_psr_disable_all(dm);
        }
 
@@ -9187,6 +9328,10 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                 * To fix this, DC should permit updating only stream properties.
                 */
                dummy_updates = kzalloc(sizeof(struct dc_surface_update) * MAX_SURFACES, GFP_ATOMIC);
+               if (!dummy_updates) {
+                       DRM_ERROR("Failed to allocate memory for dummy_updates.\n");
+                       continue;
+               }
                for (j = 0; j < status->plane_count; j++)
                        dummy_updates[j].surface = status->plane_states[0];
 
@@ -10727,11 +10872,13 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
                        goto fail;
                }
 
-               ret = compute_mst_dsc_configs_for_state(state, dm_state->context, vars);
-               if (ret) {
-                       DRM_DEBUG_DRIVER("compute_mst_dsc_configs_for_state() failed\n");
-                       ret = -EINVAL;
-                       goto fail;
+               if (dc_resource_is_dsc_encoding_supported(dc)) {
+                       ret = compute_mst_dsc_configs_for_state(state, dm_state->context, vars);
+                       if (ret) {
+                               DRM_DEBUG_DRIVER("compute_mst_dsc_configs_for_state() failed\n");
+                               ret = -EINVAL;
+                               goto fail;
+                       }
                }
 
                ret = dm_update_mst_vcpi_slots_for_dsc(state, dm_state->context, vars);