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 9bdd1f8..47338a8 100644 (file)
@@ -1939,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)
@@ -1957,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);
@@ -2130,7 +2128,8 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev)
                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_7_SCRATCH_MEM
+               DMUB_WINDOW_MEMORY_TYPE_FB,             //DMUB_WINDOW_SHARED_STATE
        };
        int r;
 
@@ -5254,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);
@@ -5278,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;
@@ -6229,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);
@@ -6437,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);
 }
 
@@ -6502,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);
        }
@@ -6542,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) ||
@@ -7565,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);
        }
@@ -7657,7 +7747,6 @@ create_i2c(struct ddc_service *ddc_service,
        if (!i2c)
                return NULL;
        i2c->base.owner = THIS_MODULE;
-       i2c->base.class = I2C_CLASS_DDC;
        i2c->base.dev.parent = &adev->pdev->dev;
        i2c->base.algo = &amdgpu_dm_i2c_algo;
        snprintf(i2c->base.name, sizeof(i2c->base.name), "AMDGPU DM i2c hw bus %d", link_index);
@@ -8334,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);
 
                        /*
@@ -9237,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];
 
@@ -10777,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);