Add omarchy-power-profiles-daemon 0.30, with a CPPC driver for ARM laptops (#897)

power-profiles-daemon only drives intel_pstate, amd_pstate and ACPI
platform_profile, so ARM laptops on cppc_cpufreq (NVIDIA N1X, Snapdragon X)
get placeholder profiles that change nothing and no performance profile.

This packages upstream 0.30 with a CPPC driver patch: balanced (EPP 64) and
power-saver (EPP 192) use CPPC autonomous frequency selection, performance
runs the performance governor. The driver only claims policies with the
schedutil and performance governors and writable autonomous selection knobs,
restores probe-time settings if the first activation fails, and reapplies the
profile on resume. The package provides and conflicts with
power-profiles-daemon, and fixes the powerprofilesctl shebang at package time
so Omarchy no longer needs to sed it.

Tested on an NVIDIA N1X laptop: median keystroke-to-frame latency in Chromium
went from ~130ms (schedutil) to ~56ms on balanced at the same idle power, and
~32ms on performance, which Omarchy selects on AC. All 137 upstream tests
pass, including five new CPPC tests.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
David Heinemeier HanssonandClaude Opus 5.5 authored and GitHub committed 2026-10-09 14:40:56 +00:00
1 parent 8b8ede46ed
commit cbded97503
3 files changed
+648

No files matched your search

@@ -0,0 +1,9 @@
{
"source": "local",
"upstream": {
"watch": {
"git_tags": "https://gitlab.freedesktop.org/upower/power-profiles-daemon.git",
"pattern": "(?P<version>[0-9]+(?:\\.[0-9]+)*)"
}
}
}
@@ -0,0 +1,68 @@
# Maintainer: David Heinemeier Hansson <david@hey.com>
# Contributor: Antonio Rojas <arojas@archlinux.org>
# Contributor: tinywrkb <tinywrkb@gmail.com>
pkgname=omarchy-power-profiles-daemon
_pkgname=power-profiles-daemon
pkgver=0.30
pkgrel=1
pkgdesc='Makes power profiles handling available over D-Bus (with CPPC support for ARM laptops)'
url='https://gitlab.freedesktop.org/upower/power-profiles-daemon'
license=(GPL-3.0-only)
arch=(x86_64 aarch64)
depends=(glib2
glibc
libgcc
libgudev
polkit
upower)
optdepends=('python-gobject: for powerprofilesctl')
makedepends=(bash-completion
git
glib2-devel
python-argparse-manpage
python-shtab
meson)
checkdepends=(python-dbusmock
python-isort
python-mccabe
umockdev)
provides=(power-profiles-daemon)
conflicts=(power-profiles-daemon)
source=(git+https://gitlab.freedesktop.org/upower/$_pkgname#tag=$pkgver
cppc-cpufreq-driver.patch)
sha256sums=('e955e833b01cbff9b5b00349592239e58c559d717eb49f3371f42932676e7a40'
'7fc9d53cc5c5d07cafbff1d249544128d3d11e4a5cfd3784d7a55dee5870cddb')
prepare() {
cd $_pkgname
# Upstream only drives intel_pstate, amd_pstate and ACPI platform_profile, so
# ARM laptops on cppc_cpufreq (NVIDIA N1X, Snapdragon X) get placeholder
# profiles that change nothing. This adds a CPPC driver: balanced and
# power-saver use CPPC autonomous frequency selection, performance runs the
# performance governor.
patch -p1 -i "$srcdir/cppc-cpufreq-driver.patch"
}
build() {
meson $_pkgname build \
--prefix /usr \
--libexec lib \
--sysconfdir /usr/share \
-Dzshcomp=/usr/share/zsh/site-functions \
-Dbashcomp=enabled \
-Dmanpage=enabled
meson compile -C build
}
check() {
meson test -C build
}
package() {
meson install -C build --destdir "$pkgdir"
# Run powerprofilesctl with the system Python, not whichever python3 a mise
# or venv puts first on PATH, which lacks PyGObject.
sed -i '1c #!/usr/bin/python3' "$pkgdir/usr/bin/powerprofilesctl"
}
@@ -0,0 +1,571 @@
From d0b09a5248723d68ba3bd38ce50af1b29a119dd6 Mon Sep 17 00:00:00 2001
From: David Heinemeier Hansson <david@hey.com>
Date: Fri, 9 Oct 2026 15:46:37 +0200
Subject: [PATCH] Add CPPC cpufreq driver
Adds a CPU profile driver for the generic ACPI CPPC cpufreq driver
(cppc_cpufreq) used on ARM64 laptops, which previously only got the
placeholder driver and so had no working profiles at all.
Balanced and power-saver enable CPPC autonomous frequency selection
with an energy performance preference of 64 and 192 respectively.
Performance leaves autonomous selection and runs the performance
governor.
The driver only probes policies that offer both the schedutil and
performance governors and writable autonomous selection knobs. A failed
first activation restores the settings found at probe time, and the
active profile is reapplied on resume in case firmware reset the CPPC
registers.
On an NVIDIA N1X laptop, balanced cut median keystroke-to-frame
latency in Chromium from ~130ms (schedutil) to ~56ms at the same idle
power, and performance to ~32ms.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---
src/meson.build | 1 +
src/power-profiles-daemon.c | 2 +
src/ppd-driver-cppc.c | 334 ++++++++++++++++++++++++++++++++++++
src/ppd-driver-cppc.h | 16 ++
tests/integration_test.py | 128 ++++++++++++++
5 files changed, 481 insertions(+)
create mode 100644 src/ppd-driver-cppc.c
create mode 100644 src/ppd-driver-cppc.h
diff --git a/src/meson.build b/src/meson.build
index 0056466..c6c1eb2 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -93,6 +93,7 @@ sources += [
'ppd-action-amdgpu-dpm.c',
'ppd-driver-intel-pstate.c',
'ppd-driver-amd-pstate.c',
+ 'ppd-driver-cppc.c',
'ppd-driver-platform-profile.c',
'ppd-driver-placeholder.c',
'ppd-driver-fake.c',
diff --git a/src/power-profiles-daemon.c b/src/power-profiles-daemon.c
index 01aac72..037f6f7 100644
--- a/src/power-profiles-daemon.c
+++ b/src/power-profiles-daemon.c
@@ -143,6 +143,7 @@ static void upower_battery_set_power_changed_reason (PpdApp *, PpdPowerChangedRe
#include "ppd-driver-platform-profile.h"
#include "ppd-driver-intel-pstate.h"
#include "ppd-driver-amd-pstate.h"
+#include "ppd-driver-cppc.h"
#include "ppd-driver-fake.h"
typedef GType (*GTypeGetFunc) (void);
@@ -153,6 +154,7 @@ static GTypeGetFunc objects[] = {
ppd_driver_platform_profile_get_type,
ppd_driver_intel_pstate_get_type,
ppd_driver_amd_pstate_get_type,
+ ppd_driver_cppc_get_type,
/* Generic profile driver */
ppd_driver_placeholder_get_type,
diff --git a/src/ppd-driver-cppc.c b/src/ppd-driver-cppc.c
new file mode 100644
index 0000000..c03df2a
--- /dev/null
+++ b/src/ppd-driver-cppc.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2020 Bastien Nocera <hadess@hadess.net>
+ * Copyright (c) 2026 David Heinemeier Hansson <david@hey.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published by
+ * the Free Software Foundation.
+ *
+ */
+
+/*
+ * Profile driver for the generic ACPI CPPC cpufreq driver (cppc_cpufreq),
+ * as used by ARM64 laptops. Balanced and power-saver hand frequency
+ * selection to the platform ("autonomous selection") with an energy
+ * performance preference, while performance runs the performance governor.
+ */
+
+#define G_LOG_DOMAIN "CpuDriver"
+
+#include "ppd-utils.h"
+#include "ppd-driver-cppc.h"
+
+#define CPUFREQ_POLICY_DIR "/sys/devices/system/cpu/cpufreq/"
+
+/* energy_performance_preference_val: 0 is max performance, 255 max efficiency */
+#define EPP_BALANCED "64"
+#define EPP_POWER_SAVER "192"
+
+typedef struct
+{
+ char *path;
+ /* Settings found at probe time, restored if the first activation fails */
+ char *governor;
+ char *auto_select;
+ char *epp;
+} CppcPolicy;
+
+struct _PpdDriverCppc
+{
+ PpdDriverCpu parent_instance;
+
+ PpdProfile activated_profile;
+ GPtrArray *policies; /* Array of CppcPolicy */
+};
+
+G_DEFINE_TYPE (PpdDriverCppc, ppd_driver_cppc, PPD_TYPE_DRIVER_CPU)
+
+static void
+cppc_policy_free (CppcPolicy *policy)
+{
+ g_free (policy->path);
+ g_free (policy->governor);
+ g_free (policy->auto_select);
+ g_free (policy->epp);
+ g_free (policy);
+}
+
+static GObject*
+ppd_driver_cppc_constructor (GType type,
+ guint n_construct_params,
+ GObjectConstructParam *construct_params)
+{
+ GObject *object;
+
+ object = G_OBJECT_CLASS (ppd_driver_cppc_parent_class)->constructor (type,
+ n_construct_params,
+ construct_params);
+ g_object_set (object,
+ "driver-name", "cppc_cpufreq",
+ "profiles", PPD_PROFILE_PERFORMANCE | PPD_PROFILE_BALANCED | PPD_PROFILE_POWER_SAVER,
+ NULL);
+
+ return object;
+}
+
+static char *
+read_policy_file (const char *base,
+ const char *name)
+{
+ g_autofree char *path = NULL;
+ g_autofree char *contents = NULL;
+ g_autoptr(GError) error = NULL;
+
+ path = g_build_filename (base, name, NULL);
+ if (!g_file_get_contents (path, &contents, NULL, &error)) {
+ g_debug ("Failed to read %s: %s", path, error->message);
+ return NULL;
+ }
+
+ return g_strdup (g_strstrip (contents));
+}
+
+static gboolean
+write_policy_file (const char *base,
+ const char *name,
+ const char *value,
+ GError **error)
+{
+ g_autofree char *path = NULL;
+
+ path = g_build_filename (base, name, NULL);
+ return ppd_utils_write (path, value, error);
+}
+
+static gboolean
+has_governors (const char *base)
+{
+ g_autofree char *available = NULL;
+ g_auto(GStrv) governors = NULL;
+
+ available = read_policy_file (base, "scaling_available_governors");
+ if (!available)
+ return FALSE;
+
+ governors = g_strsplit_set (available, " \t\n", -1);
+ return g_strv_contains ((const char * const *) governors, "schedutil") &&
+ g_strv_contains ((const char * const *) governors, "performance");
+}
+
+static CppcPolicy *
+probe_policy (const char *base)
+{
+ g_autofree char *driver = NULL;
+ g_autoptr(GError) error = NULL;
+ CppcPolicy *policy;
+
+ driver = read_policy_file (base, "scaling_driver");
+ if (g_strcmp0 (driver, "cppc_cpufreq") != 0)
+ return NULL;
+
+ /* Every profile switches to one of these */
+ if (!has_governors (base)) {
+ g_debug ("%s lacks the schedutil or performance governor", base);
+ return NULL;
+ }
+
+ policy = g_new0 (CppcPolicy, 1);
+ policy->path = g_strdup (base);
+ policy->governor = read_policy_file (base, "scaling_governor");
+ /* Autonomous selection is optional in CPPC, so its knobs may be missing */
+ policy->auto_select = read_policy_file (base, "auto_select");
+ policy->epp = read_policy_file (base, "energy_performance_preference_val");
+
+ if (!policy->governor || !policy->auto_select || !policy->epp) {
+ cppc_policy_free (policy);
+ return NULL;
+ }
+
+ /* Check that the knobs are writable by writing back what they hold */
+ if (!write_policy_file (base, "auto_select", policy->auto_select, &error) ||
+ !write_policy_file (base, "energy_performance_preference_val", policy->epp, &error)) {
+ g_debug ("Failed to write CPPC settings in %s: %s", base, error->message);
+ cppc_policy_free (policy);
+ return NULL;
+ }
+
+ return policy;
+}
+
+static PpdProbeResult
+ppd_driver_cppc_probe (PpdDriver *driver)
+{
+ PpdDriverCppc *cppc = PPD_DRIVER_CPPC (driver);
+ g_autoptr(GDir) dir = NULL;
+ g_autofree char *policy_dir = NULL;
+ const char *dirname;
+
+ policy_dir = ppd_utils_get_sysfs_path (CPUFREQ_POLICY_DIR);
+ dir = g_dir_open (policy_dir, 0, NULL);
+ if (!dir) {
+ g_debug ("Could not open %s", policy_dir);
+ return PPD_PROBE_RESULT_FAIL;
+ }
+
+ while ((dirname = g_dir_read_name (dir)) != NULL) {
+ g_autofree char *base = NULL;
+ CppcPolicy *policy;
+
+ base = g_build_filename (policy_dir, dirname, NULL);
+ policy = probe_policy (base);
+ if (!policy)
+ continue;
+
+ if (!cppc->policies)
+ cppc->policies = g_ptr_array_new_with_free_func ((GDestroyNotify) cppc_policy_free);
+
+ g_ptr_array_add (cppc->policies, policy);
+ }
+
+ g_debug ("%s CPPC autonomous selection settings",
+ cppc->policies && cppc->policies->len ? "Found" : "Didn't find");
+
+ if (cppc->policies && cppc->policies->len)
+ return PPD_PROBE_RESULT_SUCCESS;
+
+ return PPD_PROBE_RESULT_FAIL;
+}
+
+static gboolean
+apply_pref_to_policies (GPtrArray *policies,
+ PpdProfile profile,
+ GError **error)
+{
+ if (profile == PPD_PROFILE_UNSET)
+ return TRUE;
+
+ for (guint i = 0; i < policies->len; ++i) {
+ const char *base = ((CppcPolicy *) g_ptr_array_index (policies, i))->path;
+
+ switch (profile) {
+ case PPD_PROFILE_PERFORMANCE:
+ /* Leave autonomous selection first so the governor owns the frequency */
+ if (!write_policy_file (base, "auto_select", "0", error) ||
+ !write_policy_file (base, "scaling_governor", "performance", error))
+ return FALSE;
+ break;
+ case PPD_PROFILE_BALANCED:
+ case PPD_PROFILE_POWER_SAVER:
+ if (!write_policy_file (base, "scaling_governor", "schedutil", error) ||
+ !write_policy_file (base, "energy_performance_preference_val",
+ profile == PPD_PROFILE_BALANCED ? EPP_BALANCED : EPP_POWER_SAVER,
+ error) ||
+ !write_policy_file (base, "auto_select", "1", error))
+ return FALSE;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+restore_probed_settings (GPtrArray *policies)
+{
+ for (guint i = 0; i < policies->len; ++i) {
+ CppcPolicy *policy = g_ptr_array_index (policies, i);
+ g_autoptr(GError) error = NULL;
+
+ if (!write_policy_file (policy->path, "auto_select", "0", &error) ||
+ !write_policy_file (policy->path, "scaling_governor", policy->governor, &error) ||
+ !write_policy_file (policy->path, "energy_performance_preference_val", policy->epp, &error) ||
+ !write_policy_file (policy->path, "auto_select", policy->auto_select, &error))
+ g_warning ("failed to restore CPPC settings in %s: %s", policy->path, error->message);
+ }
+}
+
+static gboolean
+ppd_driver_cppc_activate_profile (PpdDriver *driver,
+ PpdProfile profile,
+ PpdProfileActivationReason reason,
+ GError **error)
+{
+ PpdDriverCppc *cppc = PPD_DRIVER_CPPC (driver);
+ gboolean ret = FALSE;
+
+ g_return_val_if_fail (cppc->policies != NULL, FALSE);
+ g_return_val_if_fail (cppc->policies->len != 0, FALSE);
+
+ ret = apply_pref_to_policies (cppc->policies, profile, error);
+ if (!ret) {
+ g_autoptr(GError) error_local = NULL;
+
+ /* Policies may be left half-switched, so put them all back */
+ if (cppc->activated_profile == PPD_PROFILE_UNSET)
+ restore_probed_settings (cppc->policies);
+ else if (!apply_pref_to_policies (cppc->policies,
+ cppc->activated_profile,
+ &error_local))
+ g_warning ("failed to restore previous profile: %s", error_local->message);
+ return ret;
+ }
+
+ cppc->activated_profile = profile;
+
+ return ret;
+}
+
+static gboolean
+ppd_driver_cppc_prepare_for_sleep (PpdDriver *driver,
+ gboolean start,
+ GError **error)
+{
+ PpdDriverCppc *cppc = PPD_DRIVER_CPPC (driver);
+ g_autoptr(GError) local_error = NULL;
+
+ if (start)
+ return TRUE;
+
+ /* Firmware may reset CPPC registers across suspend */
+ g_debug ("Re-applying CPPC settings");
+ if (!ppd_driver_cppc_activate_profile (driver,
+ cppc->activated_profile,
+ PPD_PROFILE_ACTIVATION_REASON_RESUME,
+ &local_error)) {
+ g_propagate_prefixed_error (error, g_steal_pointer (&local_error),
+ "Could not reapply CPPC settings on resume: ");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+ppd_driver_cppc_finalize (GObject *object)
+{
+ PpdDriverCppc *driver;
+
+ driver = PPD_DRIVER_CPPC (object);
+ g_clear_pointer (&driver->policies, g_ptr_array_unref);
+ G_OBJECT_CLASS (ppd_driver_cppc_parent_class)->finalize (object);
+}
+
+static void
+ppd_driver_cppc_class_init (PpdDriverCppcClass *klass)
+{
+ GObjectClass *object_class;
+ PpdDriverClass *driver_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->constructor = ppd_driver_cppc_constructor;
+ object_class->finalize = ppd_driver_cppc_finalize;
+
+ driver_class = PPD_DRIVER_CLASS (klass);
+ driver_class->probe = ppd_driver_cppc_probe;
+ driver_class->activate_profile = ppd_driver_cppc_activate_profile;
+ driver_class->prepare_to_sleep = ppd_driver_cppc_prepare_for_sleep;
+}
+
+static void
+ppd_driver_cppc_init (PpdDriverCppc *self)
+{
+}
diff --git a/src/ppd-driver-cppc.h b/src/ppd-driver-cppc.h
new file mode 100644
index 0000000..c79356d
--- /dev/null
+++ b/src/ppd-driver-cppc.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2020 Bastien Nocera <hadess@hadess.net>
+ * Copyright (c) 2026 David Heinemeier Hansson <david@hey.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published by
+ * the Free Software Foundation.
+ *
+ */
+
+#pragma once
+
+#include "ppd-driver-cpu.h"
+
+#define PPD_TYPE_DRIVER_CPPC (ppd_driver_cppc_get_type ())
+G_DECLARE_FINAL_TYPE (PpdDriverCppc, ppd_driver_cppc, PPD, DRIVER_CPPC, PpdDriverCpu)
diff --git a/tests/integration_test.py b/tests/integration_test.py
index 0994cf2..5648c1e 100644
--- a/tests/integration_test.py
+++ b/tests/integration_test.py
@@ -1258,6 +1258,134 @@ class Tests(dbusmock.DBusTestCase):
self.assert_file_eventually_contains(energy_prefs, "power")
self.assert_file_eventually_contains(scaling_governor, "powersave")
+ def create_cppc_policy(
+ self,
+ name,
+ driver="cppc_cpufreq",
+ governors="conservative ondemand userspace powersave performance schedutil",
+ ):
+ """Create a cpufreq policy with CPPC autonomous selection knobs"""
+ policy = os.path.join(
+ self.testbed.get_root_dir(), f"sys/devices/system/cpu/cpufreq/{name}/"
+ )
+ os.makedirs(policy)
+ self.write_file_contents(os.path.join(policy, "scaling_driver"), f"{driver}\n")
+ self.write_file_contents(
+ os.path.join(policy, "scaling_available_governors"), f"{governors}\n"
+ )
+ self.write_file_contents(os.path.join(policy, "scaling_governor"), "schedutil\n")
+ self.write_file_contents(os.path.join(policy, "auto_select"), "0\n")
+ self.write_file_contents(
+ os.path.join(policy, "energy_performance_preference_val"), "127\n"
+ )
+ return policy
+
+ def assert_cppc_policies(self, policies, governor, auto_select, epp=None):
+ """Check the CPPC settings of every policy"""
+ for policy in policies:
+ self.assert_file_eventually_contains(
+ os.path.join(policy, "scaling_governor"), governor
+ )
+ self.assert_file_eventually_contains(
+ os.path.join(policy, "auto_select"), auto_select
+ )
+ if epp is not None:
+ self.assert_file_eventually_contains(
+ os.path.join(policy, "energy_performance_preference_val"), epp
+ )
+
+ def test_cppc(self):
+ """CPPC cpufreq driver with autonomous selection (no UPower)"""
+
+ policies = [self.create_cppc_policy("policy0"), self.create_cppc_policy("policy1")]
+
+ self.start_daemon()
+
+ profiles = self.get_dbus_property("Profiles")
+ self.assertEqual(len(profiles), 3)
+ self.assertEqual(profiles[0]["Driver"], "multiple")
+ self.assertEqual(profiles[0]["CpuDriver"], "cppc_cpufreq")
+ self.assertEqual(profiles[0]["Profile"], "power-saver")
+
+ self.assert_cppc_policies(policies, "schedutil", "1", "64")
+
+ # Performance leaves autonomous selection and runs the performance governor
+ self.set_dbus_property("ActiveProfile", GLib.Variant.new_string("performance"))
+ self.assertEqual(self.get_dbus_property("ActiveProfile"), "performance")
+ self.assert_cppc_policies(policies, "performance", "0")
+
+ # Power saver goes back to autonomous selection, biased to efficiency
+ self.set_dbus_property("ActiveProfile", GLib.Variant.new_string("power-saver"))
+ self.assertEqual(self.get_dbus_property("ActiveProfile"), "power-saver")
+ self.assert_cppc_policies(policies, "schedutil", "1", "192")
+
+ def test_cppc_reapply_on_resume_from_sleep(self):
+ """CPPC settings are reapplied after resume"""
+
+ policy = self.create_cppc_policy("policy0")
+ auto_select = os.path.join(policy, "auto_select")
+
+ _, obj_logind, _ = self.start_dbus_template("logind", {})
+
+ self.start_daemon()
+ self.assert_dbus_property_eventually_is(
+ "ActiveProfile", "balanced", keep_checking=100
+ )
+ self.assert_file_eventually_contains(auto_select, "1")
+
+ # Simulate firmware resetting autonomous selection across suspend
+ obj_logind.EmitSignal(
+ "org.freedesktop.login1.Manager", "PrepareForSleep", "b", [True]
+ )
+ self.write_file_contents(auto_select, "0\n")
+ obj_logind.EmitSignal(
+ "org.freedesktop.login1.Manager", "PrepareForSleep", "b", [False]
+ )
+
+ self.assert_file_eventually_contains(
+ auto_select, "1", timeout=3000, keep_checking=100
+ )
+
+ def test_cppc_without_autonomous_selection(self):
+ """CPPC cpufreq driver without autonomous selection falls back to placeholder"""
+
+ policy = os.path.join(
+ self.testbed.get_root_dir(), "sys/devices/system/cpu/cpufreq/policy0/"
+ )
+ os.makedirs(policy)
+ self.write_file_contents(os.path.join(policy, "scaling_driver"), "cppc_cpufreq\n")
+ self.write_file_contents(
+ os.path.join(policy, "scaling_available_governors"), "performance schedutil\n"
+ )
+ self.write_file_contents(os.path.join(policy, "scaling_governor"), "schedutil\n")
+
+ self.start_daemon()
+
+ profiles = self.get_dbus_property("Profiles")
+ self.assertEqual(len(profiles), 2)
+ self.assertEqual(profiles[0]["Driver"], "placeholder")
+
+ def test_cppc_without_schedutil(self):
+ """CPPC cpufreq driver without the schedutil governor falls back to placeholder"""
+
+ self.create_cppc_policy("policy0", governors="performance powersave")
+
+ self.start_daemon()
+
+ profiles = self.get_dbus_property("Profiles")
+ self.assertEqual(len(profiles), 2)
+ self.assertEqual(profiles[0]["Driver"], "placeholder")
+
+ def test_cppc_other_cpufreq_driver(self):
+ """CPPC knobs on a non-CPPC cpufreq driver are ignored"""
+
+ self.create_cppc_policy("policy0", driver="acpi-cpufreq")
+
+ self.start_daemon()
+
+ profiles = self.get_dbus_property("Profiles")
+ self.assertEqual(len(profiles), 2)
+ self.assertEqual(profiles[0]["Driver"], "placeholder")
# pylint: disable=too-many-statements
def test_amd_pstate_min_freq(self):
"""AMD P-State driver min freq support"""
--
2.56.0