ARM: at91: pm: add per soc validation of pm modes

Not all SoCs supports all the PM mode. User may end up settings,
e.g. backup mode, on a non SAMA5D2 device, but the mode to not be valid.
If backup mode is used on a devices not supporting it there will be no
way of resuming other than rebooting.

Signed-off-by: Claudiu Beznea <claudiu.beznea@microchip.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Link: https://lore.kernel.org/r/1596616610-15460-3-git-send-email-claudiu.beznea@microchip.com
This commit is contained in:
Claudiu Beznea 2020-08-05 11:36:49 +03:00 committed by Alexandre Belloni
parent e70bfc2fa8
commit 39add36049
1 changed files with 79 additions and 1 deletions

View File

@ -790,6 +790,51 @@ static const struct of_device_id atmel_pmc_ids[] __initconst = {
{ /* sentinel */ },
};
static void __init at91_pm_modes_validate(const int *modes, int len)
{
u8 i, standby = 0, suspend = 0;
int mode;
for (i = 0; i < len; i++) {
if (standby && suspend)
break;
if (modes[i] == soc_pm.data.standby_mode && !standby) {
standby = 1;
continue;
}
if (modes[i] == soc_pm.data.suspend_mode && !suspend) {
suspend = 1;
continue;
}
}
if (!standby) {
if (soc_pm.data.suspend_mode == AT91_PM_STANDBY)
mode = AT91_PM_ULP0;
else
mode = AT91_PM_STANDBY;
pr_warn("AT91: PM: %s mode not supported! Using %s.\n",
pm_modes[soc_pm.data.standby_mode].pattern,
pm_modes[mode].pattern);
soc_pm.data.standby_mode = mode;
}
if (!suspend) {
if (soc_pm.data.standby_mode == AT91_PM_ULP0)
mode = AT91_PM_STANDBY;
else
mode = AT91_PM_ULP0;
pr_warn("AT91: PM: %s mode not supported! Using %s.\n",
pm_modes[soc_pm.data.suspend_mode].pattern,
pm_modes[mode].pattern);
soc_pm.data.suspend_mode = mode;
}
}
static void __init at91_pm_init(void (*pm_idle)(void))
{
struct device_node *pmc_np;
@ -831,6 +876,14 @@ void __init at91rm9200_pm_init(void)
if (!IS_ENABLED(CONFIG_SOC_AT91RM9200))
return;
/*
* Force STANDBY and ULP0 mode to avoid calling
* at91_pm_modes_validate() which may increase booting time.
* Platform supports anyway only STANDBY and ULP0 modes.
*/
soc_pm.data.standby_mode = AT91_PM_STANDBY;
soc_pm.data.suspend_mode = AT91_PM_ULP0;
at91_dt_ramc();
/*
@ -843,9 +896,14 @@ void __init at91rm9200_pm_init(void)
void __init sam9x60_pm_init(void)
{
static const int modes[] __initconst = {
AT91_PM_STANDBY, AT91_PM_ULP0, AT91_PM_ULP0_FAST, AT91_PM_ULP1,
};
if (!IS_ENABLED(CONFIG_SOC_SAM9X60))
return;
at91_pm_modes_validate(modes, ARRAY_SIZE(modes));
at91_pm_modes_init();
at91_dt_ramc();
at91_pm_init(at91sam9x60_idle);
@ -859,26 +917,46 @@ void __init at91sam9_pm_init(void)
if (!IS_ENABLED(CONFIG_SOC_AT91SAM9))
return;
/*
* Force STANDBY and ULP0 mode to avoid calling
* at91_pm_modes_validate() which may increase booting time.
* Platform supports anyway only STANDBY and ULP0 modes.
*/
soc_pm.data.standby_mode = AT91_PM_STANDBY;
soc_pm.data.suspend_mode = AT91_PM_ULP0;
at91_dt_ramc();
at91_pm_init(at91sam9_idle);
}
void __init sama5_pm_init(void)
{
static const int modes[] __initconst = {
AT91_PM_STANDBY, AT91_PM_ULP0, AT91_PM_ULP0_FAST,
};
if (!IS_ENABLED(CONFIG_SOC_SAMA5))
return;
at91_pm_modes_validate(modes, ARRAY_SIZE(modes));
at91_dt_ramc();
at91_pm_init(NULL);
}
void __init sama5d2_pm_init(void)
{
static const int modes[] __initconst = {
AT91_PM_STANDBY, AT91_PM_ULP0, AT91_PM_ULP0_FAST, AT91_PM_ULP1,
AT91_PM_BACKUP,
};
if (!IS_ENABLED(CONFIG_SOC_SAMA5D2))
return;
at91_pm_modes_validate(modes, ARRAY_SIZE(modes));
at91_pm_modes_init();
sama5_pm_init();
at91_dt_ramc();
at91_pm_init(NULL);
soc_pm.ws_ids = sama5d2_ws_ids;
soc_pm.config_shdwc_ws = at91_sama5d2_config_shdwc_ws;