All of lore.kernel.org
 help / color / mirror / Atom feed
From: Antheas Kapenekakis <lkml@antheas.dev>
To: Mario.Limonciello@amd.com
Cc: W_Armin@gmx.de, sashal@kernel.org, Shyam-Sundar.S-k@amd.com,
	derekjohn.clark@gmail.com, denis.benato@linux.dev, i@rong.moe,
	linux-kernel@vger.kernel.org,
	platform-driver-x86@vger.kernel.org,
	Antheas Kapenekakis <lkml@antheas.dev>
Subject: [RFC v4 3/4] platform/x86/amd: dptc: Add platform profile support
Date: Mon,  9 Mar 2026 21:51:24 +0100	[thread overview]
Message-ID: <20260309205125.293148-4-lkml@antheas.dev> (raw)
In-Reply-To: <20260309205125.293148-1-lkml@antheas.dev>

Register a platform_profile handler so the driver exposes standard
power profiles (low-power, balanced, performance) alongside the manual
tunable interface.

When a non-custom profile is active, parameter writes are blocked
(-EBUSY) and current_value reflects the profile's preset values.
Selecting the "custom" profile returns control to the user for manual
staging and committing. On resume, the active profile is automatically
re-applied.

Assisted-by: Claude:claude-opus-4-6
Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
---
 drivers/platform/x86/amd/Kconfig |   1 +
 drivers/platform/x86/amd/dptc.c  | 109 ++++++++++++++++++++++++++++++-
 2 files changed, 108 insertions(+), 2 deletions(-)

diff --git a/drivers/platform/x86/amd/Kconfig b/drivers/platform/x86/amd/Kconfig
index d610092467fc..41ffbd722524 100644
--- a/drivers/platform/x86/amd/Kconfig
+++ b/drivers/platform/x86/amd/Kconfig
@@ -48,6 +48,7 @@ config AMD_ISP_PLATFORM
 config AMD_DPTC
 	tristate "AMD Dynamic Power and Thermal Configuration Interface (DPTCi)"
 	depends on X86_64 && ACPI && DMI
+	select ACPI_PLATFORM_PROFILE
 	select FIRMWARE_ATTRIBUTES_CLASS
 	help
 	  Driver for AMD AGESA ALIB Function 0x0C, the Dynamic Power and
diff --git a/drivers/platform/x86/amd/dptc.c b/drivers/platform/x86/amd/dptc.c
index b884cdfa3f82..f4db95affb1b 100644
--- a/drivers/platform/x86/amd/dptc.c
+++ b/drivers/platform/x86/amd/dptc.c
@@ -23,6 +23,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
+#include <linux/platform_profile.h>
 #include <linux/processor.h>
 #include <linux/sysfs.h>
 #include <linux/unaligned.h>
@@ -56,8 +57,13 @@ struct dptc_param_limits {
 	u32 expanded_max;
 };
 
+struct dptc_profile {
+	u32 vals[DPTC_NUM_PARAMS];	/* 0 = don't set / unstage this param */
+};
+
 struct dptc_device_limits {
 	struct dptc_param_limits params[DPTC_NUM_PARAMS];
+	struct dptc_profile profiles[PLATFORM_PROFILE_LAST];
 };
 
 struct dptc_param_desc {
@@ -88,6 +94,11 @@ static const struct dptc_device_limits limits_maxhh = {
 		[DPTC_PPT_PL3_FPPT] = {  1,  4, 40,  85, 100 },
 		[DPTC_CPU_TEMP]     = { 60, 70, 95,  95, 100 },
 	},
+	.profiles = {
+		[PLATFORM_PROFILE_LOW_POWER]   = { .vals = { 15, 15, 25, 0 } },
+		[PLATFORM_PROFILE_BALANCED]    = { .vals = { 25, 27, 40, 0 } },
+		[PLATFORM_PROFILE_PERFORMANCE] = { .vals = { 60, 63, 85, 0 } },
+	},
 };
 
 /* Substring matches against boot_cpu_data.x86_model_id; order matters. */
