@@ -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;
}
@@ -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);
@@ -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;
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.limonciello@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(-)