diff mbox series

drm/amd/display: add panel_power_savings sysfs entry to eDP connectors

Message ID 20240126222300.119292-1-hamza.mahfooz@amd.com (mailing list archive)
State New, archived
Headers show
Series drm/amd/display: add panel_power_savings sysfs entry to eDP connectors | expand

Commit Message

Hamza Mahfooz Jan. 26, 2024, 10:22 p.m. UTC
We want programs besides the compositor to be able to enable or disable
panel power saving features. However, since they are currently only
configurable through DRM properties, that isn't possible. So, to remedy
that issue introduce a new "panel_power_savings" sysfs attribute.

Cc: Mario Limonciello <mario.limonciello@amd.com>
Signed-off-by: Hamza Mahfooz <hamza.mahfooz@amd.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 59 +++++++++++++++++++
 1 file changed, 59 insertions(+)

Comments

Mario Limonciello Jan. 26, 2024, 10:34 p.m. UTC | #1
On 1/26/2024 16:22, Hamza Mahfooz wrote:
> We want programs besides the compositor to be able to enable or disable
> panel power saving features. However, since they are currently only
> configurable through DRM properties, that isn't possible. So, to remedy
> that issue introduce a new "panel_power_savings" sysfs attribute.
> 
> Cc: Mario Limonciello <mario.limonciello@amd.com>
> Signed-off-by: Hamza Mahfooz <hamza.mahfooz@amd.com>
> ---
>   .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 59 +++++++++++++++++++
>   1 file changed, 59 insertions(+)
> 
> 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 cd98b3565178..b3fcd833015d 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -6534,6 +6534,58 @@ amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector)
>   	return &new_state->base;
>   }
>   
> +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;
> +	ssize_t val;
> +
> +	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
> +	val = to_dm_connector_state(connector->state)->abm_level;
> +	drm_modeset_unlock(&dev->mode_config.connection_mutex);
> +
> +	return sysfs_emit(buf, "%lu\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);
> +
> +	return count;
> +}
> +

To make this more discoverable I think you want some kerneldoc.

> +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 int
>   amdgpu_dm_connector_late_register(struct drm_connector *connector)
>   {
> @@ -6541,6 +6593,13 @@ amdgpu_dm_connector_late_register(struct drm_connector *connector)
>   		to_amdgpu_dm_connector(connector);
>   	int r;
>   
> +	if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
> +		r = sysfs_create_group(&connector->kdev->kobj,
> +				       &amdgpu_group);
> +		if (r)
> +			return r;
> +	}
> +

I think there should be some matching code sysfs_remove_group(), maybe 
in early_unregister() callback.

>   	amdgpu_dm_register_backlight_device(amdgpu_dm_connector);
>   
>   	if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
Dominik Förderer Jan. 27, 2024, 6:21 p.m. UTC | #2
I've applied the patch to 6.7.2. The device then shows up under:

|/sys/devices/pci0000:00/0000:00:08.1/0000:c1:00.0/drm/card1/card1-eDP-1/amdgpu/panel_power_savings|
|||(on Framework Laptop 13 amd 7840U with 780M).|
||
After a few tests i can say that at least in my system it’s not working. 
Setting a value between 0 and 4 in /sys/.../panel_power_savings changes 
nothing in the panel behavior. There are no errors in kernel log.

Setting an abmlevel via kernel option still works as intended.

||An other investigation is, that when setting abmlevel=0 via kernel 
option the value shown in /sys/.../panel_power_savings is 255 instead of 
0. For abmleve values 1 to 4 set via kernel option the values shown in 
/sys/.../panel_power_savings are the same.


||

