summaryrefslogtreecommitdiffstats
path: root/kernel/arch/arm/mach-at91/pm.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/arch/arm/mach-at91/pm.c')
-rw-r--r--kernel/arch/arm/mach-at91/pm.c89
1 files changed, 71 insertions, 18 deletions
diff --git a/kernel/arch/arm/mach-at91/pm.c b/kernel/arch/arm/mach-at91/pm.c
index 5062699cb..f06270198 100644
--- a/kernel/arch/arm/mach-at91/pm.c
+++ b/kernel/arch/arm/mach-at91/pm.c
@@ -31,18 +31,23 @@
#include <asm/mach/irq.h>
#include <asm/fncpy.h>
#include <asm/cacheflush.h>
+#include <asm/system_misc.h>
#include "generic.h"
#include "pm.h"
+static void __iomem *pmc;
+
/*
* FIXME: this is needed to communicate between the pinctrl driver and
* the PM implementation in the machine. Possibly part of the PM
* implementation should be moved down into the pinctrl driver and get
* called as part of the generic suspend/resume path.
*/
+#ifdef CONFIG_PINCTRL_AT91
extern void at91_pinctrl_gpio_suspend(void);
extern void at91_pinctrl_gpio_resume(void);
+#endif
static struct {
unsigned long uhp_udp_mask;
@@ -85,7 +90,7 @@ static int at91_pm_verify_clocks(void)
unsigned long scsr;
int i;
- scsr = at91_pmc_read(AT91_PMC_SCSR);
+ scsr = readl(pmc + AT91_PMC_SCSR);
/* USB must not be using PLLB */
if ((scsr & at91_pm_data.uhp_udp_mask) != 0) {
@@ -99,8 +104,7 @@ static int at91_pm_verify_clocks(void)
if ((scsr & (AT91_PMC_PCK0 << i)) == 0)
continue;
-
- css = at91_pmc_read(AT91_PMC_PCKR(i)) & AT91_PMC_CSS;
+ css = readl(pmc + AT91_PMC_PCKR(i)) & AT91_PMC_CSS;
if (css != AT91_PMC_CSS_SLOW) {
pr_err("AT91: PM - Suspend-to-RAM with PCK%d src %d\n", i, css);
return 0;
@@ -143,16 +147,17 @@ static void at91_pm_suspend(suspend_state_t state)
flush_cache_all();
outer_disable();
- at91_suspend_sram_fn(at91_pmc_base, at91_ramc_base[0],
- at91_ramc_base[1], pm_data);
+ at91_suspend_sram_fn(pmc, at91_ramc_base[0],
+ at91_ramc_base[1], pm_data);
outer_resume();
}
static int at91_pm_enter(suspend_state_t state)
{
+#ifdef CONFIG_PINCTRL_AT91
at91_pinctrl_gpio_suspend();
-
+#endif
switch (state) {
/*
* Suspend-to-RAM is like STANDBY plus slow clock mode, so
@@ -192,7 +197,9 @@ static int at91_pm_enter(suspend_state_t state)
error:
target_state = PM_SUSPEND_ON;
+#ifdef CONFIG_PINCTRL_AT91
at91_pinctrl_gpio_resume();
+#endif
return 0;
}
@@ -233,7 +240,7 @@ static void at91_pm_set_standby(void (*at91_standby)(void))
*/
static void at91rm9200_standby(void)
{
- u32 lpr = at91_ramc_read(0, AT91RM9200_SDRAMC_LPR);
+ u32 lpr = at91_ramc_read(0, AT91_MC_SDRAMC_LPR);
asm volatile(
"b 1f\n\t"
@@ -244,8 +251,8 @@ static void at91rm9200_standby(void)
" mcr p15, 0, %0, c7, c0, 4\n\t"
" str %5, [%1, %2]"
:
- : "r" (0), "r" (at91_ramc_base[0]), "r" (AT91RM9200_SDRAMC_LPR),
- "r" (1), "r" (AT91RM9200_SDRAMC_SRR),
+ : "r" (0), "r" (at91_ramc_base[0]), "r" (AT91_MC_SDRAMC_LPR),
+ "r" (1), "r" (AT91_MC_SDRAMC_SRR),
"r" (lpr));
}
@@ -311,7 +318,7 @@ static void at91sam9_sdram_standby(void)
at91_ramc_write(1, AT91_SDRAMC_LPR, saved_lpr1);
}
-static const struct of_device_id ramc_ids[] __initconst = {
+static const struct of_device_id const ramc_ids[] __initconst = {
{ .compatible = "atmel,at91rm9200-sdramc", .data = at91rm9200_standby },
{ .compatible = "atmel,at91sam9260-sdramc", .data = at91sam9_sdram_standby },
{ .compatible = "atmel,at91sam9g45-ddramc", .data = at91_ddr_standby },
@@ -348,6 +355,21 @@ static __init void at91_dt_ramc(void)
at91_pm_set_standby(standby);
}
+void at91rm9200_idle(void)
+{
+ /*
+ * Disable the processor clock. The processor will be automatically
+ * re-enabled by an interrupt or by a reset.
+ */
+ writel(AT91_PMC_PCK, pmc + AT91_PMC_SCDR);
+}
+
+void at91sam9_idle(void)
+{
+ writel(AT91_PMC_PCK, pmc + AT91_PMC_SCDR);
+ cpu_do_idle();
+}
+
static void __init at91_pm_sram_init(void)
{
struct gen_pool *sram_pool;
@@ -369,7 +391,7 @@ static void __init at91_pm_sram_init(void)
return;
}
- sram_pool = dev_get_gen_pool(&pdev->dev);
+ sram_pool = gen_pool_get(&pdev->dev, NULL);
if (!sram_pool) {
pr_warn("%s: sram pool unavailable!\n", __func__);
return;
@@ -394,13 +416,36 @@ static void __init at91_pm_sram_init(void)
&at91_pm_suspend_in_sram, at91_pm_suspend_in_sram_sz);
}
-static void __init at91_pm_init(void)
+static const struct of_device_id atmel_pmc_ids[] __initconst = {
+ { .compatible = "atmel,at91rm9200-pmc" },
+ { .compatible = "atmel,at91sam9260-pmc" },
+ { .compatible = "atmel,at91sam9g45-pmc" },
+ { .compatible = "atmel,at91sam9n12-pmc" },
+ { .compatible = "atmel,at91sam9x5-pmc" },
+ { .compatible = "atmel,sama5d3-pmc" },
+ { .compatible = "atmel,sama5d2-pmc" },
+ { /* sentinel */ },
+};
+
+static void __init at91_pm_init(void (*pm_idle)(void))
{
- at91_pm_sram_init();
+ struct device_node *pmc_np;
if (at91_cpuidle_device.dev.platform_data)
platform_device_register(&at91_cpuidle_device);
+ pmc_np = of_find_matching_node(NULL, atmel_pmc_ids);
+ pmc = of_iomap(pmc_np, 0);
+ if (!pmc) {
+ pr_err("AT91: PM not supported, PMC not found\n");
+ return;
+ }
+
+ if (pm_idle)
+ arm_pm_idle = pm_idle;
+
+ at91_pm_sram_init();
+
if (at91_suspend_sram_fn)
suspend_set_ops(&at91_pm_ops);
else
@@ -414,12 +459,12 @@ void __init at91rm9200_pm_init(void)
/*
* AT91RM9200 SDRAM low-power mode cannot be used with self-refresh.
*/
- at91_ramc_write(0, AT91RM9200_SDRAMC_LPR, 0);
+ at91_ramc_write(0, AT91_MC_SDRAMC_LPR, 0);
at91_pm_data.uhp_udp_mask = AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP;
at91_pm_data.memctrl = AT91_MEMCTRL_MC;
- at91_pm_init();
+ at91_pm_init(at91rm9200_idle);
}
void __init at91sam9260_pm_init(void)
@@ -427,7 +472,7 @@ void __init at91sam9260_pm_init(void)
at91_dt_ramc();
at91_pm_data.memctrl = AT91_MEMCTRL_SDRAMC;
at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
- return at91_pm_init();
+ at91_pm_init(at91sam9_idle);
}
void __init at91sam9g45_pm_init(void)
@@ -435,7 +480,7 @@ void __init at91sam9g45_pm_init(void)
at91_dt_ramc();
at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP;
at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
- return at91_pm_init();
+ at91_pm_init(at91sam9_idle);
}
void __init at91sam9x5_pm_init(void)
@@ -443,5 +488,13 @@ void __init at91sam9x5_pm_init(void)
at91_dt_ramc();
at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
- return at91_pm_init();
+ at91_pm_init(at91sam9_idle);
+}
+
+void __init sama5_pm_init(void)
+{
+ at91_dt_ramc();
+ at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
+ at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
+ at91_pm_init(NULL);
}