mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Dmitry Osipenko <dmitry.osipenko@collabora.com>
To: "Rafael J. Wysocki" <rafael@kernel.org>,
	Mario Limonciello <superm1@kernel.org>,
	Robert Beckett <bob.beckett@collabora.com>
Cc: linux-acpi@vger.kernel.org, kernel@collabora.com,
	linux-kernel@vger.kernel.org,
	Sebastian Reichel <sebastian.reichel@collabora.com>,
	Xaver Hugl <xaver.hugl@gmail.com>,
	Richard Hughes <richard@hughsie.com>,
	William Jon McCann <mccann@jhu.edu>,
	"Jaap A . Haitsma" <jaap@haitsma.org>,
	Benjamin Canou <bookeldor@gmail.com>,
	Bastien Nocera <hadess@hadess.net>,
	systemd-devel@lists.freedesktop.org,
	Lennart Poettering <lennart@poettering.net>,
	Antheas Kapenekakis <lkml@antheas.dev>
Subject: [RFC PATCH v1 1/1] ACPI: PM: s2idle: Add lps0_screen_off sysfs interface
Date: Tue,  2 Dec 2025 07:34:16 +0300	[thread overview]
Message-ID: <20251202043416.2310677-2-dmitry.osipenko@collabora.com> (raw)
In-Reply-To: <20251202043416.2310677-1-dmitry.osipenko@collabora.com>

Add `/sys/power/lps0_screen_off` interface to allow userspace to control
Display OFF/ON DSM notifications at runtime. Writing "1" to this file
triggers the OFF notification, and "0" triggers the ON notification.

Userspace should write "1" after turning off all physical and remote
displays. It should write "0" before turning on any of displays.

Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 Documentation/ABI/testing/sysfs-power |  13 +++
 drivers/acpi/x86/s2idle.c             | 149 +++++++++++++++++++++++---
 2 files changed, 145 insertions(+), 17 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power
index d38da077905a..af7c81ae517c 100644
--- a/Documentation/ABI/testing/sysfs-power
+++ b/Documentation/ABI/testing/sysfs-power
@@ -470,3 +470,16 @@ Description:
 
                 Minimum value: 1
                 Default value: 3
+
+What:		/sys/power/lps0_screen_off
+Date:		November 2025
+Contact:	Dmitrii Osipenko <dmitry.osipenko@collabora.com>
+Description:
+		This file is available if the ACPI/OSPM system supports
+		Display Off/On DSM notifications. It controls state of the
+		notification.
+
+		Writing a "1" to this file invokes Display Off Notification.
+		Writing a "0" to this file invokes Display On Notification.
+
+		Notifications are only triggered on state transitions.
diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c
index 6d4d06236f61..d5cb5e22431d 100644
--- a/drivers/acpi/x86/s2idle.c
+++ b/drivers/acpi/x86/s2idle.c
@@ -18,7 +18,10 @@
 #include <linux/acpi.h>
 #include <linux/device.h>
 #include <linux/dmi.h>
+#include <linux/kobject.h>
+#include <linux/mutex.h>
 #include <linux/suspend.h>
+#include <linux/sysfs.h>
 
 #include "../sleep.h"
 
@@ -61,6 +64,11 @@ static guid_t lps0_dsm_guid_microsoft;
 static int lps0_dsm_func_mask_microsoft;
 static int lps0_dsm_state;
 
