diff mbox series

platform/x86: thinkpad_acpi: Add PSC mode support

Message ID 20220225182505.7234-1-markpearson@lenovo.com (mailing list archive)
State Accepted, archived
Headers show
Series platform/x86: thinkpad_acpi: Add PSC mode support | expand

Commit Message

Mark Pearson Feb. 25, 2022, 6:25 p.m. UTC
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>
---
 drivers/platform/x86/thinkpad_acpi.c | 172 ++++++++++++++++++---------
 1 file changed, 119 insertions(+), 53 deletions(-)

Comments

Hans de Goede March 2, 2022, 2:47 p.m. UTC | #1
Hi,

On 2/25/22 19:25, Mark Pearson wrote:
> 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>

Thank you for your patch, I've applied this patch to my review-hans 
branch:
https://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git/log/?h=review-hans

Note it will show up in my review-hans branch once I've pushed my
local branch there, which might take a while.

Once I've run some tests on this branch the patches there will be
added to the platform-drivers-x86/for-next branch and eventually
will be included in the pdx86 pull-request to Linus for the next
merge-window.

Regards,

Hans



p.s.

One small thing which I noticed which could be improved is to
move the 2 convert_profile_to_dytc() calls in dytc_profile_set()
to a single call at the top of the function (before taking the
lock even) to avoid code duplication between the DYTC_FUNCMODE_MMC
vs DYTC_FUNCMODE_PSC paths.

I didn't want to block merging the patch on this, if you can
do a follow up patch with that as cleanup that would be great.






