Skip to content

Commit

Permalink
platform/surface: platform_profile: add fan profile switching
Browse files Browse the repository at this point in the history
Change naming from tmp to platform profile to clarify the module may
interact with both the TMP and FAN subystems. Add functionality that
switches the fan profile when the platform profile is changed.

Signed-off-by: Ivor Wanders <ivor@iwanders.net>
  • Loading branch information
iwanders committed Dec 22, 2023
1 parent df0bd8f commit 274e706
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 47 deletions.
38 changes: 26 additions & 12 deletions drivers/platform/surface/surface_aggregator_registry.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,26 @@ static const struct software_node ssam_node_bat_sb3base = {
.parent = &ssam_node_hub_base,
};

/* Platform profile / performance-mode device. */
static const struct software_node ssam_node_tmp_pprof = {
/* Platform profile / performance-mode device without a fan. */
static const struct software_node ssam_node_perf_profile = {
.name = "ssam:01:03:01:00:01",
.parent = &ssam_node_root,
};

/* Platform profile / performance-mode device with a fan, such that
* the fan controller profile can also be switched.
*/
static const struct property_entry ssam_node_perf_profile_has_fan[] = {
PROPERTY_ENTRY_BOOL("has_fan"),
{ }
};

static const struct software_node ssam_node_perf_profile_with_fan = {
.name = "ssam:01:03:01:00:01",
.parent = &ssam_node_root,
.properties = ssam_node_perf_profile_has_fan,
};

/* Tablet-mode switch via KIP subsystem. */
static const struct software_node ssam_node_kip_tablet_switch = {
.name = "ssam:01:0e:01:00:01",
Expand Down Expand Up @@ -202,7 +216,7 @@ static const struct software_node ssam_node_pos_tablet_switch = {
*/
static const struct software_node *ssam_node_group_gen5[] = {
&ssam_node_root,
&ssam_node_tmp_pprof,
&ssam_node_perf_profile,
NULL,
};

Expand All @@ -213,7 +227,7 @@ static const struct software_node *ssam_node_group_sb3[] = {
&ssam_node_bat_ac,
&ssam_node_bat_main,
&ssam_node_bat_sb3base,
&ssam_node_tmp_pprof,
&ssam_node_perf_profile,
&ssam_node_bas_dtx,
&ssam_node_hid_base_keyboard,
&ssam_node_hid_base_touchpad,
Expand All @@ -227,7 +241,7 @@ static const struct software_node *ssam_node_group_sl3[] = {
&ssam_node_root,
&ssam_node_bat_ac,
&ssam_node_bat_main,
&ssam_node_tmp_pprof,
&ssam_node_perf_profile,
&ssam_node_hid_main_keyboard,
&ssam_node_hid_main_touchpad,
&ssam_node_hid_main_iid5,
Expand All @@ -239,7 +253,7 @@ static const struct software_node *ssam_node_group_sl5[] = {
&ssam_node_root,
&ssam_node_bat_ac,
&ssam_node_bat_main,
&ssam_node_tmp_pprof,
&ssam_node_perf_profile,
&ssam_node_hid_main_keyboard,
&ssam_node_hid_main_touchpad,
&ssam_node_hid_main_iid5,
Expand All @@ -252,7 +266,7 @@ static const struct software_node *ssam_node_group_sls1[] = {
&ssam_node_root,
&ssam_node_bat_ac,
&ssam_node_bat_main,
&ssam_node_tmp_pprof,
&ssam_node_perf_profile,
&ssam_node_pos_tablet_switch,
&ssam_node_hid_sam_keyboard,
&ssam_node_hid_sam_penstash,
Expand All @@ -268,7 +282,7 @@ static const struct software_node *ssam_node_group_sls2[] = {
&ssam_node_root,
&ssam_node_bat_ac,
&ssam_node_bat_main,
&ssam_node_tmp_pprof,
&ssam_node_perf_profile,
&ssam_node_pos_tablet_switch,
&ssam_node_hid_sam_keyboard,
&ssam_node_hid_sam_penstash,
Expand All @@ -282,7 +296,7 @@ static const struct software_node *ssam_node_group_slg1[] = {
&ssam_node_root,
&ssam_node_bat_ac,
&ssam_node_bat_main,
&ssam_node_tmp_pprof,
&ssam_node_perf_profile,
NULL,
};

Expand All @@ -291,7 +305,7 @@ static const struct software_node *ssam_node_group_sp7[] = {
&ssam_node_root,
&ssam_node_bat_ac,
&ssam_node_bat_main,
&ssam_node_tmp_pprof,
&ssam_node_perf_profile,
NULL,
};

Expand All @@ -301,7 +315,7 @@ static const struct software_node *ssam_node_group_sp8[] = {
&ssam_node_hub_kip,
&ssam_node_bat_ac,
&ssam_node_bat_main,
&ssam_node_tmp_pprof,
&ssam_node_perf_profile,
&ssam_node_kip_tablet_switch,
&ssam_node_hid_kip_keyboard,
&ssam_node_hid_kip_penstash,
Expand All @@ -318,7 +332,7 @@ static const struct software_node *ssam_node_group_sp9[] = {
&ssam_node_hub_kip,
&ssam_node_bat_ac,
&ssam_node_bat_main,
&ssam_node_tmp_pprof,
&ssam_node_perf_profile_with_fan,
&ssam_node_pos_tablet_switch,
&ssam_node_hid_kip_keyboard,
&ssam_node_hid_kip_penstash,
Expand Down
132 changes: 97 additions & 35 deletions drivers/platform/surface/surface_platform_profile.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Surface Platform Profile / Performance Mode driver for Surface System
* Aggregator Module (thermal subsystem).
* Aggregator Module (thermal and fan subsystem).
*
* Copyright (C) 2021-2022 Maximilian Luz <luzmaximilian@gmail.com>
*/
Expand All @@ -14,67 +14,93 @@

#include <linux/surface_aggregator/device.h>

enum ssam_tmp_profile {
SSAM_TMP_PROFILE_NORMAL = 1,
SSAM_TMP_PROFILE_BATTERY_SAVER = 2,
SSAM_TMP_PROFILE_BETTER_PERFORMANCE = 3,
SSAM_TMP_PROFILE_BEST_PERFORMANCE = 4,
// Enum for the platform performance profile sent to the TMP module.
enum ssam_perf_profile {
SSAM_PERF_PROFILE_NORMAL = 1,
SSAM_PERF_PROFILE_BATTERY_SAVER = 2,
SSAM_PERF_PROFILE_BETTER_PERFORMANCE = 3,
SSAM_PERF_PROFILE_BEST_PERFORMANCE = 4,
};

struct ssam_tmp_profile_info {
// Enum for the fan profile sent to the FAN module. This fan profile is
// only sent to the EC if the 'has_fan' property is set. The integers are
// not a typo, they differ from the performance profile indices.
enum ssam_fan_profile {
SSAM_FAN_PROFILE_NORMAL = 2,
SSAM_FAN_PROFILE_BATTERY_SAVER = 1,
SSAM_FAN_PROFILE_BETTER_PERFORMANCE = 3,
SSAM_FAN_PROFILE_BEST_PERFORMANCE = 4,
};

struct ssam_perf_profile_info {
__le32 profile;
__le16 unknown1;
__le16 unknown2;
} __packed;

struct ssam_tmp_profile_device {
struct ssam_platform_profile_device {
struct ssam_device *sdev;
struct platform_profile_handler handler;
bool has_fan;
};

SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_tmp_profile_get, struct ssam_tmp_profile_info, {
SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_perf_profile_get, struct ssam_perf_profile_info, {
.target_category = SSAM_SSH_TC_TMP,
.command_id = 0x02,
});

SSAM_DEFINE_SYNC_REQUEST_CL_W(__ssam_tmp_profile_set, __le32, {
SSAM_DEFINE_SYNC_REQUEST_CL_W(__ssam_perf_profile_set, __le32, {
.target_category = SSAM_SSH_TC_TMP,
.command_id = 0x03,
});

static int ssam_tmp_profile_get(struct ssam_device *sdev, enum ssam_tmp_profile *p)
SSAM_DEFINE_SYNC_REQUEST_W(__ssam_fan_profile_set, char, {
.target_category = SSAM_SSH_TC_FAN,
.target_id = SSAM_SSH_TID_SAM,
.command_id = 0x0e,
.instance_id = 0x01,
});

static int ssam_perf_profile_get(struct ssam_device *sdev, enum ssam_perf_profile *p)
{
struct ssam_tmp_profile_info info;
struct ssam_perf_profile_info info;
int status;

status = ssam_retry(__ssam_tmp_profile_get, sdev, &info);
status = ssam_retry(__ssam_perf_profile_get, sdev, &info);
if (status < 0)
return status;

*p = le32_to_cpu(info.profile);
return 0;
}

static int ssam_tmp_profile_set(struct ssam_device *sdev, enum ssam_tmp_profile p)
static int ssam_perf_profile_set(struct ssam_device *sdev, enum ssam_perf_profile p)
{
__le32 profile_le = cpu_to_le32(p);

return ssam_retry(__ssam_tmp_profile_set, sdev, &profile_le);
return ssam_retry(__ssam_perf_profile_set, sdev, &profile_le);
}

static int ssam_fan_profile_set(struct ssam_device *sdev, enum ssam_fan_profile p)
{
char profile = p;

return ssam_retry(__ssam_fan_profile_set, sdev->ctrl, &profile);
}

static int convert_ssam_to_profile(struct ssam_device *sdev, enum ssam_tmp_profile p)
static int convert_ssam_perf_to_profile(struct ssam_device *sdev, enum ssam_perf_profile p)
{
switch (p) {
case SSAM_TMP_PROFILE_NORMAL:
case SSAM_PERF_PROFILE_NORMAL:
return PLATFORM_PROFILE_BALANCED;

case SSAM_TMP_PROFILE_BATTERY_SAVER:
case SSAM_PERF_PROFILE_BATTERY_SAVER:
return PLATFORM_PROFILE_LOW_POWER;

case SSAM_TMP_PROFILE_BETTER_PERFORMANCE:
case SSAM_PERF_PROFILE_BETTER_PERFORMANCE:
return PLATFORM_PROFILE_BALANCED_PERFORMANCE;

case SSAM_TMP_PROFILE_BEST_PERFORMANCE:
case SSAM_PERF_PROFILE_BEST_PERFORMANCE:
return PLATFORM_PROFILE_PERFORMANCE;

default:
Expand All @@ -83,20 +109,43 @@ static int convert_ssam_to_profile(struct ssam_device *sdev, enum ssam_tmp_profi
}
}

static int convert_profile_to_ssam(struct ssam_device *sdev, enum platform_profile_option p)

static int convert_profile_to_ssam_perf(struct ssam_device *sdev, enum platform_profile_option p)
{
switch (p) {
case PLATFORM_PROFILE_LOW_POWER:
return SSAM_PERF_PROFILE_BATTERY_SAVER;

case PLATFORM_PROFILE_BALANCED:
return SSAM_PERF_PROFILE_NORMAL;

case PLATFORM_PROFILE_BALANCED_PERFORMANCE:
return SSAM_PERF_PROFILE_BETTER_PERFORMANCE;

case PLATFORM_PROFILE_PERFORMANCE:
return SSAM_PERF_PROFILE_BEST_PERFORMANCE;

default:
/* This should have already been caught by platform_profile_store(). */
WARN(true, "unsupported platform profile");
return -EOPNOTSUPP;
}
}

static int convert_profile_to_ssam_fan(struct ssam_device *sdev, enum platform_profile_option p)
{
switch (p) {
case PLATFORM_PROFILE_LOW_POWER:
return SSAM_TMP_PROFILE_BATTERY_SAVER;
return SSAM_FAN_PROFILE_BATTERY_SAVER;

case PLATFORM_PROFILE_BALANCED:
return SSAM_TMP_PROFILE_NORMAL;
return SSAM_FAN_PROFILE_NORMAL;

case PLATFORM_PROFILE_BALANCED_PERFORMANCE:
return SSAM_TMP_PROFILE_BETTER_PERFORMANCE;
return SSAM_FAN_PROFILE_BETTER_PERFORMANCE;

case PLATFORM_PROFILE_PERFORMANCE:
return SSAM_TMP_PROFILE_BEST_PERFORMANCE;
return SSAM_FAN_PROFILE_BEST_PERFORMANCE;

default:
/* This should have already been caught by platform_profile_store(). */
Expand All @@ -108,17 +157,17 @@ static int convert_profile_to_ssam(struct ssam_device *sdev, enum platform_profi
static int ssam_platform_profile_get(struct platform_profile_handler *pprof,
enum platform_profile_option *profile)
{
struct ssam_tmp_profile_device *tpd;
enum ssam_tmp_profile tp;
struct ssam_platform_profile_device *tpd;
enum ssam_perf_profile tp;
int status;

tpd = container_of(pprof, struct ssam_tmp_profile_device, handler);
tpd = container_of(pprof, struct ssam_platform_profile_device, handler);

status = ssam_tmp_profile_get(tpd->sdev, &tp);
status = ssam_perf_profile_get(tpd->sdev, &tp);
if (status)
return status;

status = convert_ssam_to_profile(tpd->sdev, tp);
status = convert_ssam_perf_to_profile(tpd->sdev, tp);
if (status < 0)
return status;

Expand All @@ -129,21 +178,32 @@ static int ssam_platform_profile_get(struct platform_profile_handler *pprof,
static int ssam_platform_profile_set(struct platform_profile_handler *pprof,
enum platform_profile_option profile)
{
struct ssam_tmp_profile_device *tpd;
struct ssam_platform_profile_device *tpd;
int tp;

tpd = container_of(pprof, struct ssam_tmp_profile_device, handler);
tpd = container_of(pprof, struct ssam_platform_profile_device, handler);

tp = convert_profile_to_ssam_perf(tpd->sdev, profile);
if (tp < 0)
return tp;

tp = convert_profile_to_ssam(tpd->sdev, profile);
tp = ssam_perf_profile_set(tpd->sdev, tp);
if (tp < 0)
return tp;

return ssam_tmp_profile_set(tpd->sdev, tp);
if (tpd->has_fan) {
tp = convert_profile_to_ssam_fan(tpd->sdev, profile);
if (tp < 0)
return tp;
tp = ssam_fan_profile_set(tpd->sdev, tp);
}

return tp;
}

static int surface_platform_profile_probe(struct ssam_device *sdev)
{
struct ssam_tmp_profile_device *tpd;
struct ssam_platform_profile_device *tpd;

tpd = devm_kzalloc(&sdev->dev, sizeof(*tpd), GFP_KERNEL);
if (!tpd)
Expand All @@ -154,6 +214,8 @@ static int surface_platform_profile_probe(struct ssam_device *sdev)
tpd->handler.profile_get = ssam_platform_profile_get;
tpd->handler.profile_set = ssam_platform_profile_set;

tpd->has_fan = device_property_read_bool(&sdev->dev, "has_fan");

set_bit(PLATFORM_PROFILE_LOW_POWER, tpd->handler.choices);
set_bit(PLATFORM_PROFILE_BALANCED, tpd->handler.choices);
set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, tpd->handler.choices);
Expand Down

0 comments on commit 274e706

Please sign in to comment.