|
@@ -22,6 +22,7 @@
|
|
|
#include <asm/cacheflush.h>
|
|
|
#include <asm/fncpy.h>
|
|
|
#include <asm/system_misc.h>
|
|
|
+#include <asm/suspend.h>
|
|
|
|
|
|
#include "generic.h"
|
|
|
#include "pm.h"
|
|
@@ -58,6 +59,14 @@ static int at91_pm_valid_state(suspend_state_t state)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static int canary = 0xA5A5A5A5;
|
|
|
+
|
|
|
+static struct at91_pm_bu {
|
|
|
+ int suspended;
|
|
|
+ unsigned long reserved;
|
|
|
+ phys_addr_t canary;
|
|
|
+ phys_addr_t resume;
|
|
|
+} *pm_bu;
|
|
|
|
|
|
static suspend_state_t target_state;
|
|
|
|
|
@@ -123,15 +132,39 @@ static void (*at91_suspend_sram_fn)(struct at91_pm_data *);
|
|
|
extern void at91_pm_suspend_in_sram(struct at91_pm_data *pm_data);
|
|
|
extern u32 at91_pm_suspend_in_sram_sz;
|
|
|
|
|
|
-static void at91_pm_suspend(suspend_state_t state)
|
|
|
+static int at91_suspend_finish(unsigned long val)
|
|
|
{
|
|
|
- pm_data.mode = (state == PM_SUSPEND_MEM) ? AT91_PM_SLOW_CLOCK : 0;
|
|
|
-
|
|
|
flush_cache_all();
|
|
|
outer_disable();
|
|
|
|
|
|
at91_suspend_sram_fn(&pm_data);
|
|
|
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void at91_pm_suspend(suspend_state_t state)
|
|
|
+{
|
|
|
+ if (pm_data.deepest_state == AT91_PM_BACKUP)
|
|
|
+ if (state == PM_SUSPEND_MEM)
|
|
|
+ pm_data.mode = AT91_PM_BACKUP;
|
|
|
+ else
|
|
|
+ pm_data.mode = AT91_PM_SLOW_CLOCK;
|
|
|
+ else
|
|
|
+ pm_data.mode = (state == PM_SUSPEND_MEM) ? AT91_PM_SLOW_CLOCK : 0;
|
|
|
+
|
|
|
+ if (pm_data.mode == AT91_PM_BACKUP) {
|
|
|
+ pm_bu->suspended = 1;
|
|
|
+
|
|
|
+ cpu_suspend(0, at91_suspend_finish);
|
|
|
+
|
|
|
+ /* The SRAM is lost between suspend cycles */
|
|
|
+ at91_suspend_sram_fn = fncpy(at91_suspend_sram_fn,
|
|
|
+ &at91_pm_suspend_in_sram,
|
|
|
+ at91_pm_suspend_in_sram_sz);
|
|
|
+ } else {
|
|
|
+ at91_suspend_finish(0);
|
|
|
+ }
|
|
|
+
|
|
|
outer_resume();
|
|
|
}
|
|
|
|
|
@@ -436,6 +469,70 @@ static void __init at91_pm_sram_init(void)
|
|
|
&at91_pm_suspend_in_sram, at91_pm_suspend_in_sram_sz);
|
|
|
}
|
|
|
|
|
|
+static void __init at91_pm_backup_init(void)
|
|
|
+{
|
|
|
+ struct gen_pool *sram_pool;
|
|
|
+ struct device_node *np;
|
|
|
+ struct platform_device *pdev = NULL;
|
|
|
+
|
|
|
+ pm_bu = NULL;
|
|
|
+
|
|
|
+ np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-shdwc");
|
|
|
+ if (!np) {
|
|
|
+ pr_warn("%s: failed to find shdwc!\n", __func__);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ pm_data.shdwc = of_iomap(np, 0);
|
|
|
+ of_node_put(np);
|
|
|
+
|
|
|
+ np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-sfrbu");
|
|
|
+ if (!np) {
|
|
|
+ pr_warn("%s: failed to find sfrbu!\n", __func__);
|
|
|
+ goto sfrbu_fail;
|
|
|
+ }
|
|
|
+
|
|
|
+ pm_data.sfrbu = of_iomap(np, 0);
|
|
|
+ of_node_put(np);
|
|
|
+ pm_bu = NULL;
|
|
|
+
|
|
|
+ np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-securam");
|
|
|
+ if (!np)
|
|
|
+ goto securam_fail;
|
|
|
+
|
|
|
+ pdev = of_find_device_by_node(np);
|
|
|
+ of_node_put(np);
|
|
|
+ if (!pdev) {
|
|
|
+ pr_warn("%s: failed to find securam device!\n", __func__);
|
|
|
+ goto securam_fail;
|
|
|
+ }
|
|
|
+
|
|
|
+ sram_pool = gen_pool_get(&pdev->dev, NULL);
|
|
|
+ if (!sram_pool) {
|
|
|
+ pr_warn("%s: securam pool unavailable!\n", __func__);
|
|
|
+ goto securam_fail;
|
|
|
+ }
|
|
|
+
|
|
|
+ pm_bu = (void *)gen_pool_alloc(sram_pool, sizeof(struct at91_pm_bu));
|
|
|
+ if (!pm_bu) {
|
|
|
+ pr_warn("%s: unable to alloc securam!\n", __func__);
|
|
|
+ goto securam_fail;
|
|
|
+ }
|
|
|
+
|
|
|
+ pm_bu->suspended = 0;
|
|
|
+ pm_bu->canary = virt_to_phys(&canary);
|
|
|
+ pm_bu->resume = virt_to_phys(cpu_resume);
|
|
|
+
|
|
|
+ return;
|
|
|
+
|
|
|
+sfrbu_fail:
|
|
|
+ iounmap(pm_data.shdwc);
|
|
|
+ pm_data.shdwc = NULL;
|
|
|
+securam_fail:
|
|
|
+ iounmap(pm_data.sfrbu);
|
|
|
+ pm_data.sfrbu = NULL;
|
|
|
+}
|
|
|
+
|
|
|
struct pmc_info {
|
|
|
unsigned long uhp_udp_mask;
|
|
|
};
|
|
@@ -510,3 +607,9 @@ void __init sama5_pm_init(void)
|
|
|
at91_dt_ramc();
|
|
|
at91_pm_init(NULL);
|
|
|
}
|
|
|
+
|
|
|
+void __init sama5d2_pm_init(void)
|
|
|
+{
|
|
|
+ at91_pm_backup_init();
|
|
|
+ sama5_pm_init();
|
|
|
+}
|