Am 26.01.24 um 23:22 schrieb Hamza Mahfooz:
> We want programs besides the compositor to be able to enable or disable
> panel power saving features. However, since they are currently only
> configurable through DRM properties, that isn't possible. So, to remedy
> that issue introduce a new "panel_power_savings" sysfs attribute.
>
> Cc: Mario Limonciello <mario.limonciello@amd.com>
> Signed-off-by: Hamza Mahfooz <hamza.mahfooz@amd.com>
> ---
>   .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 59 +++++++++++++++++++
>   1 file changed, 59 insertions(+)
>
> 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 cd98b3565178..b3fcd833015d 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -6534,6 +6534,58 @@ amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector)
>   	return &new_state->base;
>   }
>   
> +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;
> +	ssize_t val;
> +
> +	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
> +	val = to_dm_connector_state(connector->state)->abm_level;
> +	drm_modeset_unlock(&dev->mode_config.connection_mutex);
> +
> +	return sysfs_emit(buf, "%lu\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);
> +
> +	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 int
>   amdgpu_dm_connector_late_register(struct drm_connector *connector)
>   {
> @@ -6541,6 +6593,13 @@ amdgpu_dm_connector_late_register(struct drm_connector *connector)
>   		to_amdgpu_dm_connector(connector);
>   	int r;
>   
> +	if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
> +		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) ||
Mario Limonciello Jan. 28, 2024, 5:38 a.m. UTC | #3
On 1/26/2024 16:34, Mario Limonciello wrote:
> On 1/26/2024 16:22, Hamza Mahfooz wrote:
>> We want programs besides the compositor to be able to enable or disable
>> panel power saving features. However, since they are currently only
>> configurable through DRM properties, that isn't possible. So, to remedy
>> that issue introduce a new "panel_power_savings" sysfs attribute.
>>
>> Cc: Mario Limonciello <mario.limonciello@amd.com>
>> Signed-off-by: Hamza Mahfooz <hamza.mahfooz@amd.com>
>> ---
>>   .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 59 +++++++++++++++++++
>>   1 file changed, 59 insertions(+)
>>
>> 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 cd98b3565178..b3fcd833015d 100644
>> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
>> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
>> @@ -6534,6 +6534,58 @@ 
>> amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector 
>> *connector)
>>       return &new_state->base;
>>   }
>> +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;
>> +    ssize_t val;
>> +
>> +    drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
>> +    val = to_dm_connector_state(connector->state)->abm_level;
>> +    drm_modeset_unlock(&dev->mode_config.connection_mutex);
>> +
>> +    return sysfs_emit(buf, "%lu\n", val);

When the system is first booted up with nothing on the kernel command 
line, this emits the value for ABM_LEVEL_IMMEDIATE_DISABLE, which isn't 
something we normally should be showing to people.

I think you should be special casing it similar to how the store special 
case works.

>> +}
>> +
>> +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);
>> +

It appears that the ABM doesn't actually take effect by writing this 
value until the next modeset.
This is also reported by Dominik Förderer.  I suggested he try to change 
resolutions in his DE and that activated ABM.

So I think it's missing another call to flush out to the hardware.

