Skip to content

Commit e1c2160

Browse files
mrhpearsonjwrdegoede
authored andcommitted
platform/x86: thinkpad_acpi: Add PSC mode support
The Lenovo AMD platforms use PSC mode for providing platform profile support. Detect if PSC mode is available and add support for setting the different profile modes appropriately. Note - if both MMC mode and PSC mode are available then MMC mode will be used in preference. Tested on T14 G1 AMD and T14s G2 AMD. Signed-off-by: Mark Pearson <markpearson@lenovo.com> Link: https://lore.kernel.org/r/20220225182505.7234-1-markpearson@lenovo.com Reviewed-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
1 parent a3d38af commit e1c2160

1 file changed

Lines changed: 119 additions & 53 deletions

File tree

drivers/platform/x86/thinkpad_acpi.c

Lines changed: 119 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -10130,6 +10130,7 @@ static struct ibm_struct proxsensor_driver_data = {
1013010130

1013110131
#define DYTC_CMD_FUNC_CAP 3 /* To get DYTC capabilities */
1013210132
#define DYTC_FC_MMC 27 /* MMC Mode supported */
10133+
#define DYTC_FC_PSC 29 /* PSC Mode supported */
1013310134

1013410135
#define DYTC_GET_FUNCTION_BIT 8 /* Bits 8-11 - function setting */
1013510136
#define DYTC_GET_MODE_BIT 12 /* Bits 12-15 - mode setting */
@@ -10140,12 +10141,17 @@ static struct ibm_struct proxsensor_driver_data = {
1014010141

1014110142
#define DYTC_FUNCTION_STD 0 /* Function = 0, standard mode */
1014210143
#define DYTC_FUNCTION_CQL 1 /* Function = 1, lap mode */
10143-
#define DYTC_FUNCTION_MMC 11 /* Function = 11, desk mode */
10144+
#define DYTC_FUNCTION_MMC 11 /* Function = 11, MMC mode */
10145+
#define DYTC_FUNCTION_PSC 13 /* Function = 13, PSC mode */
1014410146

10145-
#define DYTC_MODE_PERFORM 2 /* High power mode aka performance */
10146-
#define DYTC_MODE_LOWPOWER 3 /* Low power mode */
10147-
#define DYTC_MODE_BALANCE 0xF /* Default mode aka balanced */
10148-
#define DYTC_MODE_MMC_BALANCE 0 /* Default mode from MMC_GET, aka balanced */
10147+
#define DYTC_MODE_MMC_PERFORM 2 /* High power mode aka performance */
10148+
#define DYTC_MODE_MMC_LOWPOWER 3 /* Low power mode */
10149+
#define DYTC_MODE_MMC_BALANCE 0xF /* Default mode aka balanced */
10150+
#define DYTC_MODE_MMC_DEFAULT 0 /* Default mode from MMC_GET, aka balanced */
10151+
10152+
#define DYTC_MODE_PSC_LOWPOWER 3 /* Low power mode */
10153+
#define DYTC_MODE_PSC_BALANCE 5 /* Default mode aka balanced */
10154+
#define DYTC_MODE_PSC_PERFORM 7 /* High power mode aka performance */
1014910155

1015010156
#define DYTC_ERR_MASK 0xF /* Bits 0-3 in cmd result are the error result */
1015110157
#define DYTC_ERR_SUCCESS 1 /* CMD completed successful */
@@ -10155,30 +10161,54 @@ static struct ibm_struct proxsensor_driver_data = {
1015510161
(mode) << DYTC_SET_MODE_BIT | \
1015610162
(on) << DYTC_SET_VALID_BIT)
1015710163

10158-
#define DYTC_DISABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 0)
10164+
#define DYTC_DISABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_MMC_BALANCE, 0)
10165+
#define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_MMC_BALANCE, 1)
1015910166

10160-
#define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 1)
10167+
enum dytc_profile_funcmode {
10168+
DYTC_FUNCMODE_NONE = 0,
10169+
DYTC_FUNCMODE_MMC,
10170+
DYTC_FUNCMODE_PSC,
10171+
};
1016110172

10173+
static enum dytc_profile_funcmode dytc_profile_available;
1016210174
static enum platform_profile_option dytc_current_profile;
1016310175
static atomic_t dytc_ignore_event = ATOMIC_INIT(0);
1016410176
static DEFINE_MUTEX(dytc_mutex);
1016510177
static bool dytc_mmc_get_available;
1016610178

1016710179
static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *profile)
1016810180
{
10169-
switch (dytcmode) {
10170-
case DYTC_MODE_LOWPOWER:
10171-
*profile = PLATFORM_PROFILE_LOW_POWER;
10172-
break;
10173-
case DYTC_MODE_BALANCE:
10174-
case DYTC_MODE_MMC_BALANCE:
10175-
*profile = PLATFORM_PROFILE_BALANCED;
10176-
break;
10177-
case DYTC_MODE_PERFORM:
10178-
*profile = PLATFORM_PROFILE_PERFORMANCE;
10179-
break;
10180-
default: /* Unknown mode */
10181-
return -EINVAL;
10181+
if (dytc_profile_available == DYTC_FUNCMODE_MMC) {
10182+
switch (dytcmode) {
10183+
case DYTC_MODE_MMC_LOWPOWER:
10184+
*profile = PLATFORM_PROFILE_LOW_POWER;
10185+
break;
10186+
case DYTC_MODE_MMC_DEFAULT:
10187+
case DYTC_MODE_MMC_BALANCE:
10188+
*profile = PLATFORM_PROFILE_BALANCED;
10189+
break;
10190+
case DYTC_MODE_MMC_PERFORM:
10191+
*profile = PLATFORM_PROFILE_PERFORMANCE;
10192+
break;
10193+
default: /* Unknown mode */
10194+
return -EINVAL;
10195+
}
10196+
return 0;
10197+
}
10198+
if (dytc_profile_available == DYTC_FUNCMODE_PSC) {
10199+
switch (dytcmode) {
10200+
case DYTC_MODE_PSC_LOWPOWER:
10201+
*profile = PLATFORM_PROFILE_LOW_POWER;
10202+
break;
10203+
case DYTC_MODE_PSC_BALANCE:
10204+
*profile = PLATFORM_PROFILE_BALANCED;
10205+
break;
10206+
case DYTC_MODE_PSC_PERFORM:
10207+
*profile = PLATFORM_PROFILE_PERFORMANCE;
10208+
break;
10209+
default: /* Unknown mode */
10210+
return -EINVAL;
10211+
}
1018210212
}
1018310213
return 0;
1018410214
}
@@ -10187,13 +10217,22 @@ static int convert_profile_to_dytc(enum platform_profile_option profile, int *pe
1018710217
{
1018810218
switch (profile) {
1018910219
case PLATFORM_PROFILE_LOW_POWER:
10190-
*perfmode = DYTC_MODE_LOWPOWER;
10220+
if (dytc_profile_available == DYTC_FUNCMODE_MMC)
10221+
*perfmode = DYTC_MODE_MMC_LOWPOWER;
10222+
else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
10223+
*perfmode = DYTC_MODE_PSC_LOWPOWER;
1019110224
break;
1019210225
case PLATFORM_PROFILE_BALANCED:
10193-
*perfmode = DYTC_MODE_BALANCE;
10226+
if (dytc_profile_available == DYTC_FUNCMODE_MMC)
10227+
*perfmode = DYTC_MODE_MMC_BALANCE;
10228+
else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
10229+
*perfmode = DYTC_MODE_PSC_BALANCE;
1019410230
break;
1019510231
case PLATFORM_PROFILE_PERFORMANCE:
10196-
*perfmode = DYTC_MODE_PERFORM;
10232+
if (dytc_profile_available == DYTC_FUNCMODE_MMC)
10233+
*perfmode = DYTC_MODE_MMC_PERFORM;
10234+
else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
10235+
*perfmode = DYTC_MODE_PSC_PERFORM;
1019710236
break;
1019810237
default: /* Unknown profile */
1019910238
return -EOPNOTSUPP;
@@ -10266,25 +10305,39 @@ static int dytc_profile_set(struct platform_profile_handler *pprof,
1026610305
if (err)
1026710306
return err;
1026810307

10269-
if (profile == PLATFORM_PROFILE_BALANCED) {
10270-
/*
10271-
* To get back to balanced mode we need to issue a reset command.
10272-
* Note we still need to disable CQL mode before hand and re-enable
10273-
* it afterwards, otherwise dytc_lapmode gets reset to 0 and stays
10274-
* stuck at 0 for aprox. 30 minutes.
10275-
*/
10276-
err = dytc_cql_command(DYTC_CMD_RESET, &output);
10277-
if (err)
10278-
goto unlock;
10279-
} else {
10308+
if (dytc_profile_available == DYTC_FUNCMODE_MMC) {
10309+
if (profile == PLATFORM_PROFILE_BALANCED) {
10310+
/*
10311+
* To get back to balanced mode we need to issue a reset command.
10312+
* Note we still need to disable CQL mode before hand and re-enable
10313+
* it afterwards, otherwise dytc_lapmode gets reset to 0 and stays
10314+
* stuck at 0 for aprox. 30 minutes.
10315+
*/
10316+
err = dytc_cql_command(DYTC_CMD_RESET, &output);
10317+
if (err)
10318+
goto unlock;
10319+
} else {
10320+
int perfmode;
10321+
10322+
err = convert_profile_to_dytc(profile, &perfmode);
10323+
if (err)
10324+
goto unlock;
10325+
10326+
/* Determine if we are in CQL mode. This alters the commands we do */
10327+
err = dytc_cql_command(DYTC_SET_COMMAND(DYTC_FUNCTION_MMC, perfmode, 1),
10328+
&output);
10329+
if (err)
10330+
goto unlock;
10331+
}
10332+
}
10333+
if (dytc_profile_available == DYTC_FUNCMODE_PSC) {
1028010334
int perfmode;
1028110335

1028210336
err = convert_profile_to_dytc(profile, &perfmode);
1028310337
if (err)
1028410338
goto unlock;
1028510339

10286-
/* Determine if we are in CQL mode. This alters the commands we do */
10287-
err = dytc_cql_command(DYTC_SET_COMMAND(DYTC_FUNCTION_MMC, perfmode, 1), &output);
10340+
err = dytc_command(DYTC_SET_COMMAND(DYTC_FUNCTION_PSC, perfmode, 1), &output);
1028810341
if (err)
1028910342
goto unlock;
1029010343
}
@@ -10302,10 +10355,14 @@ static void dytc_profile_refresh(void)
1030210355
int perfmode;
1030310356

1030410357
mutex_lock(&dytc_mutex);
10305-
if (dytc_mmc_get_available)
10306-
err = dytc_command(DYTC_CMD_MMC_GET, &output);
10307-
else
10308-
err = dytc_cql_command(DYTC_CMD_GET, &output);
10358+
if (dytc_profile_available == DYTC_FUNCMODE_MMC) {
10359+
if (dytc_mmc_get_available)
10360+
err = dytc_command(DYTC_CMD_MMC_GET, &output);
10361+
else
10362+
err = dytc_cql_command(DYTC_CMD_GET, &output);
10363+
} else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
10364+
err = dytc_command(DYTC_CMD_GET, &output);
10365+
1030910366
mutex_unlock(&dytc_mutex);
1031010367
if (err)
1031110368
return;
@@ -10332,6 +10389,7 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
1033210389
set_bit(PLATFORM_PROFILE_BALANCED, dytc_profile.choices);
1033310390
set_bit(PLATFORM_PROFILE_PERFORMANCE, dytc_profile.choices);
1033410391

10392+
dytc_profile_available = DYTC_FUNCMODE_NONE;
1033510393
err = dytc_command(DYTC_CMD_QUERY, &output);
1033610394
if (err)
1033710395
return err;
@@ -10343,27 +10401,34 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
1034310401
if (dytc_version < 5)
1034410402
return -ENODEV;
1034510403

10346-
/* Check what capabilities are supported. Currently MMC is needed */
10404+
/* Check what capabilities are supported */
1034710405
err = dytc_command(DYTC_CMD_FUNC_CAP, &output);
1034810406
if (err)
1034910407
return err;
10350-
if (!(output & BIT(DYTC_FC_MMC))) {
10351-
dbg_printk(TPACPI_DBG_INIT, " DYTC MMC mode not supported\n");
10408+
10409+
if (test_bit(DYTC_FC_MMC, (void *)&output)) { /* MMC MODE */
10410+
dytc_profile_available = DYTC_FUNCMODE_MMC;
10411+
10412+
/*
10413+
* Check if MMC_GET functionality available
10414+
* Version > 6 and return success from MMC_GET command
10415+
*/
10416+
dytc_mmc_get_available = false;
10417+
if (dytc_version >= 6) {
10418+
err = dytc_command(DYTC_CMD_MMC_GET, &output);
10419+
if (!err && ((output & DYTC_ERR_MASK) == DYTC_ERR_SUCCESS))
10420+
dytc_mmc_get_available = true;
10421+
}
10422+
} else if (test_bit(DYTC_FC_PSC, (void *)&output)) { /*PSC MODE */
10423+
dytc_profile_available = DYTC_FUNCMODE_PSC;
10424+
} else {
10425+
dbg_printk(TPACPI_DBG_INIT, "No DYTC support available\n");
1035210426
return -ENODEV;
1035310427
}
1035410428

1035510429
dbg_printk(TPACPI_DBG_INIT,
1035610430
"DYTC version %d: thermal mode available\n", dytc_version);
10357-
/*
10358-
* Check if MMC_GET functionality available
10359-
* Version > 6 and return success from MMC_GET command
10360-
*/
10361-
dytc_mmc_get_available = false;
10362-
if (dytc_version >= 6) {
10363-
err = dytc_command(DYTC_CMD_MMC_GET, &output);
10364-
if (!err && ((output & DYTC_ERR_MASK) == DYTC_ERR_SUCCESS))
10365-
dytc_mmc_get_available = true;
10366-
}
10431+
1036710432
/* Create platform_profile structure and register */
1036810433
err = platform_profile_register(&dytc_profile);
1036910434
/*
@@ -10381,6 +10446,7 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
1038110446

1038210447
static void dytc_profile_exit(void)
1038310448
{
10449+
dytc_profile_available = DYTC_FUNCMODE_NONE;
1038410450
platform_profile_remove();
1038510451
}
1038610452

0 commit comments

Comments
 (0)