From c3f5b8fde71f6ab15d4fd8921997d62ef98d803a Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 14 Feb 2019 15:54:31 +0000 Subject: ARM: at91: pm: introduce at91_soc_pm structure To have per SoC PM information add a new structure which embed a member of type struct at91_pm_data. This will allow easy addition of new information without contaminate struct at91_pm_data that is passed to the last phase suspend function (at91_suspend_sram_fn). Signed-off-by: Claudiu Beznea Signed-off-by: Alexandre Belloni Signed-off-by: Ludovic Desroches --- arch/arm/mach-at91/pm.c | 118 +++++++++++++++++++++++++----------------------- 1 file changed, 62 insertions(+), 56 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 51e808adb00c..ce2ff86968f6 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -39,6 +39,17 @@ extern void at91_pinctrl_gpio_suspend(void); extern void at91_pinctrl_gpio_resume(void); #endif +struct at91_soc_pm { + struct at91_pm_data data; +}; + +static struct at91_soc_pm soc_pm = { + .data = { + .standby_mode = AT91_PM_STANDBY, + .suspend_mode = AT91_PM_ULP0, + }, +}; + static const match_table_t pm_modes __initconst = { { AT91_PM_STANDBY, "standby" }, { AT91_PM_ULP0, "ulp0" }, @@ -47,16 +58,11 @@ static const match_table_t pm_modes __initconst = { { -1, NULL }, }; -static struct at91_pm_data pm_data = { - .standby_mode = AT91_PM_STANDBY, - .suspend_mode = AT91_PM_ULP0, -}; - #define at91_ramc_read(id, field) \ - __raw_readl(pm_data.ramc[id] + field) + __raw_readl(soc_pm.data.ramc[id] + field) #define at91_ramc_write(id, field, value) \ - __raw_writel(value, pm_data.ramc[id] + field) + __raw_writel(value, soc_pm.data.ramc[id] + field) static int at91_pm_valid_state(suspend_state_t state) { @@ -116,21 +122,21 @@ static int at91_pm_config_ws(unsigned int pm_mode, bool set) if (pm_mode != AT91_PM_ULP1) return 0; - if (!pm_data.pmc || !pm_data.shdwc) + if (!soc_pm.data.pmc || !soc_pm.data.shdwc) return -EPERM; if (!set) { - writel(mode, pm_data.pmc + AT91_PMC_FSMR); + writel(mode, soc_pm.data.pmc + AT91_PMC_FSMR); return 0; } /* SHDWC.WUIR */ - val = readl(pm_data.shdwc + 0x0c); + val = readl(soc_pm.data.shdwc + 0x0c); mode |= (val & 0x3ff); polarity |= ((val >> 16) & 0x3ff); /* SHDWC.MR */ - val = readl(pm_data.shdwc + 0x04); + val = readl(soc_pm.data.shdwc + 0x04); /* Loop through defined wakeup sources. */ for_each_matching_node_and_match(np, sama5d2_ws_ids, &match) { @@ -155,8 +161,8 @@ put_device: } if (mode) { - writel(mode, pm_data.pmc + AT91_PMC_FSMR); - writel(polarity, pm_data.pmc + AT91_PMC_FSPR); + writel(mode, soc_pm.data.pmc + AT91_PMC_FSMR); + writel(polarity, soc_pm.data.pmc + AT91_PMC_FSPR); } else { pr_err("AT91: PM: no ULP1 wakeup sources found!"); } @@ -171,18 +177,18 @@ static int at91_pm_begin(suspend_state_t state) { switch (state) { case PM_SUSPEND_MEM: - pm_data.mode = pm_data.suspend_mode; + soc_pm.data.mode = soc_pm.data.suspend_mode; break; case PM_SUSPEND_STANDBY: - pm_data.mode = pm_data.standby_mode; + soc_pm.data.mode = soc_pm.data.standby_mode; break; default: - pm_data.mode = -1; + soc_pm.data.mode = -1; } - return at91_pm_config_ws(pm_data.mode, true); + return at91_pm_config_ws(soc_pm.data.mode, true); } /* @@ -194,10 +200,10 @@ static int at91_pm_verify_clocks(void) unsigned long scsr; int i; - scsr = readl(pm_data.pmc + AT91_PMC_SCSR); + scsr = readl(soc_pm.data.pmc + AT91_PMC_SCSR); /* USB must not be using PLLB */ - if ((scsr & pm_data.uhp_udp_mask) != 0) { + if ((scsr & soc_pm.data.uhp_udp_mask) != 0) { pr_err("AT91: PM - Suspend-to-RAM with USB still active\n"); return 0; } @@ -208,7 +214,7 @@ static int at91_pm_verify_clocks(void) if ((scsr & (AT91_PMC_PCK0 << i)) == 0) continue; - css = readl(pm_data.pmc + AT91_PMC_PCKR(i)) & AT91_PMC_CSS; + css = readl(soc_pm.data.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; @@ -230,7 +236,7 @@ static int at91_pm_verify_clocks(void) */ int at91_suspend_entering_slow_clock(void) { - return (pm_data.mode >= AT91_PM_ULP0); + return (soc_pm.data.mode >= AT91_PM_ULP0); } EXPORT_SYMBOL(at91_suspend_entering_slow_clock); @@ -243,14 +249,14 @@ static int at91_suspend_finish(unsigned long val) flush_cache_all(); outer_disable(); - at91_suspend_sram_fn(&pm_data); + at91_suspend_sram_fn(&soc_pm.data); return 0; } static void at91_pm_suspend(suspend_state_t state) { - if (pm_data.mode == AT91_PM_BACKUP) { + if (soc_pm.data.mode == AT91_PM_BACKUP) { pm_bu->suspended = 1; cpu_suspend(0, at91_suspend_finish); @@ -289,7 +295,7 @@ static int at91_pm_enter(suspend_state_t state) /* * Ensure that clocks are in a valid state. */ - if (pm_data.mode >= AT91_PM_ULP0 && + if (soc_pm.data.mode >= AT91_PM_ULP0 && !at91_pm_verify_clocks()) goto error; @@ -318,7 +324,7 @@ error: */ static void at91_pm_end(void) { - at91_pm_config_ws(pm_data.mode, false); + at91_pm_config_ws(soc_pm.data.mode, false); } @@ -351,7 +357,7 @@ static void at91rm9200_standby(void) " str %2, [%1, %3]\n\t" " mcr p15, 0, %0, c7, c0, 4\n\t" : - : "r" (0), "r" (pm_data.ramc[0]), + : "r" (0), "r" (soc_pm.data.ramc[0]), "r" (1), "r" (AT91_MC_SDRAMC_SRR)); } @@ -374,7 +380,7 @@ static void at91_ddr_standby(void) at91_ramc_write(0, AT91_DDRSDRC_MDR, mdr); } - if (pm_data.ramc[1]) { + if (soc_pm.data.ramc[1]) { saved_lpr1 = at91_ramc_read(1, AT91_DDRSDRC_LPR); lpr1 = saved_lpr1 & ~AT91_DDRSDRC_LPCB; lpr1 |= AT91_DDRSDRC_LPCB_SELF_REFRESH; @@ -392,14 +398,14 @@ static void at91_ddr_standby(void) /* self-refresh mode now */ at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr0); - if (pm_data.ramc[1]) + if (soc_pm.data.ramc[1]) at91_ramc_write(1, AT91_DDRSDRC_LPR, lpr1); cpu_do_idle(); at91_ramc_write(0, AT91_DDRSDRC_MDR, saved_mdr0); at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0); - if (pm_data.ramc[1]) { + if (soc_pm.data.ramc[1]) { at91_ramc_write(0, AT91_DDRSDRC_MDR, saved_mdr1); at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1); } @@ -429,7 +435,7 @@ static void at91sam9_sdram_standby(void) u32 lpr0, lpr1 = 0; u32 saved_lpr0, saved_lpr1 = 0; - if (pm_data.ramc[1]) { + if (soc_pm.data.ramc[1]) { saved_lpr1 = at91_ramc_read(1, AT91_SDRAMC_LPR); lpr1 = saved_lpr1 & ~AT91_SDRAMC_LPCB; lpr1 |= AT91_SDRAMC_LPCB_SELF_REFRESH; @@ -441,13 +447,13 @@ static void at91sam9_sdram_standby(void) /* self-refresh mode now */ at91_ramc_write(0, AT91_SDRAMC_LPR, lpr0); - if (pm_data.ramc[1]) + if (soc_pm.data.ramc[1]) at91_ramc_write(1, AT91_SDRAMC_LPR, lpr1); cpu_do_idle(); at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr0); - if (pm_data.ramc[1]) + if (soc_pm.data.ramc[1]) at91_ramc_write(1, AT91_SDRAMC_LPR, saved_lpr1); } @@ -480,14 +486,14 @@ static __init void at91_dt_ramc(void) const struct ramc_info *ramc; for_each_matching_node_and_match(np, ramc_ids, &of_id) { - pm_data.ramc[idx] = of_iomap(np, 0); - if (!pm_data.ramc[idx]) + soc_pm.data.ramc[idx] = of_iomap(np, 0); + if (!soc_pm.data.ramc[idx]) panic(pr_fmt("unable to map ramc[%d] cpu registers\n"), idx); ramc = of_id->data; if (!standby) standby = ramc->idle; - pm_data.memctrl = ramc->memctrl; + soc_pm.data.memctrl = ramc->memctrl; idx++; } @@ -509,12 +515,12 @@ static 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, pm_data.pmc + AT91_PMC_SCDR); + writel(AT91_PMC_PCK, soc_pm.data.pmc + AT91_PMC_SCDR); } static void at91sam9_idle(void) { - writel(AT91_PMC_PCK, pm_data.pmc + AT91_PMC_SCDR); + writel(AT91_PMC_PCK, soc_pm.data.pmc + AT91_PMC_SCDR); cpu_do_idle(); } @@ -566,8 +572,8 @@ static void __init at91_pm_sram_init(void) static bool __init at91_is_pm_mode_active(int pm_mode) { - return (pm_data.standby_mode == pm_mode || - pm_data.suspend_mode == pm_mode); + return (soc_pm.data.standby_mode == pm_mode || + soc_pm.data.suspend_mode == pm_mode); } static int __init at91_pm_backup_init(void) @@ -586,7 +592,7 @@ static int __init at91_pm_backup_init(void) return ret; } - pm_data.sfrbu = of_iomap(np, 0); + soc_pm.data.sfrbu = of_iomap(np, 0); of_node_put(np); np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-securam"); @@ -620,8 +626,8 @@ static int __init at91_pm_backup_init(void) return 0; securam_fail: - iounmap(pm_data.sfrbu); - pm_data.sfrbu = NULL; + iounmap(soc_pm.data.sfrbu); + soc_pm.data.sfrbu = NULL; return ret; } @@ -630,10 +636,10 @@ static void __init at91_pm_use_default_mode(int pm_mode) if (pm_mode != AT91_PM_ULP1 && pm_mode != AT91_PM_BACKUP) return; - if (pm_data.standby_mode == pm_mode) - pm_data.standby_mode = AT91_PM_ULP0; - if (pm_data.suspend_mode == pm_mode) - pm_data.suspend_mode = AT91_PM_ULP0; + if (soc_pm.data.standby_mode == pm_mode) + soc_pm.data.standby_mode = AT91_PM_ULP0; + if (soc_pm.data.suspend_mode == pm_mode) + soc_pm.data.suspend_mode = AT91_PM_ULP0; } static void __init at91_pm_modes_init(void) @@ -651,7 +657,7 @@ static void __init at91_pm_modes_init(void) goto ulp1_default; } - pm_data.shdwc = of_iomap(np, 0); + soc_pm.data.shdwc = of_iomap(np, 0); of_node_put(np); ret = at91_pm_backup_init(); @@ -665,8 +671,8 @@ static void __init at91_pm_modes_init(void) return; unmap: - iounmap(pm_data.shdwc); - pm_data.shdwc = NULL; + iounmap(soc_pm.data.shdwc); + soc_pm.data.shdwc = NULL; ulp1_default: at91_pm_use_default_mode(AT91_PM_ULP1); backup_default: @@ -709,14 +715,14 @@ static void __init at91_pm_init(void (*pm_idle)(void)) platform_device_register(&at91_cpuidle_device); pmc_np = of_find_matching_node_and_match(NULL, atmel_pmc_ids, &of_id); - pm_data.pmc = of_iomap(pmc_np, 0); - if (!pm_data.pmc) { + soc_pm.data.pmc = of_iomap(pmc_np, 0); + if (!soc_pm.data.pmc) { pr_err("AT91: PM not supported, PMC not found\n"); return; } pmc = of_id->data; - pm_data.uhp_udp_mask = pmc->uhp_udp_mask; + soc_pm.data.uhp_udp_mask = pmc->uhp_udp_mask; if (pm_idle) arm_pm_idle = pm_idle; @@ -726,8 +732,8 @@ static void __init at91_pm_init(void (*pm_idle)(void)) if (at91_suspend_sram_fn) { suspend_set_ops(&at91_pm_ops); pr_info("AT91: PM: standby: %s, suspend: %s\n", - pm_modes[pm_data.standby_mode].pattern, - pm_modes[pm_data.suspend_mode].pattern); + pm_modes[soc_pm.data.standby_mode].pattern, + pm_modes[soc_pm.data.suspend_mode].pattern); } else { pr_info("AT91: PM not supported, due to no SRAM allocated\n"); } @@ -793,8 +799,8 @@ static int __init at91_pm_modes_select(char *str) if (suspend < 0) return 0; - pm_data.standby_mode = standby; - pm_data.suspend_mode = suspend; + soc_pm.data.standby_mode = standby; + soc_pm.data.suspend_mode = suspend; return 0; } -- cgit v1.2.3-59-g8ed1b From 01c7031cfa7308c2a6d46636bda2e51be6474cf4 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 14 Feb 2019 15:54:41 +0000 Subject: ARM: at91: pm: initial PM support for SAM9X60 Add initial PM support for SAM9X60. This include idle, WFI and ULP0. Signed-off-by: Claudiu Beznea Signed-off-by: Alexandre Belloni Signed-off-by: Ludovic Desroches --- arch/arm/mach-at91/at91sam9.c | 18 ++++++++++++++++++ arch/arm/mach-at91/generic.h | 2 ++ arch/arm/mach-at91/pm.c | 14 ++++++++++++++ 3 files changed, 34 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-at91/at91sam9.c b/arch/arm/mach-at91/at91sam9.c index 3dbdef4d3cbf..c12563b09656 100644 --- a/arch/arm/mach-at91/at91sam9.c +++ b/arch/arm/mach-at91/at91sam9.c @@ -32,3 +32,21 @@ DT_MACHINE_START(at91sam_dt, "Atmel AT91SAM9") .init_machine = at91sam9_init, .dt_compat = at91_dt_board_compat, MACHINE_END + +static void __init sam9x60_init(void) +{ + of_platform_default_populate(NULL, NULL, NULL); + + sam9x60_pm_init(); +} + +static const char *const sam9x60_dt_board_compat[] __initconst = { + "microchip,sam9x60", + NULL +}; + +DT_MACHINE_START(sam9x60_dt, "Microchip SAM9X60") + /* Maintainer: Microchip */ + .init_machine = sam9x60_init, + .dt_compat = sam9x60_dt_board_compat, +MACHINE_END diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h index e2bd17237964..72b45accfa0f 100644 --- a/arch/arm/mach-at91/generic.h +++ b/arch/arm/mach-at91/generic.h @@ -14,11 +14,13 @@ #ifdef CONFIG_PM extern void __init at91rm9200_pm_init(void); extern void __init at91sam9_pm_init(void); +extern void __init sam9x60_pm_init(void); extern void __init sama5_pm_init(void); extern void __init sama5d2_pm_init(void); #else static inline void __init at91rm9200_pm_init(void) { } static inline void __init at91sam9_pm_init(void) { } +static inline void __init sam9x60_pm_init(void) { } static inline void __init sama5_pm_init(void) { } static inline void __init sama5d2_pm_init(void) { } #endif diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index ce2ff86968f6..e42db02eafe4 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -518,6 +518,11 @@ static void at91rm9200_idle(void) writel(AT91_PMC_PCK, soc_pm.data.pmc + AT91_PMC_SCDR); } +static void at91sam9x60_idle(void) +{ + cpu_do_idle(); +} + static void at91sam9_idle(void) { writel(AT91_PMC_PCK, soc_pm.data.pmc + AT91_PMC_SCDR); @@ -754,6 +759,15 @@ void __init at91rm9200_pm_init(void) at91_pm_init(at91rm9200_idle); } +void __init sam9x60_pm_init(void) +{ + if (!IS_ENABLED(CONFIG_SOC_AT91SAM9)) + return; + + at91_dt_ramc(); + at91_pm_init(at91sam9x60_idle); +} + void __init at91sam9_pm_init(void) { if (!IS_ENABLED(CONFIG_SOC_AT91SAM9)) -- cgit v1.2.3-59-g8ed1b From 2fa86e5200a49b3f236a0835f3976c3148148206 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 14 Feb 2019 15:54:47 +0000 Subject: ARM: at91: pm: keep at91_pm_backup_init() only for SAMA5D2 SoCs In at91_pm_backup_init() return if it is not about SAMA5D2 SoCs. Signed-off-by: Claudiu Beznea Signed-off-by: Alexandre Belloni Signed-off-by: Ludovic Desroches --- arch/arm/mach-at91/pm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index e42db02eafe4..c83f78000ab3 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -588,6 +588,9 @@ static int __init at91_pm_backup_init(void) struct platform_device *pdev = NULL; int ret = -ENODEV; + if (!IS_ENABLED(CONFIG_SOC_SAMA5D2)) + return -EPERM; + if (!at91_is_pm_mode_active(AT91_PM_BACKUP)) return 0; -- cgit v1.2.3-59-g8ed1b From a958156dac936d336f6f56fd2de86e36bc868ff4 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 14 Feb 2019 15:54:51 +0000 Subject: ARM: at91: pm: add support for per SoC wakeup source configuration Add support for per SoC wakeup source configuration. In this way we could have per SoC wakeup sources, shutdown controller and power management controller configurations for ULP1 power management mode. Signed-off-by: Claudiu Beznea Signed-off-by: Alexandre Belloni Signed-off-by: Ludovic Desroches --- arch/arm/mach-at91/pm.c | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index c83f78000ab3..27264caa4ec6 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -40,6 +40,9 @@ extern void at91_pinctrl_gpio_resume(void); #endif struct at91_soc_pm { + int (*config_shdwc_ws)(void __iomem *shdwc, u32 *mode, u32 *polarity); + int (*config_pmc_ws)(void __iomem *pmc, u32 mode, u32 polarity); + const struct of_device_id *ws_ids; struct at91_pm_data data; }; @@ -122,7 +125,7 @@ static int at91_pm_config_ws(unsigned int pm_mode, bool set) if (pm_mode != AT91_PM_ULP1) return 0; - if (!soc_pm.data.pmc || !soc_pm.data.shdwc) + if (!soc_pm.data.pmc || !soc_pm.data.shdwc || !soc_pm.ws_ids) return -EPERM; if (!set) { @@ -130,16 +133,14 @@ static int at91_pm_config_ws(unsigned int pm_mode, bool set) return 0; } - /* SHDWC.WUIR */ - val = readl(soc_pm.data.shdwc + 0x0c); - mode |= (val & 0x3ff); - polarity |= ((val >> 16) & 0x3ff); + if (soc_pm.config_shdwc_ws) + soc_pm.config_shdwc_ws(soc_pm.data.shdwc, &mode, &polarity); /* SHDWC.MR */ val = readl(soc_pm.data.shdwc + 0x04); /* Loop through defined wakeup sources. */ - for_each_matching_node_and_match(np, sama5d2_ws_ids, &match) { + for_each_matching_node_and_match(np, soc_pm.ws_ids, &match) { pdev = of_find_device_by_node(np); if (!pdev) continue; @@ -161,8 +162,8 @@ put_device: } if (mode) { - writel(mode, soc_pm.data.pmc + AT91_PMC_FSMR); - writel(polarity, soc_pm.data.pmc + AT91_PMC_FSPR); + if (soc_pm.config_pmc_ws) + soc_pm.config_pmc_ws(soc_pm.data.pmc, mode, polarity); } else { pr_err("AT91: PM: no ULP1 wakeup sources found!"); } @@ -170,6 +171,27 @@ put_device: return mode ? 0 : -EPERM; } +static int at91_sama5d2_config_shdwc_ws(void __iomem *shdwc, u32 *mode, + u32 *polarity) +{ + u32 val; + + /* SHDWC.WUIR */ + val = readl(shdwc + 0x0c); + *mode |= (val & 0x3ff); + *polarity |= ((val >> 16) & 0x3ff); + + return 0; +} + +static int at91_sama5d2_config_pmc_ws(void __iomem *pmc, u32 mode, u32 polarity) +{ + writel(mode, pmc + AT91_PMC_FSMR); + writel(polarity, pmc + AT91_PMC_FSPR); + + return 0; +} + /* * Called after processes are frozen, but before we shutdown devices. */ @@ -796,6 +818,10 @@ void __init sama5d2_pm_init(void) at91_pm_modes_init(); sama5_pm_init(); + + soc_pm.ws_ids = sama5d2_ws_ids; + soc_pm.config_shdwc_ws = at91_sama5d2_config_shdwc_ws; + soc_pm.config_pmc_ws = at91_sama5d2_config_pmc_ws; } static int __init at91_pm_modes_select(char *str) -- cgit v1.2.3-59-g8ed1b From eaedc0d379da6d1157a4f274d186001d11615b2b Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 14 Feb 2019 15:54:57 +0000 Subject: ARM: at91: pm: add ULP1 support for SAM9X60 Add ULP1 support for SAM9X60. In pm_suspend.S enable RC oscillator in PMC if it is not enabled. At resume the state before suspend is restored. Signed-off-by: Claudiu Beznea Acked-by: Stephen Boyd Signed-off-by: Alexandre Belloni Signed-off-by: Ludovic Desroches --- arch/arm/mach-at91/pm.c | 24 ++++++++++++++++++++++++ arch/arm/mach-at91/pm_suspend.S | 41 ++++++++++++++++++++++++++++++++++++++++- include/linux/clk/at91_pmc.h | 1 + 3 files changed, 65 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 27264caa4ec6..5571658b3c46 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -100,6 +100,8 @@ static const struct wakeup_source_info ws_info[] = { { .pmc_fsmr_bit = AT91_PMC_RTCAL, .shdwc_mr_bit = BIT(17) }, { .pmc_fsmr_bit = AT91_PMC_USBAL }, { .pmc_fsmr_bit = AT91_PMC_SDMMC_CD }, + { .pmc_fsmr_bit = AT91_PMC_RTTAL }, + { .pmc_fsmr_bit = AT91_PMC_RXLP_MCE }, }; static const struct of_device_id sama5d2_ws_ids[] = { @@ -114,6 +116,17 @@ static const struct of_device_id sama5d2_ws_ids[] = { { /* sentinel */ } }; +static const struct of_device_id sam9x60_ws_ids[] = { + { .compatible = "atmel,at91sam9x5-rtc", .data = &ws_info[1] }, + { .compatible = "atmel,at91rm9200-ohci", .data = &ws_info[2] }, + { .compatible = "usb-ohci", .data = &ws_info[2] }, + { .compatible = "atmel,at91sam9g45-ehci", .data = &ws_info[2] }, + { .compatible = "usb-ehci", .data = &ws_info[2] }, + { .compatible = "atmel,at91sam9260-rtt", .data = &ws_info[4] }, + { .compatible = "cdns,sam9x60-macb", .data = &ws_info[5] }, + { /* sentinel */ } +}; + static int at91_pm_config_ws(unsigned int pm_mode, bool set) { const struct wakeup_source_info *wsi; @@ -192,6 +205,13 @@ static int at91_sama5d2_config_pmc_ws(void __iomem *pmc, u32 mode, u32 polarity) return 0; } +static int at91_sam9x60_config_pmc_ws(void __iomem *pmc, u32 mode, u32 polarity) +{ + writel(mode, pmc + AT91_PMC_FSMR); + + return 0; +} + /* * Called after processes are frozen, but before we shutdown devices. */ @@ -789,8 +809,12 @@ void __init sam9x60_pm_init(void) if (!IS_ENABLED(CONFIG_SOC_AT91SAM9)) return; + at91_pm_modes_init(); at91_dt_ramc(); at91_pm_init(at91sam9x60_idle); + + soc_pm.ws_ids = sam9x60_ws_ids; + soc_pm.config_pmc_ws = at91_sam9x60_config_pmc_ws; } void __init at91sam9_pm_init(void) diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S index bfe1c4d06901..8b18cad1dcf5 100644 --- a/arch/arm/mach-at91/pm_suspend.S +++ b/arch/arm/mach-at91/pm_suspend.S @@ -197,8 +197,26 @@ ENDPROC(at91_backup_mode) .macro at91_pm_ulp1_mode ldr pmc, .pmc_base - /* Switch the main clock source to 12-MHz RC oscillator */ + /* Save RC oscillator state and check if it is enabled. */ + ldr tmp1, [pmc, #AT91_PMC_SR] + str tmp1, .saved_osc_status + tst tmp1, #AT91_PMC_MOSCRCS + bne 2f + + /* Enable RC oscillator */ ldr tmp1, [pmc, #AT91_CKGR_MOR] + orr tmp1, tmp1, #AT91_PMC_MOSCRCEN + bic tmp1, tmp1, #AT91_PMC_KEY_MASK + orr tmp1, tmp1, #AT91_PMC_KEY + str tmp1, [pmc, #AT91_CKGR_MOR] + + /* Wait main RC stabilization */ +1: ldr tmp1, [pmc, #AT91_PMC_SR] + tst tmp1, #AT91_PMC_MOSCRCS + beq 1b + + /* Switch the main clock source to 12-MHz RC oscillator */ +2: ldr tmp1, [pmc, #AT91_CKGR_MOR] bic tmp1, tmp1, #AT91_PMC_MOSCSEL bic tmp1, tmp1, #AT91_PMC_KEY_MASK orr tmp1, tmp1, #AT91_PMC_KEY @@ -262,6 +280,25 @@ ENDPROC(at91_backup_mode) str tmp1, [pmc, #AT91_PMC_MCKR] wait_mckrdy + + /* Restore RC oscillator state */ + ldr tmp1, .saved_osc_status + tst tmp1, #AT91_PMC_MOSCRCS + bne 3f + + /* Disable RC oscillator */ + ldr tmp1, [pmc, #AT91_CKGR_MOR] + bic tmp1, tmp1, #AT91_PMC_MOSCRCEN + bic tmp1, tmp1, #AT91_PMC_KEY_MASK + orr tmp1, tmp1, #AT91_PMC_KEY + str tmp1, [pmc, #AT91_CKGR_MOR] + + /* Wait RC oscillator disable done */ +4: ldr tmp1, [pmc, #AT91_PMC_SR] + tst tmp1, #AT91_PMC_MOSCRCS + bne 4b + +3: .endm ENTRY(at91_ulp_mode) @@ -475,6 +512,8 @@ ENDPROC(at91_sramc_self_refresh) .word 0 .saved_sam9_mdr1: .word 0 +.saved_osc_status: + .word 0 ENTRY(at91_pm_suspend_in_sram_sz) .word .-at91_pm_suspend_in_sram diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h index 931ab05f771d..bd3a65c0bad3 100644 --- a/include/linux/clk/at91_pmc.h +++ b/include/linux/clk/at91_pmc.h @@ -159,6 +159,7 @@ #define AT91_PMC_FSMR 0x70 /* Fast Startup Mode Register */ #define AT91_PMC_FSTT(n) BIT(n) +#define AT91_PMC_RTTAL BIT(16) #define AT91_PMC_RTCAL BIT(17) /* RTC Alarm Enable */ #define AT91_PMC_USBAL BIT(18) /* USB Resume Enable */ #define AT91_PMC_SDMMC_CD BIT(19) /* SDMMC Card Detect Enable */ -- cgit v1.2.3-59-g8ed1b From bc0779bd8f1317faddf65385f7af1f1fe229f23b Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 14 Feb 2019 15:55:01 +0000 Subject: ARM: at91: pm: disable RC oscillator in ULP0 Disable RC oscillator in ULP0 as datasheet specifies. Signed-off-by: Claudiu Beznea Signed-off-by: Alexandre Belloni Signed-off-by: Ludovic Desroches --- arch/arm/mach-at91/pm_suspend.S | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S index 8b18cad1dcf5..5c33023f9129 100644 --- a/arch/arm/mach-at91/pm_suspend.S +++ b/arch/arm/mach-at91/pm_suspend.S @@ -178,11 +178,46 @@ ENDPROC(at91_backup_mode) orr tmp1, tmp1, #AT91_PMC_KEY str tmp1, [pmc, #AT91_CKGR_MOR] + /* Save RC oscillator state */ + ldr tmp1, [pmc, #AT91_PMC_SR] + str tmp1, .saved_osc_status + tst tmp1, #AT91_PMC_MOSCRCS + bne 1f + + /* Turn off RC oscillator */ + ldr tmp1, [pmc, #AT91_CKGR_MOR] + bic tmp1, tmp1, #AT91_PMC_MOSCRCEN + bic tmp1, tmp1, #AT91_PMC_KEY_MASK + orr tmp1, tmp1, #AT91_PMC_KEY + str tmp1, [pmc, #AT91_CKGR_MOR] + + /* Wait main RC disabled done */ +2: ldr tmp1, [pmc, #AT91_PMC_SR] + tst tmp1, #AT91_PMC_MOSCRCS + bne 2b + /* Wait for interrupt */ - at91_cpu_idle +1: at91_cpu_idle - /* Turn on the crystal oscillator */ + /* Restore RC oscillator state */ + ldr tmp1, .saved_osc_status + tst tmp1, #AT91_PMC_MOSCRCS + beq 4f + + /* Turn on RC oscillator */ ldr tmp1, [pmc, #AT91_CKGR_MOR] + orr tmp1, tmp1, #AT91_PMC_MOSCRCEN + bic tmp1, tmp1, #AT91_PMC_KEY_MASK + orr tmp1, tmp1, #AT91_PMC_KEY + str tmp1, [pmc, #AT91_CKGR_MOR] + + /* Wait main RC stabilization */ +3: ldr tmp1, [pmc, #AT91_PMC_SR] + tst tmp1, #AT91_PMC_MOSCRCS + beq 3b + + /* Turn on the crystal oscillator */ +4: ldr tmp1, [pmc, #AT91_CKGR_MOR] orr tmp1, tmp1, #AT91_PMC_MOSCEN orr tmp1, tmp1, #AT91_PMC_KEY str tmp1, [pmc, #AT91_CKGR_MOR] -- cgit v1.2.3-59-g8ed1b From 2725d70aa5138284ba2cebf0ef51dd23e0c9ea21 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 14 Feb 2019 15:55:06 +0000 Subject: ARM: at91: pm: do not disable/enable PLLA for ULP modes There is no need to disable/enable PLLA when switching to one of the ULP modes. The PLLA consumers should take care of this. Signed-off-by: Claudiu Beznea Signed-off-by: Alexandre Belloni Signed-off-by: Ludovic Desroches --- arch/arm/mach-at91/pm_suspend.S | 31 ------------------------------- 1 file changed, 31 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S index 5c33023f9129..77e29309cc6e 100644 --- a/arch/arm/mach-at91/pm_suspend.S +++ b/arch/arm/mach-at91/pm_suspend.S @@ -50,15 +50,6 @@ tmp2 .req r5 beq 1b .endm -/* - * Wait until PLLA has locked. - */ - .macro wait_pllalock -1: ldr tmp1, [pmc, #AT91_PMC_SR] - tst tmp1, #AT91_PMC_LOCKA - beq 1b - .endm - /* * Put the processor to enter the idle state */ @@ -351,14 +342,6 @@ ENTRY(at91_ulp_mode) wait_mckrdy - /* Save PLLA setting and disable it */ - ldr tmp1, [pmc, #AT91_CKGR_PLLAR] - str tmp1, .saved_pllar - - mov tmp1, #AT91_PMC_PLLCOUNT - orr tmp1, tmp1, #(1 << 29) /* bit 29 always set */ - str tmp1, [pmc, #AT91_CKGR_PLLAR] - ldr r0, .pm_mode cmp r0, #AT91_PM_ULP1 beq ulp1_mode @@ -373,18 +356,6 @@ ulp1_mode: ulp_exit: ldr pmc, .pmc_base - /* Restore PLLA setting */ - ldr tmp1, .saved_pllar - str tmp1, [pmc, #AT91_CKGR_PLLAR] - - tst tmp1, #(AT91_PMC_MUL & 0xff0000) - bne 3f - tst tmp1, #(AT91_PMC_MUL & ~0xff0000) - beq 4f -3: - wait_pllalock -4: - /* * Restore master clock setting */ @@ -537,8 +508,6 @@ ENDPROC(at91_sramc_self_refresh) .word 0 .saved_mckr: .word 0 -.saved_pllar: - .word 0 .saved_sam9_lpr: .word 0 .saved_sam9_lpr1: -- cgit v1.2.3-59-g8ed1b