+static DEFINE_MUTEX(lps0_dsm_screen_off_lock);
+static bool lps0_dsm_screen_state_off;
+static bool lps0_screen_off_suspended;
+static bool lps0_screen_off_sysfs_inhibit;
+
 /* Device constraint entry structure */
 struct lpi_device_info {
 	char *name;
@@ -513,6 +521,76 @@ static struct acpi_scan_handler lps0_handler = {
 	.attach = lps0_device_attach,
 };
 
+static bool lps0_has_screen_off_dsm(void)
+{
+	int id = acpi_s2idle_vendor_amd() ?
+		 ACPI_LPS0_SCREEN_ON_AMD : ACPI_LPS0_SCREEN_OFF;
+
+	if (lps0_dsm_func_mask_microsoft > 0 &&
+	    (lps0_dsm_func_mask & BIT(ACPI_LPS0_SCREEN_OFF)))
+		return true;
+
+	if (lps0_dsm_func_mask > 0 && (lps0_dsm_func_mask & BIT(id)))
+		return true;
+
+	return false;
+}
+
+static void lps0_dsm_screen_off(void)
+{
+	if (lps0_dsm_screen_state_off)
+		return;
+
+	if (lps0_dsm_func_mask > 0)
+		acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
+					ACPI_LPS0_SCREEN_OFF_AMD :
+					ACPI_LPS0_SCREEN_OFF,
+					lps0_dsm_func_mask, lps0_dsm_guid);
+
+	if (lps0_dsm_func_mask_microsoft > 0)
+		acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF,
+					lps0_dsm_func_mask_microsoft,
+					lps0_dsm_guid_microsoft);
+
+	lps0_dsm_screen_state_off = true;
+}
+
+static void lps0_dsm_screen_on(void)
+{
+	if (!lps0_dsm_screen_state_off)
+		return;
+
+	if (lps0_dsm_func_mask_microsoft > 0)
+		acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON,
+					lps0_dsm_func_mask_microsoft,
+					lps0_dsm_guid_microsoft);
+
+	if (lps0_dsm_func_mask > 0)
+		acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
+					ACPI_LPS0_SCREEN_ON_AMD :
+					ACPI_LPS0_SCREEN_ON,
+					lps0_dsm_func_mask, lps0_dsm_guid);
+
+	lps0_dsm_screen_state_off = false;
+}
+
+static void lps0_dsm_screen_off_set(int sysfs_off, int suspended)
+{
+	mutex_lock(&lps0_dsm_screen_off_lock);
+
+	if (sysfs_off > -1)
+		lps0_screen_off_sysfs_inhibit = sysfs_off;
+	if (suspended > -1)
+		lps0_screen_off_suspended = suspended;
+
+	if (lps0_screen_off_suspended || lps0_screen_off_sysfs_inhibit)
+		lps0_dsm_screen_off();
+	else
+		lps0_dsm_screen_on();
+
+	mutex_unlock(&lps0_dsm_screen_off_lock);
+}
+
 static int acpi_s2idle_begin_lps0(void)
 {
 	if (pm_debug_messages_on && !lpi_constraints_table) {
@@ -543,15 +621,7 @@ static int acpi_s2idle_prepare_late_lps0(void)
 		lpi_check_constraints();
 
 	/* Screen off */
-	if (lps0_dsm_func_mask > 0)
-		acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
-					ACPI_LPS0_SCREEN_OFF_AMD :
-					ACPI_LPS0_SCREEN_OFF,
-					lps0_dsm_func_mask, lps0_dsm_guid);
-
-	if (lps0_dsm_func_mask_microsoft > 0)
-		acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF,
-				lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
+	lps0_dsm_screen_off_set(-1, true);
 
 	/* LPS0 entry */
 	if (lps0_dsm_func_mask > 0 && acpi_s2idle_vendor_amd())
@@ -618,14 +688,7 @@ static void acpi_s2idle_restore_early_lps0(void)
 	}
 
 	/* Screen on */
-	if (lps0_dsm_func_mask_microsoft > 0)
-		acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON,
-				lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
-	if (lps0_dsm_func_mask > 0)
-		acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
-					ACPI_LPS0_SCREEN_ON_AMD :
-					ACPI_LPS0_SCREEN_ON,
-					lps0_dsm_func_mask, lps0_dsm_guid);
+	lps0_dsm_screen_off_set(-1, false);
 }
 
 static const struct platform_s2idle_ops acpi_s2idle_ops_lps0 = {
@@ -673,4 +736,56 @@ void acpi_unregister_lps0_dev(struct acpi_s2idle_dev_ops *arg)
 }
 EXPORT_SYMBOL_GPL(acpi_unregister_lps0_dev);
 
