summaryrefslogtreecommitdiff
path: root/arch/arm/mach-at91/pm.c
diff options
context:
space:
mode:
authorClaudiu Beznea <claudiu.beznea@microchip.com>2020-08-05 11:36:49 +0300
committerAlexandre Belloni <alexandre.belloni@bootlin.com>2020-08-17 11:18:17 +0200
commit39add36049c347dffcb2be872dd442c137625f17 (patch)
tree19141f5aeffb25cbd5af51527294d6e10ab0be28 /arch/arm/mach-at91/pm.c
parente70bfc2fa8fe1a95a522f9d1ccf24d3d9b81366a (diff)
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
Diffstat (limited to 'arch/arm/mach-at91/pm.c')
-rw-r--r--arch/arm/mach-at91/pm.c80
1 files changed, 79 insertions, 1 deletions
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index a6336af1f449..e9091ff5b0f5 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -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;