diff mbox series

[RESEND,2/2] soc: qcom: rpmhpd: Make power_on actually enable the domain

Message ID 20210703025449.2687201-1-bjorn.andersson@linaro.org
State Superseded
Headers show
Series None | expand

Commit Message

Bjorn Andersson July 3, 2021, 2:54 a.m. UTC
The general expectation is that powering on a power-domain should make
the power domain deliver some power, and if a specific performace state
is needed further requests has to be made.

But in contrast with other power-domain implementations (e.g. rpmpd) the
RPMh does not have an interface to enable the power, so the driver has
to vote for a particular corner (performance level) in rpmh_power_on().

But the corner is never initialized, so a typical request to simply
enable the power domain would not actually turn on the hardware. Further
more, when no more clients vote for a performance state (i.e. the
aggregated vote is 0) the power domain would be turn off.

Fix both of these issues by always voting for a corner with non-zero
value, when the power domain is enabled.

The tracking of the lowest non-zero corner is performed to handle the
corner case if there's ever a domain with a non-zero lowest corner, in
which case both rpmh_power_on() and rpmh_rpmhpd_set_performance_state()
would be allowed to use this lowest corner.

Fixes: 279b7e8a62cc ("soc: qcom: rpmhpd: Add RPMh power domain driver")
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>

---

Resending because the hunk in rpmhpd_update_level_mapping() was left in the
index.

 drivers/soc/qcom/rpmhpd.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

-- 
2.29.2

Comments

Stephen Boyd July 8, 2021, 12:23 a.m. UTC | #1
Quoting Bjorn Andersson (2021-07-02 19:54:49)
> The general expectation is that powering on a power-domain should make

> the power domain deliver some power, and if a specific performace state

> is needed further requests has to be made.

>

> But in contrast with other power-domain implementations (e.g. rpmpd) the

> RPMh does not have an interface to enable the power, so the driver has

> to vote for a particular corner (performance level) in rpmh_power_on().

>

> But the corner is never initialized, so a typical request to simply

> enable the power domain would not actually turn on the hardware. Further

> more, when no more clients vote for a performance state (i.e. the

> aggregated vote is 0) the power domain would be turn off.


s/turn/turned/

>

> Fix both of these issues by always voting for a corner with non-zero

> value, when the power domain is enabled.

>

> The tracking of the lowest non-zero corner is performed to handle the

> corner case if there's ever a domain with a non-zero lowest corner, in

> which case both rpmh_power_on() and rpmh_rpmhpd_set_performance_state()

> would be allowed to use this lowest corner.

>

> Fixes: 279b7e8a62cc ("soc: qcom: rpmhpd: Add RPMh power domain driver")

> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>

> ---


Reviewed-by: Stephen Boyd <swboyd@chromium.org>
Stephen Boyd July 8, 2021, 12:25 a.m. UTC | #2
Quoting Bjorn Andersson (2021-07-02 19:54:49)
> @@ -472,6 +478,10 @@ static int rpmhpd_update_level_mapping(struct rpmhpd *rpmhpd)