@@ -139,11 +150,14 @@ struct dptc_priv {
 
 	bool expanded;
 
+	enum platform_profile_option profile;
+	struct device *ppdev;
+
 	enum dptc_save_mode save_mode;
 
 	u32 staged[DPTC_NUM_PARAMS];
 
-	/* Protects staged, expanded, and save_mode */
+	/* Protects staged, expanded, save_mode, and profile */
 	struct mutex lock;
 
 	struct dptc_attr_sysfs params[DPTC_NUM_PARAMS];
@@ -271,6 +285,14 @@ static ssize_t dptc_current_value_show(struct kobject *kobj,
 
 	guard(mutex)(&dptc->lock);
 
+	if (dptc->profile != PLATFORM_PROFILE_CUSTOM) {
+		u32 val = dptc->dev_limits->profiles[dptc->profile].vals[ps->idx];
+
+		if (!val)
+			return sysfs_emit(buf, "\n");
+		return sysfs_emit(buf, "%u\n", val);
+	}
+
 	if (!dptc->staged[ps->idx])
 		return sysfs_emit(buf, "\n");
 	return sysfs_emit(buf, "%u\n", dptc->staged[ps->idx]);
@@ -288,6 +310,9 @@ static ssize_t dptc_current_value_store(struct kobject *kobj,
 
 	guard(mutex)(&dptc->lock);
 
+	if (dptc->profile != PLATFORM_PROFILE_CUSTOM)
+		return -EBUSY;
+
 	if (count == 1 && buf[0] == '\n') {
 		dptc->staged[ps->idx] = 0;
 		return count;
@@ -425,6 +450,9 @@ static ssize_t dptc_expanded_current_value_store(struct kobject *kobj,
 
 	guard(mutex)(&dptc->lock);
 
+	if (dptc->profile != PLATFORM_PROFILE_CUSTOM)
+		return -EBUSY;
+
 	dptc->expanded = val;
 	/* Clear staged values: limits changed, old values may be out of range */
 	memset(dptc->staged, 0, sizeof(dptc->staged));
@@ -593,6 +621,75 @@ static void dptc_kset_unregister(void *data)
 	kset_unregister(data);
 }
 
+/* Platform profile */
+
+static int dptc_apply_profile(struct dptc_priv *dptc,
+			      enum platform_profile_option profile)
+{
+	const struct dptc_profile *pp;
+	int i;
+
+	memset(dptc->staged, 0, sizeof(dptc->staged));
+
+	if (profile == PLATFORM_PROFILE_CUSTOM)
+		return 0;
+
+	pp = &dptc->dev_limits->profiles[profile];
+	for (i = 0; i < DPTC_NUM_PARAMS; i++) {
+		if (!pp->vals[i])
+			continue;
+		dptc->staged[i] = pp->vals[i];
+	}
+
+	return dptc_alib_save(dptc);
+}
+
+static int dptc_pp_probe(void *drvdata, unsigned long *choices)
+{
+	struct dptc_priv *dptc = drvdata;
+	int i, j;
+
+	set_bit(PLATFORM_PROFILE_CUSTOM, choices);
+	for (i = 0; i < PLATFORM_PROFILE_LAST; i++) {
+		for (j = 0; j < DPTC_NUM_PARAMS; j++) {
+			if (dptc->dev_limits->profiles[i].vals[j]) {
+				set_bit(i, choices);
+				break;
+			}
+		}
+	}
+	return 0;
+}
+
+static int dptc_pp_get(struct device *dev,
+		       enum platform_profile_option *profile)
+{
+	struct dptc_priv *dptc = dev_get_drvdata(dev);
+
+	guard(mutex)(&dptc->lock);
+
+	*profile = dptc->profile;
+	return 0;
+}
+
+static int dptc_pp_set(struct device *dev,
+		       enum platform_profile_option profile)
+{
+	struct dptc_priv *dptc = dev_get_drvdata(dev);
+
+	guard(mutex)(&dptc->lock);
+
+	dptc->profile = profile;
+
+	return dptc_apply_profile(dptc, profile);
+}
+
+static const struct platform_profile_ops dptc_pp_ops = {
+	.probe       = dptc_pp_probe,
+	.profile_get = dptc_pp_get,
+	.profile_set = dptc_pp_set,
+};
+
 static int dptc_resume(struct device *dev)
 {
 	struct dptc_priv *dptc = dev_get_drvdata(dev);
@@ -601,7 +698,9 @@ static int dptc_resume(struct device *dev)
 	guard(mutex)(&dptc->lock);
 
 	/* In bulk mode, do not use pm ops for userspace flexibility. */
-	if (dptc->save_mode == SAVE_SINGLE)
+	if (dptc->profile != PLATFORM_PROFILE_CUSTOM)
+		ret = dptc_apply_profile(dptc, dptc->profile);
+	else if (dptc->save_mode == SAVE_SINGLE)
 		ret = dptc_alib_save(dptc);
 	else
 		ret = 0;
@@ -679,6 +778,12 @@ static int dptc_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	dptc->profile = PLATFORM_PROFILE_CUSTOM;
+	dptc->ppdev = devm_platform_profile_register(dev, "amd-dptc", dptc,
+						     &dptc_pp_ops);
+	if (IS_ERR(dptc->ppdev))
+		return PTR_ERR(dptc->ppdev);
+
 	return 0;
 }
 
-- 
2.52.0



  parent reply	other threads:[~2026-03-09 20:52 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-09 20:51 [RFC v4 0/4] platform/x86/amd: Add AMD DPTCi driver for TDP control in devices without vendor-specific controls Antheas Kapenekakis
2026-03-09 20:51 ` [RFC v4 1/4] Documentation: firmware-attributes: generalize save_settings entry Antheas Kapenekakis
2026-03-09 20:51 ` [RFC v4 2/4] platform/x86/amd: dptc: Add AMD DPTCi driver Antheas Kapenekakis
2026-03-10  4:01   ` Mario Limonciello
2026-03-10  8:02     ` Antheas Kapenekakis
2026-03-10 16:26       ` Mario Limonciello
2026-03-11 19:09         ` Antheas Kapenekakis
2026-03-12 13:24           ` Mario Limonciello
2026-03-12 13:47             ` Antheas Kapenekakis
2026-03-12 16:05               ` Mario Limonciello
2026-03-12 16:19                 ` Antheas Kapenekakis
2026-03-09 20:51 ` Antheas Kapenekakis [this message]
2026-03-10  4:07   ` [RFC v4 3/4] platform/x86/amd: dptc: Add platform profile support Mario Limonciello
2026-03-09 20:51 ` [RFC v4 4/4] platform/x86/amd: dptc: Add device entries for handheld PCs Antheas Kapenekakis
2026-03-10  4:11   ` Mario Limonciello
2026-03-10  8:13     ` Antheas Kapenekakis
2026-03-10 16:35       ` Mario Limonciello
2026-03-11 19:13         ` Antheas Kapenekakis
2026-03-12 13:26           ` Mario Limonciello
2026-03-10  2:43 ` [RFC v4 0/4] platform/x86/amd: Add AMD DPTCi driver for TDP control in devices without vendor-specific controls Mario Limonciello
2026-03-10  7:59   ` Antheas Kapenekakis

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=20260309205125.293148-4-lkml@antheas.dev \
    --to=lkml@antheas.dev \
    --cc=Mario.Limonciello@amd.com \
    --cc=Shyam-Sundar.S-k@amd.com \
    --cc=W_Armin@gmx.de \
    --cc=denis.benato@linux.dev \
    --cc=derekjohn.clark@gmail.com \
    --cc=i@rong.moe \
    --cc=linux-kernel@vger.kernel.org \
    --cc=platform-driver-x86@vger.kernel.org \
    --cc=sashal@kernel.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.