When the `panel_power_saving` property is set to "Forbidden" ABM
should be disabled immediately and any requests by sysfs to update
will return an -EBUSY error.

When the property is restored to "Allowed" the previous value of
ABM will be restored.

Signed-off-by: Mario Limonciello <mario.limoncie...@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_display.c   |  3 ++
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 36 ++++++++++++++++---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  1 +
 3 files changed, 35 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
index 3ecc7ef95172..6e6531c93d81 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
@@ -1350,6 +1350,9 @@ int amdgpu_display_modeset_create_props(struct 
amdgpu_device *adev)
                                         "dither",
                                         amdgpu_dither_enum_list, sz);
 
+       if (adev->dc_enabled)
+               drm_mode_create_panel_power_saving_property(adev_to_drm(adev));
+
        return 0;
 }
 
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 01b0a331e4a6..f6b80018b136 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6421,6 +6421,12 @@ int amdgpu_dm_connector_atomic_set_property(struct 
drm_connector *connector,
        } else if (property == adev->mode_info.underscan_property) {
                dm_new_state->underscan_enable = val;
                ret = 0;
+       } else if (property == dev->mode_config.panel_power_saving) {
+               dm_new_state->abm_forbidden = val;
+               dm_new_state->abm_level = (val || !amdgpu_dm_abm_level) ?
+                                               ABM_LEVEL_IMMEDIATE_DISABLE :
+                                               amdgpu_dm_abm_level;
+               ret = 0;
        }
 
        return ret;
@@ -6463,6 +6469,9 @@ int amdgpu_dm_connector_atomic_get_property(struct 
drm_connector *connector,
        } else if (property == adev->mode_info.underscan_property) {
                *val = dm_state->underscan_enable;
                ret = 0;
+       } else if (property == dev->mode_config.panel_power_saving) {
+               *val = dm_state->abm_forbidden;
+               ret = 0;
        }
 
        return ret;
@@ -6489,9 +6498,12 @@ static ssize_t panel_power_savings_show(struct device 
*device,
        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;
+       if (to_dm_connector_state(connector->state)->abm_forbidden)
+               val = 0;
+       else
+               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);
@@ -6515,10 +6527,16 @@ static ssize_t panel_power_savings_store(struct device 
*device,
                return -EINVAL;
 
        drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
-       to_dm_connector_state(connector->state)->abm_level = val ?:
-               ABM_LEVEL_IMMEDIATE_DISABLE;
+       if (to_dm_connector_state(connector->state)->abm_forbidden)
+               ret = -EBUSY;
+       else
+               to_dm_connector_state(connector->state)->abm_level = val ?:
+                       ABM_LEVEL_IMMEDIATE_DISABLE;
        drm_modeset_unlock(&dev->mode_config.connection_mutex);
 
+       if (ret)
+               return ret;
+
        drm_kms_helper_hotplug_event(dev);
 
        return count;
@@ -7689,6 +7707,14 @@ void amdgpu_dm_connector_init_helper(struct 
amdgpu_display_manager *dm,
        aconnector->base.state->max_bpc = 16;
        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) && amdgpu_dm_abm_level < 0) {
+               drm_object_attach_property(&aconnector->base.base,
+                               dm->ddev->mode_config.panel_power_saving,
+                               DRM_MODE_PANEL_POWER_SAVING_ALLOWED);
+       }
+
        if (connector_type == DRM_MODE_CONNECTOR_HDMIA) {
                /* Content Type is currently only implemented for HDMI. */
                drm_connector_attach_content_type_property(&aconnector->base);
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 09519b7abf67..43c3e5845a94 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -873,6 +873,7 @@ struct dm_connector_state {
        bool underscan_enable;
        bool freesync_capable;
        bool update_hdcp;
+       bool abm_forbidden;
        uint8_t abm_level;
        int vcpi_slots;
        uint64_t pbn;
-- 
2.45.0

Reply via email to