>> +    return count;
>> +}
>> +
> 
> To make this more discoverable I think you want some kerneldoc.
> 
>> +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 int
>>   amdgpu_dm_connector_late_register(struct drm_connector *connector)
>>   {
>> @@ -6541,6 +6593,13 @@ amdgpu_dm_connector_late_register(struct 
>> drm_connector *connector)
>>           to_amdgpu_dm_connector(connector);
>>       int r;
>> +    if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
>> +        r = sysfs_create_group(&connector->kdev->kobj,
>> +                       &amdgpu_group);
>> +        if (r)
>> +            return r;
>> +    }
>> +
> 
> I think there should be some matching code sysfs_remove_group(), maybe 
> in early_unregister() callback.
> 
>>       amdgpu_dm_register_backlight_device(amdgpu_dm_connector);
>>       if ((connector->connector_type == 
>> DRM_MODE_CONNECTOR_DisplayPort) ||
>
Dominik Förderer Jan. 28, 2024, 10:26 a.m. UTC | #4
I've applied the patch to 6.7.2. The device then shows up under:

/sys/devices/pci0000:00/0000:00:08.1/0000:c1:00.0/drm/card1/card1-eDP-1/amdgpu/panel_power_savings
(on Framework Laptop 13 amd 7840U with 780M).

After a few tests i can say that at least in my system it’s not working. 
Setting a value between 0 and 4 in /sys/.../panel_power_savings changes 
nothing in the panel behavior. There are no errors in kernel log.

Setting an abmlevel via kernel option still works as intended.


The issue can be resolved if one set the panel_power_savings value and 
after that change the display resolution to a lower value and than 
switch back. For example this script works:


xterm -e 'echo 0 | sudo tee 
/sys/devices/pci0000:00/0000:00:08.1/0000:c1:00.0/drm/card1/card1-eDP-1/amdgpu/panel_power_savings'
gnome-randr modify -m 1920x1200@59.999 eDP-1 && gnome-randr modify -m 
2256x1504@59.999 eDP-1


Am 26.01.24 um 23:22 schrieb Hamza Mahfooz:
> We want programs besides the compositor to be able to enable or disable
> panel power saving features. However, since they are currently only
> configurable through DRM properties, that isn't possible. So, to remedy
> that issue introduce a new "panel_power_savings" sysfs attribute.
>
> Cc: Mario Limonciello <mario.limonciello@amd.com>
> Signed-off-by: Hamza Mahfooz <hamza.mahfooz@amd.com>
> ---
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 59 +++++++++++++++++++
> 1 file changed, 59 insertions(+)
>
> 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 cd98b3565178..b3fcd833015d 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -6534,6 +6534,58 @@ 
> amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector 
> *connector)
> return &new_state->base;
> }
> +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;
> + ssize_t val;
> +
> + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
> + val = to_dm_connector_state(connector->state)->abm_level;
> + drm_modeset_unlock(&dev->mode_config.connection_mutex);
> +
> + return sysfs_emit(buf, "%lu\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);
> +
> + 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 int
> amdgpu_dm_connector_late_register(struct drm_connector *connector)
> {
> @@ -6541,6 +6593,13 @@ amdgpu_dm_connector_late_register(struct 
> drm_connector *connector)
> to_amdgpu_dm_connector(connector);
> int r;
> + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
> + 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) ||
Dominik Förderer Jan. 28, 2024, 10:28 a.m. UTC | #5
I've applied the patch to 6.7.2. The device then shows up under:

/sys/devices/pci0000:00/0000:00:08.1/0000:c1:00.0/drm/card1/card1-eDP-1/amdgpu/panel_power_savings
(on Framework Laptop 13 amd 7840U with 780M).

After a few tests i can say that at least in my system it’s not working. 
Setting a value between 0 and 4 in /sys/.../panel_power_savings changes 
nothing in the panel behavior. There are no errors in kernel log.

Setting an abmlevel via kernel option still works as intended.


The issue can be resolved if one set the panel_power_savings value and 
after that change the display resolution to a lower value and than 
switch back. For example this script works:


xterm -e 'echo 0 | sudo tee 
/sys/devices/pci0000:00/0000:00:08.1/0000:c1:00.0/drm/card1/card1-eDP-1/amdgpu/panel_power_savings'
gnome-randr modify -m 1920x1200@59.999 eDP-1 && gnome-randr modify -m 
2256x1504@59.999 eDP-1


Am 26.01.24 um 23:22 schrieb Hamza Mahfooz:
> We want programs besides the compositor to be able to enable or disable
> panel power saving features. However, since they are currently only
> configurable through DRM properties, that isn't possible. So, to remedy
> that issue introduce a new "panel_power_savings" sysfs attribute.
>
> Cc: Mario Limonciello <mario.limonciello@amd.com>
> Signed-off-by: Hamza Mahfooz <hamza.mahfooz@amd.com>
> ---
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 59 +++++++++++++++++++
> 1 file changed, 59 insertions(+)
>
> 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 cd98b3565178..b3fcd833015d 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -6534,6 +6534,58 @@ 
> amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector 
> *connector)
> return &new_state->base;
> }
> +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;
> + ssize_t val;
> +
> + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
> + val = to_dm_connector_state(connector->state)->abm_level;
> + drm_modeset_unlock(&dev->mode_config.connection_mutex);
> +
> + return sysfs_emit(buf, "%lu\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);
> +
> + 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 int
> amdgpu_dm_connector_late_register(struct drm_connector *connector)
> {
> @@ -6541,6 +6593,13 @@ amdgpu_dm_connector_late_register(struct 
> drm_connector *connector)
> to_amdgpu_dm_connector(connector);
> int r;
> + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
> + 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) ||
Dominik Förderer Jan. 28, 2024, 10:30 a.m. UTC | #6
I've applied the patch to 6.7.2. The device then shows up under:

/sys/devices/pci0000:00/0000:00:08.1/0000:c1:00.0/drm/card1/card1-eDP-1/amdgpu/panel_power_savings
(on Framework Laptop 13 amd 7840U with 780M).

After a few tests i can say that at least in my system it’s not working. 
Setting a value between 0 and 4 in /sys/.../panel_power_savings changes 
nothing in the panel behavior. There are no errors in kernel log.

Setting an abmlevel via kernel option still works as intended.


The issue can be resolved if one set the panel_power_savings value and 
after that change the display resolution to a lower value and than 
switch back. For example this script works:


xterm -e 'echo 0 | sudo tee 
/sys/devices/pci0000:00/0000:00:08.1/0000:c1:00.0/drm/card1/card1-eDP-1/amdgpu/panel_power_savings'
gnome-randr modify -m 1920x1200@59.999 eDP-1 && gnome-randr modify -m 
2256x1504@59.999 eDP-1


Am 26.01.24 um 23:22 schrieb Hamza Mahfooz:
> We want programs besides the compositor to be able to enable or disable
> panel power saving features. However, since they are currently only
> configurable through DRM properties, that isn't possible. So, to remedy
> that issue introduce a new "panel_power_savings" sysfs attribute.
>
> Cc: Mario Limonciello <mario.limonciello@amd.com>
> Signed-off-by: Hamza Mahfooz <hamza.mahfooz@amd.com>
> ---
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 59 +++++++++++++++++++
> 1 file changed, 59 insertions(+)
>
> 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 cd98b3565178..b3fcd833015d 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -6534,6 +6534,58 @@ 
> amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector 
> *connector)
> return &new_state->base;
> }
> +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;
> + ssize_t val;
> +
> + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
> + val = to_dm_connector_state(connector->state)->abm_level;
> + drm_modeset_unlock(&dev->mode_config.connection_mutex);
> +
> + return sysfs_emit(buf, "%lu\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);
> +
> + 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 int
> amdgpu_dm_connector_late_register(struct drm_connector *connector)
> {
> @@ -6541,6 +6593,13 @@ amdgpu_dm_connector_late_register(struct 
> drm_connector *connector)
> to_amdgpu_dm_connector(connector);
> int r;
> + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
> + 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) ||
Dominik Förderer Jan. 28, 2024, 6:33 p.m. UTC | #7
I've applied the patch to 6.7.2. The device then shows up under:

/sys/devices/pci0000:00/0000:00:08.1/0000:c1:00.0/drm/card1/card1-eDP-1/amdgpu/panel_power_savings
(on Framework Laptop 13 amd 7840U with 780M).

After a few tests i can say that at least in my system it’s not  
working. Setting a value between 0 and 4 in
/sys/.../panel_power_savings changes nothing in the panel behavior.  
There are no errors in kernel log.

Setting an abmlevel via kernel option still works as intended.

The issue can be resolved if one set the panel_power_savings value and  
after that change the display resolution to a lower value and than  
switch back. For example this script works:

xterm -e 'echo 0 | sudo tee  
/sys/devices/pci0000:00/0000:00:08.1/0000:c1:00.0/drm/card1/card1-eDP-1/amdgpu/panel_power_savings'
gnome-randr modify -m 1920x1200@59.999 eDP-1 && gnome-randr modify -m  
2256x1504@59.999 eDP-1

> Am 26.01.24 um 23:22 schrieb Hamza Mahfooz:
> We want programs besides the compositor to be able to enable or disable
> panel power saving features. However, since they are currently only
> configurable through DRM properties, that isn't possible. So, to remedy
> that issue introduce a new "panel_power_savings" sysfs attribute.
>
> Cc: Mario Limonciello <mario.limonciello@amd.com>
> Signed-off-by: Hamza Mahfooz <hamza.mahfooz@amd.com>
> ---
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 59 +++++++++++++++++++
> 1 file changed, 59 insertions(+)
>
> 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 cd98b3565178..b3fcd833015d 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -6534,6 +6534,58 @@  
> amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector  
> *connector)
> return &new_state->base;
> }
> +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;
> + ssize_t val;
> +
> + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
> + val = to_dm_connector_state(connector->state)->abm_level;
> + drm_modeset_unlock(&dev->mode_config.connection_mutex);
> +
> + return sysfs_emit(buf, "%lu\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);
> +
> + 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 int
> amdgpu_dm_connector_late_register(struct drm_connector *connector)
> {
> @@ -6541,6 +6593,13 @@ amdgpu_dm_connector_late_register(struct  
> drm_connector *connector)
> to_amdgpu_dm_connector(connector);
> int r;
> + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
> + 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) ||
diff mbox series

Patch

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 cd98b3565178..b3fcd833015d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6534,6 +6534,58 @@  amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector)
 	return &new_state->base;
 }
 
+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;
+	ssize_t val;
+
+	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+	val = to_dm_connector_state(connector->state)->abm_level;
+	drm_modeset_unlock(&dev->mode_config.connection_mutex);
+
+	return sysfs_emit(buf, "%lu\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);
+
+	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 int
 amdgpu_dm_connector_late_register(struct drm_connector *connector)
 {
@@ -6541,6 +6593,13 @@  amdgpu_dm_connector_late_register(struct drm_connector *connector)
 		to_amdgpu_dm_connector(connector);
 	int r;
 
+	if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+		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) ||