>         for (i = 0; i < rpmhpd->level_count; i++) {

>                 rpmhpd->level[i] = buf[i];


BTW, this looks like it should actually be an __le16 pointer and then we
should do le16_to_cpup() here. Hooray for void pointers.

>

> +               /* Remember the first non-zero corner */

> +               if (!rpmhpd->enable_corner)

> +                       rpmhpd->enable_corner = i;

> +
Rajendra Nayak July 14, 2021, 9:22 a.m. UTC | #3
On 7/3/2021 8:24 AM, Bjorn Andersson wrote:
> The general expectation is that powering on a power-domain should make

> the power domain deliver some power, and if a specific performace state

> is needed further requests has to be made.

> 

> But in contrast with other power-domain implementations (e.g. rpmpd) the

> RPMh does not have an interface to enable the power, so the driver has

> to vote for a particular corner (performance level) in rpmh_power_on().

> 

> But the corner is never initialized, so a typical request to simply

> enable the power domain would not actually turn on the hardware. Further

> more, when no more clients vote for a performance state (i.e. the

> aggregated vote is 0) the power domain would be turn off.

> 

> Fix both of these issues by always voting for a corner with non-zero

> value, when the power domain is enabled.

> 

> The tracking of the lowest non-zero corner is performed to handle the

> corner case if there's ever a domain with a non-zero lowest corner, in

> which case both rpmh_power_on() and rpmh_rpmhpd_set_performance_state()

> would be allowed to use this lowest corner.

> 

> Fixes: 279b7e8a62cc ("soc: qcom: rpmhpd: Add RPMh power domain driver")

> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>


Did some testing on sc7180 and sc7280 devices, no regressions seen,
Reviewed-by: Rajendra Nayak <rnayak@codeaurora.org>

Tested-by: Rajendra Nayak <rnayak@codeaurora.org>


> ---

> 

> Resending because the hunk in rpmhpd_update_level_mapping() was left in the

> index.

> 

>   drivers/soc/qcom/rpmhpd.c | 18 ++++++++++++++----

>   1 file changed, 14 insertions(+), 4 deletions(-)

> 

> diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c

> index fa209b479ab3..76ea6b053ef0 100644

> --- a/drivers/soc/qcom/rpmhpd.c

> +++ b/drivers/soc/qcom/rpmhpd.c

> @@ -30,6 +30,7 @@

>    * @active_only:	True if it represents an Active only peer

>    * @corner:		current corner

>    * @active_corner:	current active corner

> + * @enable_corner:	lowest non-zero corner

>    * @level:		An array of level (vlvl) to corner (hlvl) mappings

>    *			derived from cmd-db

>    * @level_count:	Number of levels supported by the power domain. max

> @@ -47,6 +48,7 @@ struct rpmhpd {

>   	const bool	active_only;

>   	unsigned int	corner;

>   	unsigned int	active_corner;

> +	unsigned int	enable_corner;

>   	u32		level[RPMH_ARC_MAX_LEVELS];

>   	size_t		level_count;

>   	bool		enabled;

> @@ -385,13 +387,13 @@ static int rpmhpd_aggregate_corner(struct rpmhpd *pd, unsigned int corner)

>   static int rpmhpd_power_on(struct generic_pm_domain *domain)

>   {

>   	struct rpmhpd *pd = domain_to_rpmhpd(domain);

> -	int ret = 0;

> +	unsigned int corner;

> +	int ret;

>   

>   	mutex_lock(&rpmhpd_lock);

>   

> -	if (pd->corner)

> -		ret = rpmhpd_aggregate_corner(pd, pd->corner);

> -

> +	corner = max(pd->corner, pd->enable_corner);

> +	ret = rpmhpd_aggregate_corner(pd, corner);

>   	if (!ret)

>   		pd->enabled = true;

>   

> @@ -436,6 +438,10 @@ static int rpmhpd_set_performance_state(struct generic_pm_domain *domain,

>   		i--;

>   

>   	if (pd->enabled) {

> +		/* Ensure that the domain isn't turn off */

> +		if (i < pd->enable_corner)

> +			i = pd->enable_corner;

> +

>   		ret = rpmhpd_aggregate_corner(pd, i);

>   		if (ret)

>   			goto out;

> @@ -472,6 +478,10 @@ static int rpmhpd_update_level_mapping(struct rpmhpd *rpmhpd)

>   	for (i = 0; i < rpmhpd->level_count; i++) {

>   		rpmhpd->level[i] = buf[i];

>   

> +		/* Remember the first non-zero corner */

> +		if (!rpmhpd->enable_corner)

> +			rpmhpd->enable_corner = i;

> +

>   		/*

>   		 * The AUX data may be zero padded.  These 0 valued entries at

>   		 * the end of the map must be ignored.

> 


-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
Sibi Sankar July 15, 2021, 12:16 p.m. UTC | #4
Hey Bjorn,

Thanks for the patch.

On 2021-07-03 08:24, Bjorn Andersson wrote:
> The general expectation is that powering on a power-domain should make

> the power domain deliver some power, and if a specific performace state


s/performace/performance/

> is needed further requests has to be made.

> 

> But in contrast with other power-domain implementations (e.g. rpmpd) 

> the

> RPMh does not have an interface to enable the power, so the driver has

> to vote for a particular corner (performance level) in rpmh_power_on().

> 

> But the corner is never initialized, so a typical request to simply

> enable the power domain would not actually turn on the hardware. 

> Further

> more, when no more clients vote for a performance state (i.e. the

> aggregated vote is 0) the power domain would be turn off.

> 

> Fix both of these issues by always voting for a corner with non-zero

> value, when the power domain is enabled.

> 

> The tracking of the lowest non-zero corner is performed to handle the

> corner case if there's ever a domain with a non-zero lowest corner, in

> which case both rpmh_power_on() and rpmh_rpmhpd_set_performance_state()

> would be allowed to use this lowest corner.

> 

> Fixes: 279b7e8a62cc ("soc: qcom: rpmhpd: Add RPMh power domain driver")

> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>

> ---

> 

> Resending because the hunk in rpmhpd_update_level_mapping() was left in 

> the

> index.

> 

>  drivers/soc/qcom/rpmhpd.c | 18 ++++++++++++++----

>  1 file changed, 14 insertions(+), 4 deletions(-)

> 

> diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c

> index fa209b479ab3..76ea6b053ef0 100644

> --- a/drivers/soc/qcom/rpmhpd.c

> +++ b/drivers/soc/qcom/rpmhpd.c

> @@ -30,6 +30,7 @@

>   * @active_only:	True if it represents an Active only peer

>   * @corner:		current corner

>   * @active_corner:	current active corner

> + * @enable_corner:	lowest non-zero corner

>   * @level:		An array of level (vlvl) to corner (hlvl) mappings

>   *			derived from cmd-db

>   * @level_count:	Number of levels supported by the power domain. max

> @@ -47,6 +48,7 @@ struct rpmhpd {

>  	const bool	active_only;

>  	unsigned int	corner;

>  	unsigned int	active_corner;

> +	unsigned int	enable_corner;

>  	u32		level[RPMH_ARC_MAX_LEVELS];

>  	size_t		level_count;

>  	bool		enabled;

> @@ -385,13 +387,13 @@ static int rpmhpd_aggregate_corner(struct rpmhpd

> *pd, unsigned int corner)

>  static int rpmhpd_power_on(struct generic_pm_domain *domain)

>  {

>  	struct rpmhpd *pd = domain_to_rpmhpd(domain);

> -	int ret = 0;

> +	unsigned int corner;

> +	int ret;

> 

>  	mutex_lock(&rpmhpd_lock);

> 

> -	if (pd->corner)

> -		ret = rpmhpd_aggregate_corner(pd, pd->corner);

> -

> +	corner = max(pd->corner, pd->enable_corner);

> +	ret = rpmhpd_aggregate_corner(pd, corner);

>  	if (!ret)

>  		pd->enabled = true;

> 

> @@ -436,6 +438,10 @@ static int rpmhpd_set_performance_state(struct

> generic_pm_domain *domain,

>  		i--;

> 

>  	if (pd->enabled) {

> +		/* Ensure that the domain isn't turn off */

> +		if (i < pd->enable_corner)

> +			i = pd->enable_corner;

> +

>  		ret = rpmhpd_aggregate_corner(pd, i);

>  		if (ret)

>  			goto out;

> @@ -472,6 +478,10 @@ static int rpmhpd_update_level_mapping(struct

> rpmhpd *rpmhpd)

>  	for (i = 0; i < rpmhpd->level_count; i++) {

>  		rpmhpd->level[i] = buf[i];

> 

> +		/* Remember the first non-zero corner */


Shouldn't we be tracking the corner that
corresponds to the first non-zero level
instead?

> +		if (!rpmhpd->enable_corner)

> +			rpmhpd->enable_corner = i;

> +

>  		/*

>  		 * The AUX data may be zero padded.  These 0 valued entries at

>  		 * the end of the map must be ignored.


-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project.
Rajendra Nayak July 15, 2021, 12:24 p.m. UTC | #5
On 7/15/2021 5:46 PM, Sibi Sankar wrote:
> Hey Bjorn,

> 

> Thanks for the patch.

> 

> On 2021-07-03 08:24, Bjorn Andersson wrote:

>> The general expectation is that powering on a power-domain should make

>> the power domain deliver some power, and if a specific performace state

> 

> s/performace/performance/

> 

>> is needed further requests has to be made.

>>

>> But in contrast with other power-domain implementations (e.g. rpmpd) the

>> RPMh does not have an interface to enable the power, so the driver has

>> to vote for a particular corner (performance level) in rpmh_power_on().

>>

>> But the corner is never initialized, so a typical request to simply

>> enable the power domain would not actually turn on the hardware. Further

>> more, when no more clients vote for a performance state (i.e. the

>> aggregated vote is 0) the power domain would be turn off.

>>

>> Fix both of these issues by always voting for a corner with non-zero

>> value, when the power domain is enabled.

>>

>> The tracking of the lowest non-zero corner is performed to handle the

>> corner case if there's ever a domain with a non-zero lowest corner, in

>> which case both rpmh_power_on() and rpmh_rpmhpd_set_performance_state()

>> would be allowed to use this lowest corner.

>>

>> Fixes: 279b7e8a62cc ("soc: qcom: rpmhpd: Add RPMh power domain driver")

>> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>

>> ---

>>

>> Resending because the hunk in rpmhpd_update_level_mapping() was left in the

>> index.

>>

>>  drivers/soc/qcom/rpmhpd.c | 18 ++++++++++++++----

>>  1 file changed, 14 insertions(+), 4 deletions(-)

>>

>> diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c

>> index fa209b479ab3..76ea6b053ef0 100644

>> --- a/drivers/soc/qcom/rpmhpd.c

>> +++ b/drivers/soc/qcom/rpmhpd.c

>> @@ -30,6 +30,7 @@

>>   * @active_only:    True if it represents an Active only peer

>>   * @corner:        current corner

>>   * @active_corner:    current active corner

>> + * @enable_corner:    lowest non-zero corner

>>   * @level:        An array of level (vlvl) to corner (hlvl) mappings

>>   *            derived from cmd-db

>>   * @level_count:    Number of levels supported by the power domain. max

>> @@ -47,6 +48,7 @@ struct rpmhpd {

>>      const bool    active_only;

>>      unsigned int    corner;

>>      unsigned int    active_corner;

>> +    unsigned int    enable_corner;

>>      u32        level[RPMH_ARC_MAX_LEVELS];

>>      size_t        level_count;

>>      bool        enabled;

>> @@ -385,13 +387,13 @@ static int rpmhpd_aggregate_corner(struct rpmhpd

>> *pd, unsigned int corner)

>>  static int rpmhpd_power_on(struct generic_pm_domain *domain)

>>  {

>>      struct rpmhpd *pd = domain_to_rpmhpd(domain);

>> -    int ret = 0;

>> +    unsigned int corner;

>> +    int ret;

>>

>>      mutex_lock(&rpmhpd_lock);

>>

>> -    if (pd->corner)

>> -        ret = rpmhpd_aggregate_corner(pd, pd->corner);

>> -

>> +    corner = max(pd->corner, pd->enable_corner);

>> +    ret = rpmhpd_aggregate_corner(pd, corner);

>>      if (!ret)

>>          pd->enabled = true;

>>

>> @@ -436,6 +438,10 @@ static int rpmhpd_set_performance_state(struct

>> generic_pm_domain *domain,

>>          i--;

>>

>>      if (pd->enabled) {

>> +        /* Ensure that the domain isn't turn off */

>> +        if (i < pd->enable_corner)

>> +            i = pd->enable_corner;

>> +

>>          ret = rpmhpd_aggregate_corner(pd, i);

>>          if (ret)

>>              goto out;

>> @@ -472,6 +478,10 @@ static int rpmhpd_update_level_mapping(struct

>> rpmhpd *rpmhpd)

>>      for (i = 0; i < rpmhpd->level_count; i++) {

>>          rpmhpd->level[i] = buf[i];

>>

>> +        /* Remember the first non-zero corner */

> 

> Shouldn't we be tracking the corner that

> corresponds to the first non-zero level

> instead?


Thats correct, thanks for spotting this, the first non-zero
corner is always 1 :)

> 

>> +        if (!rpmhpd->enable_corner)

>> +            rpmhpd->enable_corner = i;

>> +

>>          /*

>>           * The AUX data may be zero padded.  These 0 valued entries at

>>           * the end of the map must be ignored.

> 


-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
Dmitry Baryshkov Aug. 12, 2021, 1:21 p.m. UTC | #6
On 03/07/2021 05:54, Bjorn Andersson wrote:
> The general expectation is that powering on a power-domain should make

> the power domain deliver some power, and if a specific performace state

> is needed further requests has to be made.

> 

> But in contrast with other power-domain implementations (e.g. rpmpd) the

> RPMh does not have an interface to enable the power, so the driver has

> to vote for a particular corner (performance level) in rpmh_power_on().

> 

> But the corner is never initialized, so a typical request to simply

> enable the power domain would not actually turn on the hardware. Further

> more, when no more clients vote for a performance state (i.e. the

> aggregated vote is 0) the power domain would be turn off.

> 

> Fix both of these issues by always voting for a corner with non-zero

> value, when the power domain is enabled.

> 

> The tracking of the lowest non-zero corner is performed to handle the

> corner case if there's ever a domain with a non-zero lowest corner, in

> which case both rpmh_power_on() and rpmh_rpmhpd_set_performance_state()

> would be allowed to use this lowest corner.

> 

> Fixes: 279b7e8a62cc ("soc: qcom: rpmhpd: Add RPMh power domain driver")

> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>

> ---

> 

> Resending because the hunk in rpmhpd_update_level_mapping() was left in the

> index.


So, colleagues, what is the fate of this patch? Is it going to be 
applied? Or we agree that current approach (power_on + 
set_performance_state) is the expected behaviour? My patches on gdsc 
rework depend on this patch, but I can rework in them in favour of 
required-opp approach.

> 

>   drivers/soc/qcom/rpmhpd.c | 18 ++++++++++++++----

>   1 file changed, 14 insertions(+), 4 deletions(-)

> 

> diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c

> index fa209b479ab3..76ea6b053ef0 100644

> --- a/drivers/soc/qcom/rpmhpd.c

> +++ b/drivers/soc/qcom/rpmhpd.c

> @@ -30,6 +30,7 @@

>    * @active_only:	True if it represents an Active only peer

>    * @corner:		current corner

>    * @active_corner:	current active corner

> + * @enable_corner:	lowest non-zero corner

>    * @level:		An array of level (vlvl) to corner (hlvl) mappings

>    *			derived from cmd-db

>    * @level_count:	Number of levels supported by the power domain. max

> @@ -47,6 +48,7 @@ struct rpmhpd {

>   	const bool	active_only;

>   	unsigned int	corner;

>   	unsigned int	active_corner;

> +	unsigned int	enable_corner;

>   	u32		level[RPMH_ARC_MAX_LEVELS];

>   	size_t		level_count;

>   	bool		enabled;

> @@ -385,13 +387,13 @@ static int rpmhpd_aggregate_corner(struct rpmhpd *pd, unsigned int corner)

>   static int rpmhpd_power_on(struct generic_pm_domain *domain)

>   {

>   	struct rpmhpd *pd = domain_to_rpmhpd(domain);

> -	int ret = 0;

> +	unsigned int corner;

> +	int ret;

>   

>   	mutex_lock(&rpmhpd_lock);

>   

> -	if (pd->corner)

> -		ret = rpmhpd_aggregate_corner(pd, pd->corner);

> -

> +	corner = max(pd->corner, pd->enable_corner);

> +	ret = rpmhpd_aggregate_corner(pd, corner);

>   	if (!ret)

>   		pd->enabled = true;

>   

> @@ -436,6 +438,10 @@ static int rpmhpd_set_performance_state(struct generic_pm_domain *domain,

>   		i--;

>   

>   	if (pd->enabled) {

> +		/* Ensure that the domain isn't turn off */

> +		if (i < pd->enable_corner)

> +			i = pd->enable_corner;

> +

>   		ret = rpmhpd_aggregate_corner(pd, i);

>   		if (ret)

>   			goto out;

> @@ -472,6 +478,10 @@ static int rpmhpd_update_level_mapping(struct rpmhpd *rpmhpd)

>   	for (i = 0; i < rpmhpd->level_count; i++) {

>   		rpmhpd->level[i] = buf[i];

>   

> +		/* Remember the first non-zero corner */

> +		if (!rpmhpd->enable_corner)

> +			rpmhpd->enable_corner = i;

> +

>   		/*

>   		 * The AUX data may be zero padded.  These 0 valued entries at

>   		 * the end of the map must be ignored.

> 



-- 
With best wishes
Dmitry
Ulf Hansson Aug. 13, 2021, 9:45 a.m. UTC | #7
On Thu, 12 Aug 2021 at 15:21, Dmitry Baryshkov
<dmitry.baryshkov@linaro.org> wrote:
>

> On 03/07/2021 05:54, Bjorn Andersson wrote:

> > The general expectation is that powering on a power-domain should make

> > the power domain deliver some power, and if a specific performace state

> > is needed further requests has to be made.

> >

> > But in contrast with other power-domain implementations (e.g. rpmpd) the

> > RPMh does not have an interface to enable the power, so the driver has

> > to vote for a particular corner (performance level) in rpmh_power_on().

> >

> > But the corner is never initialized, so a typical request to simply

> > enable the power domain would not actually turn on the hardware. Further

> > more, when no more clients vote for a performance state (i.e. the

> > aggregated vote is 0) the power domain would be turn off.

> >

> > Fix both of these issues by always voting for a corner with non-zero

> > value, when the power domain is enabled.

> >

> > The tracking of the lowest non-zero corner is performed to handle the

> > corner case if there's ever a domain with a non-zero lowest corner, in

> > which case both rpmh_power_on() and rpmh_rpmhpd_set_performance_state()

> > would be allowed to use this lowest corner.

> >

> > Fixes: 279b7e8a62cc ("soc: qcom: rpmhpd: Add RPMh power domain driver")

> > Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>

> > ---

> >

> > Resending because the hunk in rpmhpd_update_level_mapping() was left in the

> > index.

>

> So, colleagues, what is the fate of this patch? Is it going to be

> applied? Or we agree that current approach (power_on +

> set_performance_state) is the expected behaviour? My patches on gdsc

> rework depend on this patch, but I can rework in them in favour of

> required-opp approach.


Today, genpd treats performance states and power on/off states as
orthogonal. You know this already, ofcourse.

Although, to clarify, this means that the genpd provider has to deal
with the scenario when its ->set_performance_state() callback may be
invoked, while the PM domain is turned off, for example. Similarly,
genpd may power on the PM domain by invoking the ->power_on()
callback, before the ->set_performance_state() has been invoked. And
finally, the power domain may be turned off even if there are some
active votes for a performance state.

So for now, the genpd provider needs to deal with these cases. Yes, we
have discussed changing the behaviour in genpd around this and I think
there have been some good reasons for it, but we are not there, at
least yet.

[...]

Kind regards
Uffe
diff mbox series

Patch

diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c
index fa209b479ab3..76ea6b053ef0 100644
--- a/drivers/soc/qcom/rpmhpd.c
+++ b/drivers/soc/qcom/rpmhpd.c
@@ -30,6 +30,7 @@ 
  * @active_only:	True if it represents an Active only peer
  * @corner:		current corner
  * @active_corner:	current active corner
+ * @enable_corner:	lowest non-zero corner
  * @level:		An array of level (vlvl) to corner (hlvl) mappings
  *			derived from cmd-db
  * @level_count:	Number of levels supported by the power domain. max
@@ -47,6 +48,7 @@  struct rpmhpd {
 	const bool	active_only;
 	unsigned int	corner;
 	unsigned int	active_corner;
+	unsigned int	enable_corner;
 	u32		level[RPMH_ARC_MAX_LEVELS];
 	size_t		level_count;
 	bool		enabled;
@@ -385,13 +387,13 @@  static int rpmhpd_aggregate_corner(struct rpmhpd *pd, unsigned int corner)
 static int rpmhpd_power_on(struct generic_pm_domain *domain)
 {
 	struct rpmhpd *pd = domain_to_rpmhpd(domain);
-	int ret = 0;
+	unsigned int corner;
+	int ret;
 
 	mutex_lock(&rpmhpd_lock);
 
-	if (pd->corner)
-		ret = rpmhpd_aggregate_corner(pd, pd->corner);
-
+	corner = max(pd->corner, pd->enable_corner);
+	ret = rpmhpd_aggregate_corner(pd, corner);
 	if (!ret)
 		pd->enabled = true;
 
@@ -436,6 +438,10 @@  static int rpmhpd_set_performance_state(struct generic_pm_domain *domain,
 		i--;
 
 	if (pd->enabled) {
+		/* Ensure that the domain isn't turn off */
+		if (i < pd->enable_corner)
+			i = pd->enable_corner;
+
 		ret = rpmhpd_aggregate_corner(pd, i);
 		if (ret)
 			goto out;
@@ -472,6 +478,10 @@  static int rpmhpd_update_level_mapping(struct rpmhpd *rpmhpd)
 	for (i = 0; i < rpmhpd->level_count; i++) {
 		rpmhpd->level[i] = buf[i];
 
+		/* Remember the first non-zero corner */
+		if (!rpmhpd->enable_corner)
+			rpmhpd->enable_corner = i;
+
 		/*
 		 * The AUX data may be zero padded.  These 0 valued entries at
 		 * the end of the map must be ignored.