+static ssize_t lps0_screen_off_store(struct kobject *kobj,
+				     struct kobj_attribute *attr,
+				     const char *buf, size_t count)
+{
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+
+	if (val > 1)
+		return -EINVAL;
+
+	lps0_dsm_screen_off_set(val, -1);
+
+	return count;
+}
+
+static ssize_t lps0_screen_off_show(struct kobject *kobj,
+				    struct kobj_attribute *attr,
+				    char *buf)
+{
+	return sprintf(buf, "%d\n", lps0_screen_off_sysfs_inhibit);
+}
+
+static struct kobj_attribute lps0_screen_off_attr =
+	__ATTR(lps0_screen_off, 0644,
+	       lps0_screen_off_show, lps0_screen_off_store);
+
+static struct attribute *lps0_screen_off_attrs[] = {
+	&lps0_screen_off_attr.attr,
+	NULL,
+};
+
+static struct attribute_group lps0_screen_off_attr_group = {
+	.attrs = lps0_screen_off_attrs,
+};
+
+static int lps0_dsm_screen_off_init(void)
+{
+	int ret;
+
+	if (!lps0_has_screen_off_dsm())
+		return 0;
+
+	ret = sysfs_create_group(power_kobj, &lps0_screen_off_attr_group);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+late_initcall(lps0_dsm_screen_off_init);
+
 #endif /* CONFIG_SUSPEND */
-- 
2.51.1


  reply	other threads:[~2025-12-02  4:36 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-12-02  4:34 [RFC PATCH v1 0/1] ACPI: s2idle: Add /sys/power/lps0_screen_off Dmitry Osipenko
2025-12-02  4:34 ` Dmitry Osipenko [this message]
2025-12-02  4:43   ` [RFC PATCH v1 1/1] ACPI: PM: s2idle: Add lps0_screen_off sysfs interface Mario Limonciello (AMD) (kernel.org)
2025-12-02  5:26     ` Dmitry Osipenko
2025-12-02  9:32   ` Antheas Kapenekakis
2025-12-02 14:23     ` Mario Limonciello
2025-12-02 15:17       ` Antheas Kapenekakis
2025-12-02 21:25         ` Mario Limonciello (AMD) (kernel.org)
2025-12-02 22:35           ` Dmitry Osipenko
2025-12-03  2:12             ` Mario Limonciello (AMD) (kernel.org)
2025-12-03  6:46               ` Dmitry Osipenko
2025-12-03 10:12                 ` Antheas Kapenekakis
2025-12-03 14:34                   ` Mario Limonciello
2025-12-03 14:46                     ` Antheas Kapenekakis
2025-12-02 21:59     ` Dmitry Osipenko
2025-12-03 14:58   ` Rafael J. Wysocki
2025-12-04 15:03     ` Dmitry Osipenko
2025-12-04 16:41       ` Rafael J. Wysocki
2025-12-04 18:31         ` Antheas Kapenekakis
2025-12-05 16:32           ` Rafael J. Wysocki
2025-12-05 16:46             ` Mario Limonciello (AMD) (kernel.org)
2025-12-05 17:22               ` Rafael J. Wysocki
2025-12-05 18:07                 ` Mario Limonciello
2025-12-05 19:37                   ` Rafael J. Wysocki
2025-12-05 19:42                     ` Mario Limonciello
2025-12-05 20:06                       ` Rafael J. Wysocki
2025-12-05 21:52                         ` Antheas Kapenekakis
2025-12-06 14:34                           ` Rafael J. Wysocki
2025-12-06 20:50                             ` Mario Limonciello
2025-12-06 23:35                               ` Antheas Kapenekakis
2025-12-07  0:31                                 ` Mario Limonciello
2025-12-07 10:34                                   ` Antheas Kapenekakis
2025-12-05 22:51             ` Antheas Kapenekakis
2025-12-07 11:06               ` Rafael J. Wysocki
2025-12-07 11:19                 ` Rafael J. Wysocki
2025-12-07 11:50                   ` Antheas Kapenekakis
2025-12-09 22:13                     ` Dmitry Osipenko
2025-12-09 22:22                       ` Antheas Kapenekakis
2025-12-09 22:23                       ` Rafael J. Wysocki
2025-12-07 11:42                 ` Antheas Kapenekakis
2025-12-05 13:34 ` [RFC PATCH v1 0/1] ACPI: s2idle: Add /sys/power/lps0_screen_off Pavel Machek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20251202043416.2310677-2-dmitry.osipenko@collabora.com \
    --to=dmitry.osipenko@collabora.com \
    --cc=bob.beckett@collabora.com \
    --cc=bookeldor@gmail.com \
    --cc=hadess@hadess.net \
    --cc=jaap@haitsma.org \
    --cc=kernel@collabora.com \
    --cc=lennart@poettering.net \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lkml@antheas.dev \
    --cc=mccann@jhu.edu \
    --cc=rafael@kernel.org \
    --cc=richard@hughsie.com \
    --cc=sebastian.reichel@collabora.com \
    --cc=superm1@kernel.org \
    --cc=systemd-devel@lists.freedesktop.org \
    --cc=xaver.hugl@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome