mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: "Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>
To: Alex Yeo <alexyeo362@gmail.com>
Cc: platform-driver-x86@vger.kernel.org,
	Hans de Goede <hansg@kernel.org>,
	 Kenneth Chan <kenneth.t.chan@gmail.com>,
	 LKML <linux-kernel@vger.kernel.org>
Subject: Re: [RFC PATCH v3] platform/x86: panasonic-laptop: Add platform_profile support
Date: Fri, 16 Oct 2026 14:12:18 +0300 (EEST)	[thread overview]
Message-ID: <31bc2c6d-5d06-e278-a701-0bd4138598f9@linux.intel.com> (raw)
In-Reply-To: <20261007190446.38862-1-alexyeo362@gmail.com>

On Thu, 8 Oct 2026, Alex Yeo wrote:

> Expose firmware thermal and power management policies via the
> platform_profile interface.
> 
> Supported and tested models:
>  - CF-RZ6 (2016)
>  - CF-SV8 (2019)
>  - CF-QV9 (2020)
>  - CF-SR4 (2024)
> 
> Firmware fan operating mode and the TDP limit switch are mapped onto
> the Linux platform_profile ABI.
> 
> This implementation queries the firmware for every get().
> CUSTOM is returned when the current state is not recognized.
> The set() callback writes the values regardless of what the
> current fan mode and TDP limit is.
> 
>  - Introduce as separate platform_driver
>  - Used DEFINE for driver and platform_profile device name
>  - DMI quirks restrict support to tested models
>  - When raising TDP, fan mode is switched first
>  - When limiting TDP, TDP limit is applied first
>  - ACPI handle for the EC device was used as the EC path varies
>    slightly between models.
>  - This device is optional: keep hotkey and everything already
>    loaded if profile driver fails for any reason.
> 
> Signed-off-by: Alex Yeo <alexyeo362@gmail.com>
> ---
> v3:
>  - Removed sysfs.h import
>  - Refactored platform profile probe function to use a different pattern
>    (check warn_on, continue on double unset, then set)
> 
> v2: https://lore.kernel.org/platform-driver-x86/20261006085021.853827-1-alexyeo362@gmail.com/
>  - Refactored code to use its own platform_driver
>  - Removed DEFINE_FREE and its corresponding __free as its addition
>    in this module is inappropriate
>  - Removed pr_fmt line as its addition to this patch is inappropriate
>  - Added DMI check during __init to prevent attempt of platform profile
>    device loading on unsupported hardware
>  - Fixed use of enums as truth values by adding explicit comparisons
>  - Added *profile_pdev to keep track of new platform_driver
>  - Removed extra spaces in the quirk definitions
>  - Added helper function for calling EC methods for simplicity
>  - Use ARRAY_SIZE() for for loops and added include for array_size.h
>  - Refactored pcc_profile to be a pointer in platform profile set
>    function
>  - Use WARN_ON() when a malformed quirk is detected in the platform
>    profile probe function
>  - Avoid use of status as variable name if not acpi_status
>  - Added Kconfig line for ACPI_PLATFORM_PROFILE
>  - Removed bool .use_platform_profiles from the quirks struct as it is
>    no longer needed as a result of the platform_driver being separate.
>  - Moved DMI quirk matching in probe function before devm_kzalloc of
>    driver struct
> 
> v1: https://lore.kernel.org/platform-driver-x86/20260805180544.1134916-1-alexyeo362@gmail.com/
> 
> This RFC patch adds support for mapping firmware thermal and CPU power
> operating policy to platform_profile for Panasonic Let's Note laptops.
> This originally started as a hwmon and thermal patch, but further
> analysis had revealed that these are firmware power and thermal
> policies as opposed to fan control.
> 
> Panasonic firmware exposes firmware operating policy through two
> methods:
>  - Fan cooling policy (active/passive)
>  - Processor TDP limit (capped/uncapped)
> 
> At boot, firmware defaults to an active cooling policy with the
> CPU TDP capped. Vendor drivers / DPTF normally unlocks this on
> Windows.
> 
> These 2 methods map to 4 possible distinct states. Only states that
> correspond to the platform_profile ABI are mapped and exposed as
> choices. Unmapped states will be returned as "custom" by the driver.
> 
> I have tested the following models:
>  - CF-RZ6 (2016)
>  - CF-SV8 (2019)
>  - CF-QV9 (2020)
>  - CF-SR4 (2024)
> 
> State to platform_profile mapping:
> 
>  Profile                         | Fan Mode  | TDP
> +--------------------------------+-----------+------------+
>  PLATFORM_PROFILE_COOL (SR4 only)| Active    | Locked
>  PLATFORM_PROFILE_BALANCED       | Active    | Locked
>  PLATFORM_PROFILE_QUIET          | Passive   | Locked
>  PLATFORM_PROFILE_PERFORMANCE    | Active    | Unlocked
>  CUSTOM (unmapped on all)        | Passive   | Unlocked
> 
> Across all of them, the fan and TDP modes are toggled by the same ACPI
> methods. However, there is a slight variation in its interpretation based
> on testing results.
> 
> These methods are normally called by the DPTF/IPF _OSC handshake.
> Depending on the capability bits, the firmware will alter its thermal
> and power policy.
> 
> \_SB.IETM Implementation A:
>  - CF-RZ6 (2016)
>  - CF-SV8 (2019)
> 
> \_SB.IETM Implementation B:
>  - CF-QV9 (2020)
>  - CF-SR4 (2024)
> 
> Models belonging to the same group share what appears to be identical
> AML code for the _OSC.
> 
> This patch only exposes the ability to read and set these firmware
> toggles. The get() callback queries current firmware state and returns
> the mapped platform_profile. The set() callback sets the target state
> regardless of current state.
> 
> Proposed mappings in this patch are defined in the quirks struct.
> Activation of platform_profile is gated by DMI checks.
> 
> For every model except the SR4, only balanced and performance profiles
> are defined. This is because the aggressive fan paired with the locked
> TDP on the SR4 more appropriately correspond to the cool profile.
> 
> Test results for the proposed mappings are below.
> 
> Test results:
> ================
> (CPU PkgWatt: peak / sustained)
> (Sysbench CPU: all available threads)
> 
> CF-RZ6: (i5-7Y57, Startup default: Balanced)
> 
>  Platform Profile |  CPU PkgWatt    |  Sysbench CPU  | Stress Temp (CPU)
> +-----------------+-----------------+----------------+-------------------+
>  BALANCED         |  10.0W / 9.0W   |    19712       |   57C
>  PERFORMANCE      |  18.9W / 14.9W  |    29132       |   72C
> 
> CF-SV8: (i5-8365U, Startup default: Balanced)
> 
>  Platform Profile |  CPU PkgWatt     |  Sysbench CPU  | Stress Temp (CPU)
> +-----------------+------------------+----------------+-------------------+
>  BALANCED         |  9.9W  / 9.9W    |    44695       |   58C
>  PERFORMANCE      |  29.0W / 19.9W   |    71747       |   81C
> 
> CF-QV9: (i5-10310U, Startup default: Balanced)
> 
>  Platform Profile |  CPU PkgWatt     |  Sysbench CPU  | Stress Temp (CPU)
> +-----------------+------------------+----------------+-------------------+
>  BALANCED         |  10.0W / 9.9W    |    46545       |   59C
>  PERFORMANCE      |  18.9W / 14.9W   |    57416       |   70C
> 
> CF-SR4: (i5-1345U, Startup default: Cool)
> 
>  Platform Profile |  CPU PkgWatt     |  Sysbench CPU  | Stress Temp (CPU)
> +-----------------+------------------+----------------+-------------------+
>  COOL             |  12.0W / 12.0W   |    177139      |   66C
>  QUIET            |  12.0W / 12.0W   |    176315      |   73C-75C
>  PERFORMANCE      |  29.6W / 21.3W   |    247602      |   98C-100C
> 
> CF-SR4 Notes:
>  - QUIET: downclock/throttle at 75C, no increase in package_throttle_count
>  - PERFORMANCE: stable boost clock, package_throttle_count increase
> 
> 
> Other notes:
> ===============
> 
> Additional notes about thermald:
> During testing, I have observed that running thermald for the first time
> since boot will trigger an _OSC negotiation that will unlock CPU TDP for
> new models (IETM Implementation B). Once thermald is running, exits or
> runs again, these bits were not observed to change again during testing.
> 
> Running thermald on older models (IETM Implementation A) does not touch
> the fan curve or TDP mode setting.
> 
> Suspend: observed to not alter the values set prior to suspend
> 
>  drivers/platform/x86/Kconfig            |   1 +
>  drivers/platform/x86/panasonic-laptop.c | 399 +++++++++++++++++++++++-
>  2 files changed, 399 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
> index 957034f39e4e..571c09152310 100644
> --- a/drivers/platform/x86/Kconfig
> +++ b/drivers/platform/x86/Kconfig
> @@ -820,6 +820,7 @@ config PANASONIC_LAPTOP
>  	depends on ACPI_VIDEO=n || ACPI_VIDEO
>  	depends on SERIO_I8042 || SERIO_I8042 = n
>  	select INPUT_SPARSEKMAP
> +	select ACPI_PLATFORM_PROFILE
>  	help
>  	  This driver adds support for access to backlight control and hotkeys
>  	  on Panasonic Let's Note laptops.
> diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
> index 19d194ff37ca..c4b13a3554e3 100644
> --- a/drivers/platform/x86/panasonic-laptop.c
> +++ b/drivers/platform/x86/panasonic-laptop.c
> @@ -120,9 +120,13 @@
>   */
>  
>  #include <linux/acpi.h>
> +#include <linux/array_size.h>
>  #include <linux/backlight.h>
>  #include <linux/bits.h>
>  #include <linux/ctype.h>
> +#include <linux/dmi.h>
> +#include <linux/err.h>
> +#include <linux/errno.h>
>  #include <linux/i8042.h>
>  #include <linux/init.h>
>  #include <linux/input.h>
> @@ -130,6 +134,8 @@
>  #include <linux/kernel.h>
>  #include <linux/module.h>
>  #include <linux/platform_device.h>
> +#include <linux/platform_profile.h>
> +#include <linux/printk.h>
>  #include <linux/seq_file.h>
>  #include <linux/serio.h>
>  #include <linux/slab.h>
> @@ -158,10 +164,37 @@ MODULE_LICENSE("GPL");
>  #define ECO_MODE_OFF		0x00
>  #define ECO_MODE_ON		0x80
>  
> +#define PCC_ACPI_FAN_ACTIVE_MODE	0x00
> +#define PCC_ACPI_FAN_PASSIVE_MODE	0x01
> +#define PCC_ACPI_TDP_LIMIT_ON		0x01
> +#define PCC_ACPI_TDP_LIMIT_OFF		0x00
> +
>  #define ACPI_PCC_DRIVER_NAME	"Panasonic Laptop Support"
> +#define PROFILE_PCC_DRIVER_NAME	"panasonic-platform-profile"
>  
>  #define ACPI_PCC_INPUT_PHYS	"panasonic/hkey0"
>  
> +enum pcc_profile_fan_mode {
> +	PCC_FAN_MODE_UNSET = 0,
> +	PCC_FAN_MODE_ACTIVE,
> +	PCC_FAN_MODE_PASSIVE,
> +};
> +
> +enum pcc_profile_tdp_mode {
> +	PCC_TDP_MODE_UNSET = 0,
> +	PCC_TDP_MODE_LOCKED,
> +	PCC_TDP_MODE_UNLOCKED,
> +};
> +
> +struct pcc_platform_profile {
> +	enum pcc_profile_fan_mode fan_mode;
> +	enum pcc_profile_tdp_mode tdp_mode;
> +};
> +
> +struct pcc_profile_quirk {
> +	struct pcc_platform_profile platform_profiles[PLATFORM_PROFILE_LAST];
> +};
> +
>  /* LCD_TYPEs: 0 = Normal, 1 = Semi-transparent
>     ECO_MODEs: 0x03 = off, 0x83 = on
>  */
> @@ -251,6 +284,104 @@ struct pcc_acpi {
>  	u32			sinf[] __counted_by(num_sifr);
>  };
>  
> +struct pcc_profile {
> +	acpi_handle			ec_handle;
> +	const struct pcc_profile_quirk	*quirks;
> +	struct device			*platform_profile_dev;
> +};
> +
> +static struct pcc_profile_quirk quirk_cf_sr4 = {
> +	.platform_profiles = {
> +		[PLATFORM_PROFILE_QUIET] = {
> +			.fan_mode = PCC_FAN_MODE_PASSIVE,
> +			.tdp_mode = PCC_TDP_MODE_LOCKED,
> +		},
> +		[PLATFORM_PROFILE_COOL] = {
> +			.fan_mode = PCC_FAN_MODE_ACTIVE,
> +			.tdp_mode = PCC_TDP_MODE_LOCKED,
> +		},
> +		[PLATFORM_PROFILE_PERFORMANCE] = {
> +			.fan_mode = PCC_FAN_MODE_ACTIVE,
> +			.tdp_mode = PCC_TDP_MODE_UNLOCKED,
> +		},
> +	},
> +};
> +
> +static struct pcc_profile_quirk quirk_cf_qv9 = {
> +	.platform_profiles = {
> +		[PLATFORM_PROFILE_BALANCED] = {
> +			.fan_mode = PCC_FAN_MODE_ACTIVE,
> +			.tdp_mode = PCC_TDP_MODE_LOCKED,
> +		},
> +		[PLATFORM_PROFILE_PERFORMANCE] = {
> +			.fan_mode = PCC_FAN_MODE_ACTIVE,
> +			.tdp_mode = PCC_TDP_MODE_UNLOCKED,
> +		},
> +	},
> +};
> +
> +static struct pcc_profile_quirk quirk_cf_sv8 = {
> +	.platform_profiles = {
> +		[PLATFORM_PROFILE_BALANCED] = {
> +			.fan_mode = PCC_FAN_MODE_ACTIVE,
> +			.tdp_mode = PCC_TDP_MODE_LOCKED,
> +		},
> +		[PLATFORM_PROFILE_PERFORMANCE] = {
> +			.fan_mode = PCC_FAN_MODE_ACTIVE,
> +			.tdp_mode = PCC_TDP_MODE_UNLOCKED,
> +		},
> +	},
> +};
> +
> +static struct pcc_profile_quirk quirk_cf_rz6 = {
> +	.platform_profiles = {
> +		[PLATFORM_PROFILE_BALANCED] = {
> +			.fan_mode = PCC_FAN_MODE_ACTIVE,
> +			.tdp_mode = PCC_TDP_MODE_LOCKED,
> +		},
> +		[PLATFORM_PROFILE_PERFORMANCE] = {
> +			.fan_mode = PCC_FAN_MODE_ACTIVE,
> +			.tdp_mode = PCC_TDP_MODE_UNLOCKED,
> +		},
> +	},
> +};

Multiple of these look exact duplicates. In such cases, we try to reuse 
the same struct even if we cannot then exactly match the name with the 
model.

> +static const struct dmi_system_id pcc_profile_quirks[] = {
> +	{
> +		.ident = "Panasonic Connect Co., Ltd. CFSR4-1",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Panasonic Connect Co., Ltd."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "CFSR4-1"),
> +		},
> +		.driver_data = &quirk_cf_sr4,
> +	},
> +	{
> +		.ident = "Panasonic Corporation CFQV9-1",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Panasonic Corporation"),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "CFQV9-1"),
> +		},
> +		.driver_data = &quirk_cf_qv9,
> +	},
> +	{
> +		.ident = "Panasonic Corporation CFSV8-2",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Panasonic Corporation"),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "CFSV8-2"),
> +		},
> +		.driver_data = &quirk_cf_sv8,
> +	},
> +	{
> +		.ident = "Panasonic Corporation CFRZ6-2",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Panasonic Corporation"),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "CFRZ6-2"),
> +		},
> +		.driver_data = &quirk_cf_rz6,
> +	},
> +	{},
> +};

-- 
 i.

      reply	other threads:[~2026-10-16 11:12 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-07 19:04 Alex Yeo
2026-10-16 11:12 ` Ilpo Järvinen [this message]

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=31bc2c6d-5d06-e278-a701-0bd4138598f9@linux.intel.com \
    --to=ilpo.jarvinen@linux.intel.com \
    --cc=alexyeo362@gmail.com \
    --cc=hansg@kernel.org \
    --cc=kenneth.t.chan@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=platform-driver-x86@vger.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®