> ---
>  drivers/platform/x86/thinkpad_acpi.c | 172 ++++++++++++++++++---------
>  1 file changed, 119 insertions(+), 53 deletions(-)
> 
> diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
> index d0599e8a7b4d..d9117f824ce9 100644
> --- a/drivers/platform/x86/thinkpad_acpi.c
> +++ b/drivers/platform/x86/thinkpad_acpi.c
> @@ -10130,6 +10130,7 @@ static struct ibm_struct proxsensor_driver_data = {
>  
>  #define DYTC_CMD_FUNC_CAP     3 /* To get DYTC capabilities */
>  #define DYTC_FC_MMC           27 /* MMC Mode supported */
> +#define DYTC_FC_PSC           29 /* PSC Mode supported */
>  
>  #define DYTC_GET_FUNCTION_BIT 8  /* Bits  8-11 - function setting */
>  #define DYTC_GET_MODE_BIT     12 /* Bits 12-15 - mode setting */
> @@ -10140,12 +10141,17 @@ static struct ibm_struct proxsensor_driver_data = {
>  
>  #define DYTC_FUNCTION_STD     0  /* Function = 0, standard mode */
>  #define DYTC_FUNCTION_CQL     1  /* Function = 1, lap mode */
> -#define DYTC_FUNCTION_MMC     11 /* Function = 11, desk mode */
> +#define DYTC_FUNCTION_MMC     11 /* Function = 11, MMC mode */
> +#define DYTC_FUNCTION_PSC     13 /* Function = 13, PSC mode */
>  
> -#define DYTC_MODE_PERFORM     2  /* High power mode aka performance */
> -#define DYTC_MODE_LOWPOWER    3  /* Low power mode */
> -#define DYTC_MODE_BALANCE   0xF  /* Default mode aka balanced */
> -#define DYTC_MODE_MMC_BALANCE 0  /* Default mode from MMC_GET, aka balanced */
> +#define DYTC_MODE_MMC_PERFORM  2  /* High power mode aka performance */
> +#define DYTC_MODE_MMC_LOWPOWER 3  /* Low power mode */
> +#define DYTC_MODE_MMC_BALANCE  0xF  /* Default mode aka balanced */
> +#define DYTC_MODE_MMC_DEFAULT  0  /* Default mode from MMC_GET, aka balanced */
> +
> +#define DYTC_MODE_PSC_LOWPOWER 3  /* Low power mode */
> +#define DYTC_MODE_PSC_BALANCE  5  /* Default mode aka balanced */
> +#define DYTC_MODE_PSC_PERFORM  7  /* High power mode aka performance */
>  
>  #define DYTC_ERR_MASK       0xF  /* Bits 0-3 in cmd result are the error result */
>  #define DYTC_ERR_SUCCESS      1  /* CMD completed successful */
> @@ -10155,10 +10161,16 @@ static struct ibm_struct proxsensor_driver_data = {
>  	 (mode) << DYTC_SET_MODE_BIT | \
>  	 (on) << DYTC_SET_VALID_BIT)
>  
> -#define DYTC_DISABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 0)
> +#define DYTC_DISABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_MMC_BALANCE, 0)
> +#define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_MMC_BALANCE, 1)
>  
> -#define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 1)
> +enum dytc_profile_funcmode {
> +	DYTC_FUNCMODE_NONE = 0,
> +	DYTC_FUNCMODE_MMC,
> +	DYTC_FUNCMODE_PSC,
> +};
>  
> +static enum dytc_profile_funcmode dytc_profile_available;
>  static enum platform_profile_option dytc_current_profile;
>  static atomic_t dytc_ignore_event = ATOMIC_INIT(0);
>  static DEFINE_MUTEX(dytc_mutex);
> @@ -10166,19 +10178,37 @@ static bool dytc_mmc_get_available;
>  
>  static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *profile)
>  {
> -	switch (dytcmode) {
> -	case DYTC_MODE_LOWPOWER:
> -		*profile = PLATFORM_PROFILE_LOW_POWER;
> -		break;
> -	case DYTC_MODE_BALANCE:
> -	case DYTC_MODE_MMC_BALANCE:
> -		*profile =  PLATFORM_PROFILE_BALANCED;
> -		break;
> -	case DYTC_MODE_PERFORM:
> -		*profile =  PLATFORM_PROFILE_PERFORMANCE;
> -		break;
> -	default: /* Unknown mode */
> -		return -EINVAL;
> +	if (dytc_profile_available == DYTC_FUNCMODE_MMC) {
> +		switch (dytcmode) {
> +		case DYTC_MODE_MMC_LOWPOWER:
> +			*profile = PLATFORM_PROFILE_LOW_POWER;
> +			break;
> +		case DYTC_MODE_MMC_DEFAULT:
> +		case DYTC_MODE_MMC_BALANCE:
> +			*profile =  PLATFORM_PROFILE_BALANCED;
> +			break;
> +		case DYTC_MODE_MMC_PERFORM:
> +			*profile =  PLATFORM_PROFILE_PERFORMANCE;
> +			break;
> +		default: /* Unknown mode */
> +			return -EINVAL;
> +		}
> +		return 0;
> +	}
> +	if (dytc_profile_available == DYTC_FUNCMODE_PSC) {
> +		switch (dytcmode) {
> +		case DYTC_MODE_PSC_LOWPOWER:
> +			*profile = PLATFORM_PROFILE_LOW_POWER;
> +			break;
> +		case DYTC_MODE_PSC_BALANCE:
> +			*profile =  PLATFORM_PROFILE_BALANCED;
> +			break;
> +		case DYTC_MODE_PSC_PERFORM:
> +			*profile =  PLATFORM_PROFILE_PERFORMANCE;
> +			break;
> +		default: /* Unknown mode */
> +			return -EINVAL;
> +		}
>  	}
>  	return 0;
>  }
> @@ -10187,13 +10217,22 @@ static int convert_profile_to_dytc(enum platform_profile_option profile, int *pe
>  {
>  	switch (profile) {
>  	case PLATFORM_PROFILE_LOW_POWER:
> -		*perfmode = DYTC_MODE_LOWPOWER;
> +		if (dytc_profile_available == DYTC_FUNCMODE_MMC)
> +			*perfmode = DYTC_MODE_MMC_LOWPOWER;
> +		else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
> +			*perfmode = DYTC_MODE_PSC_LOWPOWER;
>  		break;
>  	case PLATFORM_PROFILE_BALANCED:
> -		*perfmode = DYTC_MODE_BALANCE;
> +		if (dytc_profile_available == DYTC_FUNCMODE_MMC)
> +			*perfmode = DYTC_MODE_MMC_BALANCE;
> +		else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
> +			*perfmode = DYTC_MODE_PSC_BALANCE;
>  		break;
>  	case PLATFORM_PROFILE_PERFORMANCE:
> -		*perfmode = DYTC_MODE_PERFORM;
> +		if (dytc_profile_available == DYTC_FUNCMODE_MMC)
> +			*perfmode = DYTC_MODE_MMC_PERFORM;
> +		else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
> +			*perfmode = DYTC_MODE_PSC_PERFORM;
>  		break;
>  	default: /* Unknown profile */
>  		return -EOPNOTSUPP;
> @@ -10266,25 +10305,39 @@ static int dytc_profile_set(struct platform_profile_handler *pprof,
>  	if (err)
>  		return err;
>  
> -	if (profile == PLATFORM_PROFILE_BALANCED) {
> -		/*
> -		 * To get back to balanced mode we need to issue a reset command.
> -		 * Note we still need to disable CQL mode before hand and re-enable
> -		 * it afterwards, otherwise dytc_lapmode gets reset to 0 and stays
> -		 * stuck at 0 for aprox. 30 minutes.
> -		 */
> -		err = dytc_cql_command(DYTC_CMD_RESET, &output);
> -		if (err)
> -			goto unlock;
> -	} else {
> +	if (dytc_profile_available == DYTC_FUNCMODE_MMC) {
> +		if (profile == PLATFORM_PROFILE_BALANCED) {
> +			/*
> +			 * To get back to balanced mode we need to issue a reset command.
> +			 * Note we still need to disable CQL mode before hand and re-enable
> +			 * it afterwards, otherwise dytc_lapmode gets reset to 0 and stays
> +			 * stuck at 0 for aprox. 30 minutes.
> +			 */
> +			err = dytc_cql_command(DYTC_CMD_RESET, &output);
> +			if (err)
> +				goto unlock;
> +		} else {
> +			int perfmode;
> +
> +			err = convert_profile_to_dytc(profile, &perfmode);
> +			if (err)
> +				goto unlock;
> +
> +			/* Determine if we are in CQL mode. This alters the commands we do */
> +			err = dytc_cql_command(DYTC_SET_COMMAND(DYTC_FUNCTION_MMC, perfmode, 1),
> +						&output);
> +			if (err)
> +				goto unlock;
> +		}
> +	}
> +	if (dytc_profile_available == DYTC_FUNCMODE_PSC) {
>  		int perfmode;
>  
>  		err = convert_profile_to_dytc(profile, &perfmode);
>  		if (err)
>  			goto unlock;
>  
> -		/* Determine if we are in CQL mode. This alters the commands we do */
> -		err = dytc_cql_command(DYTC_SET_COMMAND(DYTC_FUNCTION_MMC, perfmode, 1), &output);
> +		err = dytc_command(DYTC_SET_COMMAND(DYTC_FUNCTION_PSC, perfmode, 1), &output);
>  		if (err)
>  			goto unlock;
>  	}
> @@ -10302,10 +10355,14 @@ static void dytc_profile_refresh(void)
>  	int perfmode;
>  
>  	mutex_lock(&dytc_mutex);
> -	if (dytc_mmc_get_available)
> -		err = dytc_command(DYTC_CMD_MMC_GET, &output);
> -	else
> -		err = dytc_cql_command(DYTC_CMD_GET, &output);
> +	if (dytc_profile_available == DYTC_FUNCMODE_MMC) {
> +		if (dytc_mmc_get_available)
> +			err = dytc_command(DYTC_CMD_MMC_GET, &output);
> +		else
> +			err = dytc_cql_command(DYTC_CMD_GET, &output);
> +	} else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
> +		err = dytc_command(DYTC_CMD_GET, &output);
> +
>  	mutex_unlock(&dytc_mutex);
>  	if (err)
>  		return;
> @@ -10332,6 +10389,7 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
>  	set_bit(PLATFORM_PROFILE_BALANCED, dytc_profile.choices);
>  	set_bit(PLATFORM_PROFILE_PERFORMANCE, dytc_profile.choices);
>  
> +	dytc_profile_available = DYTC_FUNCMODE_NONE;
>  	err = dytc_command(DYTC_CMD_QUERY, &output);
>  	if (err)
>  		return err;
> @@ -10343,27 +10401,34 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
>  	if (dytc_version < 5)
>  		return -ENODEV;
>  
> -	/* Check what capabilities are supported. Currently MMC is needed */
> +	/* Check what capabilities are supported */
>  	err = dytc_command(DYTC_CMD_FUNC_CAP, &output);
>  	if (err)
>  		return err;
> -	if (!(output & BIT(DYTC_FC_MMC))) {
> -		dbg_printk(TPACPI_DBG_INIT, " DYTC MMC mode not supported\n");
> +
> +	if (test_bit(DYTC_FC_MMC, (void *)&output)) { /* MMC MODE */
> +		dytc_profile_available = DYTC_FUNCMODE_MMC;
> +
> +		/*
> +		 * Check if MMC_GET functionality available
> +		 * Version > 6 and return success from MMC_GET command
> +		 */
> +		dytc_mmc_get_available = false;
> +		if (dytc_version >= 6) {
> +			err = dytc_command(DYTC_CMD_MMC_GET, &output);
> +			if (!err && ((output & DYTC_ERR_MASK) == DYTC_ERR_SUCCESS))
> +				dytc_mmc_get_available = true;
> +		}
> +	} else if (test_bit(DYTC_FC_PSC, (void *)&output)) { /*PSC MODE */
> +		dytc_profile_available = DYTC_FUNCMODE_PSC;
> +	} else {
> +		dbg_printk(TPACPI_DBG_INIT, "No DYTC support available\n");
>  		return -ENODEV;
>  	}
>  
>  	dbg_printk(TPACPI_DBG_INIT,
>  			"DYTC version %d: thermal mode available\n", dytc_version);
> -	/*
> -	 * Check if MMC_GET functionality available
> -	 * Version > 6 and return success from MMC_GET command
> -	 */
> -	dytc_mmc_get_available = false;
> -	if (dytc_version >= 6) {
> -		err = dytc_command(DYTC_CMD_MMC_GET, &output);
> -		if (!err && ((output & DYTC_ERR_MASK) == DYTC_ERR_SUCCESS))
> -			dytc_mmc_get_available = true;
> -	}
> +
>  	/* Create platform_profile structure and register */
>  	err = platform_profile_register(&dytc_profile);
>  	/*
> @@ -10381,6 +10446,7 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
>  
>  static void dytc_profile_exit(void)
>  {
> +	dytc_profile_available = DYTC_FUNCMODE_NONE;
>  	platform_profile_remove();
>  }
>
Mark Pearson March 2, 2022, 3:32 p.m. UTC | #2
Thanks Hans

On 2022-03-02 09:47, Hans de Goede wrote:
> Hi,
> 
> On 2/25/22 19:25, Mark Pearson wrote:
>> 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>
> 
> Thank you for your patch, I've applied this patch to my review-hans 
> branch:
> https://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git/log/?h=review-hans>> 
> Note it will show up in my review-hans branch once I've pushed my
> local branch there, which might take a while.
> 
> Once I've run some tests on this branch the patches there will be
> added to the platform-drivers-x86/for-next branch and eventually
> will be included in the pdx86 pull-request to Linus for the next
> merge-window.
> 
> Regards,
> 
> Hans
> 
Awesome - thank you!
> 
> 
> p.s.
> 
> One small thing which I noticed which could be improved is to
> move the 2 convert_profile_to_dytc() calls in dytc_profile_set()
> to a single call at the top of the function (before taking the
> lock even) to avoid code duplication between the DYTC_FUNCMODE_MMC
> vs DYTC_FUNCMODE_PSC paths.
> 
> I didn't want to block merging the patch on this, if you can
> do a follow up patch with that as cleanup that would be great.
> 
ack - that makes sense. Will do.

Mark
diff mbox series

Patch

diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index d0599e8a7b4d..d9117f824ce9 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -10130,6 +10130,7 @@  static struct ibm_struct proxsensor_driver_data = {
 
 #define DYTC_CMD_FUNC_CAP     3 /* To get DYTC capabilities */
 #define DYTC_FC_MMC           27 /* MMC Mode supported */
+#define DYTC_FC_PSC           29 /* PSC Mode supported */
 
 #define DYTC_GET_FUNCTION_BIT 8  /* Bits  8-11 - function setting */
 #define DYTC_GET_MODE_BIT     12 /* Bits 12-15 - mode setting */
@@ -10140,12 +10141,17 @@  static struct ibm_struct proxsensor_driver_data = {
 
 #define DYTC_FUNCTION_STD     0  /* Function = 0, standard mode */
 #define DYTC_FUNCTION_CQL     1  /* Function = 1, lap mode */
-#define DYTC_FUNCTION_MMC     11 /* Function = 11, desk mode */
+#define DYTC_FUNCTION_MMC     11 /* Function = 11, MMC mode */
+#define DYTC_FUNCTION_PSC     13 /* Function = 13, PSC mode */
 
-#define DYTC_MODE_PERFORM     2  /* High power mode aka performance */
-#define DYTC_MODE_LOWPOWER    3  /* Low power mode */
-#define DYTC_MODE_BALANCE   0xF  /* Default mode aka balanced */
-#define DYTC_MODE_MMC_BALANCE 0  /* Default mode from MMC_GET, aka balanced */
+#define DYTC_MODE_MMC_PERFORM  2  /* High power mode aka performance */
+#define DYTC_MODE_MMC_LOWPOWER 3  /* Low power mode */
+#define DYTC_MODE_MMC_BALANCE  0xF  /* Default mode aka balanced */
+#define DYTC_MODE_MMC_DEFAULT  0  /* Default mode from MMC_GET, aka balanced */
+
+#define DYTC_MODE_PSC_LOWPOWER 3  /* Low power mode */
+#define DYTC_MODE_PSC_BALANCE  5  /* Default mode aka balanced */
+#define DYTC_MODE_PSC_PERFORM  7  /* High power mode aka performance */
 
 #define DYTC_ERR_MASK       0xF  /* Bits 0-3 in cmd result are the error result */
 #define DYTC_ERR_SUCCESS      1  /* CMD completed successful */
@@ -10155,10 +10161,16 @@  static struct ibm_struct proxsensor_driver_data = {
 	 (mode) << DYTC_SET_MODE_BIT | \
 	 (on) << DYTC_SET_VALID_BIT)
 
-#define DYTC_DISABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 0)
+#define DYTC_DISABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_MMC_BALANCE, 0)
+#define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_MMC_BALANCE, 1)
 
-#define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 1)
+enum dytc_profile_funcmode {
+	DYTC_FUNCMODE_NONE = 0,
+	DYTC_FUNCMODE_MMC,
+	DYTC_FUNCMODE_PSC,
+};
 
+static enum dytc_profile_funcmode dytc_profile_available;
 static enum platform_profile_option dytc_current_profile;
 static atomic_t dytc_ignore_event = ATOMIC_INIT(0);
 static DEFINE_MUTEX(dytc_mutex);
@@ -10166,19 +10178,37 @@  static bool dytc_mmc_get_available;
 
 static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *profile)
 {
-	switch (dytcmode) {
-	case DYTC_MODE_LOWPOWER:
-		*profile = PLATFORM_PROFILE_LOW_POWER;
-		break;
-	case DYTC_MODE_BALANCE:
-	case DYTC_MODE_MMC_BALANCE:
-		*profile =  PLATFORM_PROFILE_BALANCED;
-		break;
-	case DYTC_MODE_PERFORM:
-		*profile =  PLATFORM_PROFILE_PERFORMANCE;
-		break;
-	default: /* Unknown mode */
-		return -EINVAL;
+	if (dytc_profile_available == DYTC_FUNCMODE_MMC) {
+		switch (dytcmode) {
+		case DYTC_MODE_MMC_LOWPOWER:
+			*profile = PLATFORM_PROFILE_LOW_POWER;
+			break;
+		case DYTC_MODE_MMC_DEFAULT:
+		case DYTC_MODE_MMC_BALANCE:
+			*profile =  PLATFORM_PROFILE_BALANCED;
+			break;
+		case DYTC_MODE_MMC_PERFORM:
+			*profile =  PLATFORM_PROFILE_PERFORMANCE;
+			break;
+		default: /* Unknown mode */
+			return -EINVAL;
+		}
+		return 0;
+	}
+	if (dytc_profile_available == DYTC_FUNCMODE_PSC) {
+		switch (dytcmode) {
+		case DYTC_MODE_PSC_LOWPOWER:
+			*profile = PLATFORM_PROFILE_LOW_POWER;
+			break;
+		case DYTC_MODE_PSC_BALANCE:
+			*profile =  PLATFORM_PROFILE_BALANCED;
+			break;
+		case DYTC_MODE_PSC_PERFORM:
+			*profile =  PLATFORM_PROFILE_PERFORMANCE;
+			break;
+		default: /* Unknown mode */
+			return -EINVAL;
+		}
 	}
 	return 0;
 }
@@ -10187,13 +10217,22 @@  static int convert_profile_to_dytc(enum platform_profile_option profile, int *pe
 {
 	switch (profile) {
 	case PLATFORM_PROFILE_LOW_POWER:
-		*perfmode = DYTC_MODE_LOWPOWER;
+		if (dytc_profile_available == DYTC_FUNCMODE_MMC)
+			*perfmode = DYTC_MODE_MMC_LOWPOWER;
+		else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
+			*perfmode = DYTC_MODE_PSC_LOWPOWER;
 		break;
 	case PLATFORM_PROFILE_BALANCED:
-		*perfmode = DYTC_MODE_BALANCE;
+		if (dytc_profile_available == DYTC_FUNCMODE_MMC)
+			*perfmode = DYTC_MODE_MMC_BALANCE;
+		else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
+			*perfmode = DYTC_MODE_PSC_BALANCE;
 		break;
 	case PLATFORM_PROFILE_PERFORMANCE:
-		*perfmode = DYTC_MODE_PERFORM;
+		if (dytc_profile_available == DYTC_FUNCMODE_MMC)
+			*perfmode = DYTC_MODE_MMC_PERFORM;
+		else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
+			*perfmode = DYTC_MODE_PSC_PERFORM;
 		break;
 	default: /* Unknown profile */
 		return -EOPNOTSUPP;
@@ -10266,25 +10305,39 @@  static int dytc_profile_set(struct platform_profile_handler *pprof,
 	if (err)
 		return err;
 
-	if (profile == PLATFORM_PROFILE_BALANCED) {
-		/*
-		 * To get back to balanced mode we need to issue a reset command.
-		 * Note we still need to disable CQL mode before hand and re-enable
-		 * it afterwards, otherwise dytc_lapmode gets reset to 0 and stays
-		 * stuck at 0 for aprox. 30 minutes.
-		 */
-		err = dytc_cql_command(DYTC_CMD_RESET, &output);
-		if (err)
-			goto unlock;
-	} else {
+	if (dytc_profile_available == DYTC_FUNCMODE_MMC) {
+		if (profile == PLATFORM_PROFILE_BALANCED) {
+			/*
+			 * To get back to balanced mode we need to issue a reset command.
+			 * Note we still need to disable CQL mode before hand and re-enable
+			 * it afterwards, otherwise dytc_lapmode gets reset to 0 and stays
+			 * stuck at 0 for aprox. 30 minutes.
+			 */
+			err = dytc_cql_command(DYTC_CMD_RESET, &output);
+			if (err)
+				goto unlock;
+		} else {
+			int perfmode;
+
+			err = convert_profile_to_dytc(profile, &perfmode);
+			if (err)
+				goto unlock;
+
+			/* Determine if we are in CQL mode. This alters the commands we do */
+			err = dytc_cql_command(DYTC_SET_COMMAND(DYTC_FUNCTION_MMC, perfmode, 1),
+						&output);
+			if (err)
+				goto unlock;
+		}
+	}
+	if (dytc_profile_available == DYTC_FUNCMODE_PSC) {
 		int perfmode;
 
 		err = convert_profile_to_dytc(profile, &perfmode);
 		if (err)
 			goto unlock;
 
-		/* Determine if we are in CQL mode. This alters the commands we do */
-		err = dytc_cql_command(DYTC_SET_COMMAND(DYTC_FUNCTION_MMC, perfmode, 1), &output);
+		err = dytc_command(DYTC_SET_COMMAND(DYTC_FUNCTION_PSC, perfmode, 1), &output);
 		if (err)
 			goto unlock;
 	}
@@ -10302,10 +10355,14 @@  static void dytc_profile_refresh(void)
 	int perfmode;
 
 	mutex_lock(&dytc_mutex);
-	if (dytc_mmc_get_available)
-		err = dytc_command(DYTC_CMD_MMC_GET, &output);
-	else
-		err = dytc_cql_command(DYTC_CMD_GET, &output);
+	if (dytc_profile_available == DYTC_FUNCMODE_MMC) {
+		if (dytc_mmc_get_available)
+			err = dytc_command(DYTC_CMD_MMC_GET, &output);
+		else
+			err = dytc_cql_command(DYTC_CMD_GET, &output);
+	} else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
+		err = dytc_command(DYTC_CMD_GET, &output);
+
 	mutex_unlock(&dytc_mutex);
 	if (err)
 		return;
@@ -10332,6 +10389,7 @@  static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
 	set_bit(PLATFORM_PROFILE_BALANCED, dytc_profile.choices);
 	set_bit(PLATFORM_PROFILE_PERFORMANCE, dytc_profile.choices);
 
+	dytc_profile_available = DYTC_FUNCMODE_NONE;
 	err = dytc_command(DYTC_CMD_QUERY, &output);
 	if (err)
 		return err;
@@ -10343,27 +10401,34 @@  static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
 	if (dytc_version < 5)
 		return -ENODEV;
 
-	/* Check what capabilities are supported. Currently MMC is needed */
+	/* Check what capabilities are supported */
 	err = dytc_command(DYTC_CMD_FUNC_CAP, &output);
 	if (err)
 		return err;
-	if (!(output & BIT(DYTC_FC_MMC))) {
-		dbg_printk(TPACPI_DBG_INIT, " DYTC MMC mode not supported\n");
+
+	if (test_bit(DYTC_FC_MMC, (void *)&output)) { /* MMC MODE */
+		dytc_profile_available = DYTC_FUNCMODE_MMC;
+
+		/*
+		 * Check if MMC_GET functionality available
+		 * Version > 6 and return success from MMC_GET command
+		 */
+		dytc_mmc_get_available = false;
+		if (dytc_version >= 6) {
+			err = dytc_command(DYTC_CMD_MMC_GET, &output);
+			if (!err && ((output & DYTC_ERR_MASK) == DYTC_ERR_SUCCESS))
+				dytc_mmc_get_available = true;
+		}
+	} else if (test_bit(DYTC_FC_PSC, (void *)&output)) { /*PSC MODE */
+		dytc_profile_available = DYTC_FUNCMODE_PSC;
+	} else {
+		dbg_printk(TPACPI_DBG_INIT, "No DYTC support available\n");
 		return -ENODEV;
 	}
 
 	dbg_printk(TPACPI_DBG_INIT,
 			"DYTC version %d: thermal mode available\n", dytc_version);
-	/*
-	 * Check if MMC_GET functionality available
-	 * Version > 6 and return success from MMC_GET command
-	 */
-	dytc_mmc_get_available = false;
-	if (dytc_version >= 6) {
-		err = dytc_command(DYTC_CMD_MMC_GET, &output);
-		if (!err && ((output & DYTC_ERR_MASK) == DYTC_ERR_SUCCESS))
-			dytc_mmc_get_available = true;
-	}
+
 	/* Create platform_profile structure and register */
 	err = platform_profile_register(&dytc_profile);
 	/*
@@ -10381,6 +10446,7 @@  static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
 
 static void dytc_profile_exit(void)
 {
+	dytc_profile_available = DYTC_FUNCMODE_NONE;
 	platform_profile_remove();
 }