blob: d6cfe7c4bb00f7f6e6b1132b8f95370e86f30096 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Andrew Victor907d6de2006-06-20 19:30:19 +01002/*
Andrew Victor9d041262007-02-05 11:42:07 +01003 * arch/arm/mach-at91/pm.c
Andrew Victor907d6de2006-06-20 19:30:19 +01004 * AT91 Power Management
5 *
6 * Copyright (C) 2005 David Brownell
Andrew Victor907d6de2006-06-20 19:30:19 +01007 */
8
Alexandre Bellonid2e46792015-01-15 15:59:25 +01009#include <linux/genalloc.h>
Alexandre Belloni9824c442017-01-31 13:49:24 +010010#include <linux/io.h>
11#include <linux/of_address.h>
Alexandre Bellonif5598d32015-01-15 15:59:24 +010012#include <linux/of.h>
Claudiu Beznead2d47162021-04-15 13:50:05 +030013#include <linux/of_fdt.h>
Alexandre Bellonid2e46792015-01-15 15:59:25 +010014#include <linux/of_platform.h>
Alexandre Belloni7693e182017-04-26 16:31:03 +020015#include <linux/parser.h>
Alexandre Belloni9824c442017-01-31 13:49:24 +010016#include <linux/suspend.h>
17
Boris BREZILLON2edb90a2013-10-11 09:37:45 +020018#include <linux/clk/at91_pmc.h>
Philippe Mazenauer95701b12019-05-22 09:36:57 +000019#include <linux/platform_data/atmel.h>
Andrew Victor907d6de2006-06-20 19:30:19 +010020
Lee Jones41dbf4a2021-03-03 12:41:49 +000021#include <soc/at91/pm.h>
22
Wenyou Yang385acc02015-03-09 11:54:26 +080023#include <asm/cacheflush.h>
Alexandre Belloni9824c442017-01-31 13:49:24 +010024#include <asm/fncpy.h>
Alexandre Bellonifbc7edc2015-09-30 01:58:40 +020025#include <asm/system_misc.h>
Alexandre Belloni24a0f5c2016-09-27 12:29:50 +020026#include <asm/suspend.h>
Andrew Victor907d6de2006-06-20 19:30:19 +010027
Andrew Victor907d6de2006-06-20 19:30:19 +010028#include "generic.h"
Albin Tonnerre1ea60cf2009-11-01 18:40:50 +010029#include "pm.h"
Andrew Victor907d6de2006-06-20 19:30:19 +010030
Claudiu Beznead2d47162021-04-15 13:50:05 +030031#define BACKUP_DDR_PHY_CALIBRATION (9)
32
Claudiu Bezneaf19dd1d2021-04-15 13:49:47 +030033/**
34 * struct at91_pm_bu - AT91 power management backup unit data structure
35 * @suspended: true if suspended to backup mode
36 * @reserved: reserved
37 * @canary: canary data for memory checking after exit from backup mode
38 * @resume: resume API
Claudiu Beznead2d47162021-04-15 13:50:05 +030039 * @ddr_phy_calibration: DDR PHY calibration data: ZQ0CR0, first 8 words
40 * of the memory
Claudiu Bezneaf19dd1d2021-04-15 13:49:47 +030041 */
42struct at91_pm_bu {
43 int suspended;
44 unsigned long reserved;
45 phys_addr_t canary;
46 phys_addr_t resume;
Claudiu Beznead2d47162021-04-15 13:50:05 +030047 unsigned long ddr_phy_calibration[BACKUP_DDR_PHY_CALIBRATION];
Claudiu Bezneaf19dd1d2021-04-15 13:49:47 +030048};
49
Claudiu Beznea0a7a2442021-04-15 13:49:49 +030050/**
51 * struct at91_soc_pm - AT91 SoC power management data structure
52 * @config_shdwc_ws: wakeup sources configuration function for SHDWC
53 * @config_pmc_ws: wakeup srouces configuration function for PMC
54 * @ws_ids: wakup sources of_device_id array
55 * @data: PM data to be used on last phase of suspend
56 * @bu: backup unit mapped data (for backup mode)
Claudiu Beznead2d47162021-04-15 13:50:05 +030057 * @memcs: memory chip select
Claudiu Beznea0a7a2442021-04-15 13:49:49 +030058 */
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +000059struct at91_soc_pm {
Claudiu Bezneaa9581562019-02-14 15:54:51 +000060 int (*config_shdwc_ws)(void __iomem *shdwc, u32 *mode, u32 *polarity);
61 int (*config_pmc_ws)(void __iomem *pmc, u32 mode, u32 polarity);
62 const struct of_device_id *ws_ids;
Claudiu Bezneaf19dd1d2021-04-15 13:49:47 +030063 struct at91_pm_bu *bu;
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +000064 struct at91_pm_data data;
Claudiu Beznead2d47162021-04-15 13:50:05 +030065 void *memcs;
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +000066};
67
Claudiu Beznea404956f2021-04-15 13:49:50 +030068/**
69 * enum at91_pm_iomaps: IOs that needs to be mapped for different PM modes
70 * @AT91_PM_IOMAP_SHDWC: SHDWC controller
71 * @AT91_PM_IOMAP_SFRBU: SFRBU controller
72 */
73enum at91_pm_iomaps {
74 AT91_PM_IOMAP_SHDWC,
75 AT91_PM_IOMAP_SFRBU,
76};
77
78#define AT91_PM_IOMAP(name) BIT(AT91_PM_IOMAP_##name)
79
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +000080static struct at91_soc_pm soc_pm = {
81 .data = {
82 .standby_mode = AT91_PM_STANDBY,
83 .suspend_mode = AT91_PM_ULP0,
84 },
85};
86
Alexandre Belloni7693e182017-04-26 16:31:03 +020087static const match_table_t pm_modes __initconst = {
Claudiu Bezneae70bfc22020-08-05 11:36:48 +030088 { AT91_PM_STANDBY, "standby" },
89 { AT91_PM_ULP0, "ulp0" },
90 { AT91_PM_ULP0_FAST, "ulp0-fast" },
91 { AT91_PM_ULP1, "ulp1" },
92 { AT91_PM_BACKUP, "backup" },
Alexandre Belloni7693e182017-04-26 16:31:03 +020093 { -1, NULL },
94};
95
Alexandre Belloni4d767bc2017-01-31 14:08:47 +010096#define at91_ramc_read(id, field) \
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +000097 __raw_readl(soc_pm.data.ramc[id] + field)
Alexandre Belloni4d767bc2017-01-31 14:08:47 +010098
99#define at91_ramc_write(id, field, value) \
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000100 __raw_writel(value, soc_pm.data.ramc[id] + field)
Daniel Lezcano5ad945e2013-09-22 22:29:57 +0200101
Andrew Victor907d6de2006-06-20 19:30:19 +0100102static int at91_pm_valid_state(suspend_state_t state)
103{
104 switch (state) {
105 case PM_SUSPEND_ON:
106 case PM_SUSPEND_STANDBY:
107 case PM_SUSPEND_MEM:
108 return 1;
109
110 default:
111 return 0;
112 }
113}
114
Alexandre Belloni24a0f5c2016-09-27 12:29:50 +0200115static int canary = 0xA5A5A5A5;
Andrew Victor907d6de2006-06-20 19:30:19 +0100116
Claudiu Beznead7484f52018-07-17 14:06:24 +0300117struct wakeup_source_info {
118 unsigned int pmc_fsmr_bit;
119 unsigned int shdwc_mr_bit;
120 bool set_polarity;
121};
122
123static const struct wakeup_source_info ws_info[] = {
124 { .pmc_fsmr_bit = AT91_PMC_FSTT(10), .set_polarity = true },
125 { .pmc_fsmr_bit = AT91_PMC_RTCAL, .shdwc_mr_bit = BIT(17) },
126 { .pmc_fsmr_bit = AT91_PMC_USBAL },
127 { .pmc_fsmr_bit = AT91_PMC_SDMMC_CD },
Claudiu Bezneaeaedc0d2019-02-14 15:54:57 +0000128 { .pmc_fsmr_bit = AT91_PMC_RTTAL },
129 { .pmc_fsmr_bit = AT91_PMC_RXLP_MCE },
Claudiu Beznead7484f52018-07-17 14:06:24 +0300130};
131
132static const struct of_device_id sama5d2_ws_ids[] = {
133 { .compatible = "atmel,sama5d2-gem", .data = &ws_info[0] },
134 { .compatible = "atmel,at91rm9200-rtc", .data = &ws_info[1] },
135 { .compatible = "atmel,sama5d3-udc", .data = &ws_info[2] },
136 { .compatible = "atmel,at91rm9200-ohci", .data = &ws_info[2] },
137 { .compatible = "usb-ohci", .data = &ws_info[2] },
138 { .compatible = "atmel,at91sam9g45-ehci", .data = &ws_info[2] },
139 { .compatible = "usb-ehci", .data = &ws_info[2] },
140 { .compatible = "atmel,sama5d2-sdhci", .data = &ws_info[3] },
141 { /* sentinel */ }
142};
143
Claudiu Bezneaeaedc0d2019-02-14 15:54:57 +0000144static const struct of_device_id sam9x60_ws_ids[] = {
145 { .compatible = "atmel,at91sam9x5-rtc", .data = &ws_info[1] },
146 { .compatible = "atmel,at91rm9200-ohci", .data = &ws_info[2] },
147 { .compatible = "usb-ohci", .data = &ws_info[2] },
148 { .compatible = "atmel,at91sam9g45-ehci", .data = &ws_info[2] },
149 { .compatible = "usb-ehci", .data = &ws_info[2] },
150 { .compatible = "atmel,at91sam9260-rtt", .data = &ws_info[4] },
151 { .compatible = "cdns,sam9x60-macb", .data = &ws_info[5] },
152 { /* sentinel */ }
153};
154
Claudiu Beznea65013302021-04-15 13:50:09 +0300155static const struct of_device_id sama7g5_ws_ids[] = {
156 { .compatible = "atmel,at91sam9x5-rtc", .data = &ws_info[1] },
157 { .compatible = "microchip,sama7g5-ohci", .data = &ws_info[2] },
158 { .compatible = "usb-ohci", .data = &ws_info[2] },
159 { .compatible = "atmel,at91sam9g45-ehci", .data = &ws_info[2] },
160 { .compatible = "usb-ehci", .data = &ws_info[2] },
161 { .compatible = "microchip,sama7g5-sdhci", .data = &ws_info[3] },
162 { .compatible = "atmel,at91sam9260-rtt", .data = &ws_info[4] },
163 { /* sentinel */ }
164};
165
Claudiu Beznead7484f52018-07-17 14:06:24 +0300166static int at91_pm_config_ws(unsigned int pm_mode, bool set)
167{
168 const struct wakeup_source_info *wsi;
169 const struct of_device_id *match;
170 struct platform_device *pdev;
171 struct device_node *np;
172 unsigned int mode = 0, polarity = 0, val = 0;
173
174 if (pm_mode != AT91_PM_ULP1)
175 return 0;
176
Claudiu Bezneaa9581562019-02-14 15:54:51 +0000177 if (!soc_pm.data.pmc || !soc_pm.data.shdwc || !soc_pm.ws_ids)
Claudiu Beznead7484f52018-07-17 14:06:24 +0300178 return -EPERM;
179
180 if (!set) {
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000181 writel(mode, soc_pm.data.pmc + AT91_PMC_FSMR);
Claudiu Beznead7484f52018-07-17 14:06:24 +0300182 return 0;
183 }
184
Claudiu Bezneaa9581562019-02-14 15:54:51 +0000185 if (soc_pm.config_shdwc_ws)
186 soc_pm.config_shdwc_ws(soc_pm.data.shdwc, &mode, &polarity);
Claudiu Beznead7484f52018-07-17 14:06:24 +0300187
188 /* SHDWC.MR */
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000189 val = readl(soc_pm.data.shdwc + 0x04);
Claudiu Beznead7484f52018-07-17 14:06:24 +0300190
191 /* Loop through defined wakeup sources. */
Claudiu Bezneaa9581562019-02-14 15:54:51 +0000192 for_each_matching_node_and_match(np, soc_pm.ws_ids, &match) {
Claudiu Beznead7484f52018-07-17 14:06:24 +0300193 pdev = of_find_device_by_node(np);
194 if (!pdev)
195 continue;
196
197 if (device_may_wakeup(&pdev->dev)) {
198 wsi = match->data;
199
200 /* Check if enabled on SHDWC. */
201 if (wsi->shdwc_mr_bit && !(val & wsi->shdwc_mr_bit))
zhong jiang95590a62018-08-16 18:26:22 +0800202 goto put_device;
Claudiu Beznead7484f52018-07-17 14:06:24 +0300203
204 mode |= wsi->pmc_fsmr_bit;
205 if (wsi->set_polarity)
206 polarity |= wsi->pmc_fsmr_bit;
207 }
208
zhong jiang95590a62018-08-16 18:26:22 +0800209put_device:
210 put_device(&pdev->dev);
Claudiu Beznead7484f52018-07-17 14:06:24 +0300211 }
212
213 if (mode) {
Claudiu Bezneaa9581562019-02-14 15:54:51 +0000214 if (soc_pm.config_pmc_ws)
215 soc_pm.config_pmc_ws(soc_pm.data.pmc, mode, polarity);
Claudiu Beznead7484f52018-07-17 14:06:24 +0300216 } else {
217 pr_err("AT91: PM: no ULP1 wakeup sources found!");
218 }
219
220 return mode ? 0 : -EPERM;
221}
222
Claudiu Bezneaa9581562019-02-14 15:54:51 +0000223static int at91_sama5d2_config_shdwc_ws(void __iomem *shdwc, u32 *mode,
224 u32 *polarity)
225{
226 u32 val;
227
228 /* SHDWC.WUIR */
229 val = readl(shdwc + 0x0c);
230 *mode |= (val & 0x3ff);
231 *polarity |= ((val >> 16) & 0x3ff);
232
233 return 0;
234}
235
236static int at91_sama5d2_config_pmc_ws(void __iomem *pmc, u32 mode, u32 polarity)
237{
238 writel(mode, pmc + AT91_PMC_FSMR);
239 writel(polarity, pmc + AT91_PMC_FSPR);
240
241 return 0;
242}
243
Claudiu Bezneaeaedc0d2019-02-14 15:54:57 +0000244static int at91_sam9x60_config_pmc_ws(void __iomem *pmc, u32 mode, u32 polarity)
245{
246 writel(mode, pmc + AT91_PMC_FSMR);
247
248 return 0;
249}
250
Andrew Victor907d6de2006-06-20 19:30:19 +0100251/*
252 * Called after processes are frozen, but before we shutdown devices.
253 */
Rafael J. Wysockic697eec2008-01-08 00:04:17 +0100254static int at91_pm_begin(suspend_state_t state)
Andrew Victor907d6de2006-06-20 19:30:19 +0100255{
Claudiu Bezneafe4c09e2021-04-15 13:49:48 +0300256 int ret;
257
Alexandre Belloni7693e182017-04-26 16:31:03 +0200258 switch (state) {
259 case PM_SUSPEND_MEM:
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000260 soc_pm.data.mode = soc_pm.data.suspend_mode;
Alexandre Belloni7693e182017-04-26 16:31:03 +0200261 break;
262
263 case PM_SUSPEND_STANDBY:
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000264 soc_pm.data.mode = soc_pm.data.standby_mode;
Alexandre Belloni7693e182017-04-26 16:31:03 +0200265 break;
266
267 default:
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000268 soc_pm.data.mode = -1;
Alexandre Belloni7693e182017-04-26 16:31:03 +0200269 }
270
Claudiu Bezneafe4c09e2021-04-15 13:49:48 +0300271 ret = at91_pm_config_ws(soc_pm.data.mode, true);
272 if (ret)
273 return ret;
274
275 if (soc_pm.data.mode == AT91_PM_BACKUP)
276 soc_pm.bu->suspended = 1;
277 else if (soc_pm.bu)
278 soc_pm.bu->suspended = 0;
279
280 return 0;
Andrew Victor907d6de2006-06-20 19:30:19 +0100281}
282
283/*
284 * Verify that all the clocks are correct before entering
285 * slow-clock mode.
286 */
287static int at91_pm_verify_clocks(void)
288{
289 unsigned long scsr;
290 int i;
291
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000292 scsr = readl(soc_pm.data.pmc + AT91_PMC_SCSR);
Andrew Victor907d6de2006-06-20 19:30:19 +0100293
294 /* USB must not be using PLLB */
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000295 if ((scsr & soc_pm.data.uhp_udp_mask) != 0) {
Alexandre Bellonif5598d32015-01-15 15:59:24 +0100296 pr_err("AT91: PM - Suspend-to-RAM with USB still active\n");
297 return 0;
Andrew Victor907d6de2006-06-20 19:30:19 +0100298 }
299
Andrew Victor907d6de2006-06-20 19:30:19 +0100300 /* PCK0..PCK3 must be disabled, or configured to use clk32k */
301 for (i = 0; i < 4; i++) {
302 u32 css;
303
304 if ((scsr & (AT91_PMC_PCK0 << i)) == 0)
305 continue;
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000306 css = readl(soc_pm.data.pmc + AT91_PMC_PCKR(i)) & AT91_PMC_CSS;
Andrew Victor907d6de2006-06-20 19:30:19 +0100307 if (css != AT91_PMC_CSS_SLOW) {
Ryan Mallon7f96b1c2009-04-01 20:33:30 +0100308 pr_err("AT91: PM - Suspend-to-RAM with PCK%d src %d\n", i, css);
Andrew Victor907d6de2006-06-20 19:30:19 +0100309 return 0;
310 }
311 }
Andrew Victor907d6de2006-06-20 19:30:19 +0100312
313 return 1;
314}
315
316/*
317 * Call this from platform driver suspend() to see how deeply to suspend.
318 * For example, some controllers (like OHCI) need one of the PLL clocks
319 * in order to act as a wakeup source, and those are not available when
320 * going into slow clock mode.
321 *
322 * REVISIT: generalize as clk_will_be_available(clk)? Other platforms have
323 * the very same problem (but not using at91 main_clk), and it'd be better
324 * to add one generic API rather than lots of platform-specific ones.
325 */
326int at91_suspend_entering_slow_clock(void)
327{
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000328 return (soc_pm.data.mode >= AT91_PM_ULP0);
Andrew Victor907d6de2006-06-20 19:30:19 +0100329}
330EXPORT_SYMBOL(at91_suspend_entering_slow_clock);
331
Alexandre Belloni65cc1a52017-01-31 18:12:57 +0100332static void (*at91_suspend_sram_fn)(struct at91_pm_data *);
333extern void at91_pm_suspend_in_sram(struct at91_pm_data *pm_data);
Wenyou Yang5726a8b2015-03-09 11:51:09 +0800334extern u32 at91_pm_suspend_in_sram_sz;
Andrew Victorf5d0f452008-04-02 21:50:16 +0100335
Alexandre Belloni24a0f5c2016-09-27 12:29:50 +0200336static int at91_suspend_finish(unsigned long val)
Wenyou Yang23be4be2015-03-09 11:49:46 +0800337{
Claudiu Beznead2d47162021-04-15 13:50:05 +0300338 int i;
339
340 if (soc_pm.data.mode == AT91_PM_BACKUP && soc_pm.data.ramc_phy) {
341 /*
342 * The 1st 8 words of memory might get corrupted in the process
343 * of DDR PHY recalibration; it is saved here in securam and it
344 * will be restored later, after recalibration, by bootloader
345 */
346 for (i = 1; i < BACKUP_DDR_PHY_CALIBRATION; i++)
347 soc_pm.bu->ddr_phy_calibration[i] =
348 *((unsigned int *)soc_pm.memcs + (i - 1));
349 }
350
Wenyou Yang385acc02015-03-09 11:54:26 +0800351 flush_cache_all();
352 outer_disable();
353
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000354 at91_suspend_sram_fn(&soc_pm.data);
Wenyou Yang385acc02015-03-09 11:54:26 +0800355
Alexandre Belloni24a0f5c2016-09-27 12:29:50 +0200356 return 0;
357}
358
359static void at91_pm_suspend(suspend_state_t state)
360{
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000361 if (soc_pm.data.mode == AT91_PM_BACKUP) {
Alexandre Belloni24a0f5c2016-09-27 12:29:50 +0200362 cpu_suspend(0, at91_suspend_finish);
363
364 /* The SRAM is lost between suspend cycles */
365 at91_suspend_sram_fn = fncpy(at91_suspend_sram_fn,
366 &at91_pm_suspend_in_sram,
367 at91_pm_suspend_in_sram_sz);
368 } else {
369 at91_suspend_finish(0);
370 }
371
Wenyou Yang385acc02015-03-09 11:54:26 +0800372 outer_resume();
Wenyou Yang23be4be2015-03-09 11:49:46 +0800373}
374
Alexandre Belloni7693e182017-04-26 16:31:03 +0200375/*
376 * STANDBY mode has *all* drivers suspended; ignores irqs not marked as 'wakeup'
377 * event sources; and reduces DRAM power. But otherwise it's identical to
378 * PM_SUSPEND_ON: cpu idle, and nothing fancy done with main or cpu clocks.
379 *
Claudiu Beznea514e2a22018-07-17 11:26:54 +0300380 * AT91_PM_ULP0 is like STANDBY plus slow clock mode, so drivers must
Alexandre Belloni7693e182017-04-26 16:31:03 +0200381 * suspend more deeply, the master clock switches to the clk32k and turns off
382 * the main oscillator
383 *
384 * AT91_PM_BACKUP turns off the whole SoC after placing the DDR in self refresh
385 */
Andrew Victor907d6de2006-06-20 19:30:19 +0100386static int at91_pm_enter(suspend_state_t state)
387{
Ludovic Desroches84235362015-12-01 11:44:40 +0100388#ifdef CONFIG_PINCTRL_AT91
Lee Jones41dbf4a2021-03-03 12:41:49 +0000389 /*
390 * FIXME: this is needed to communicate between the pinctrl driver and
391 * the PM implementation in the machine. Possibly part of the PM
392 * implementation should be moved down into the pinctrl driver and get
393 * called as part of the generic suspend/resume path.
394 */
Arnd Bergmann85c4b312014-12-02 12:08:27 +0100395 at91_pinctrl_gpio_suspend();
Ludovic Desroches84235362015-12-01 11:44:40 +0100396#endif
Alexandre Belloni7693e182017-04-26 16:31:03 +0200397
Andrew Victor907d6de2006-06-20 19:30:19 +0100398 switch (state) {
Wenyou Yang23be4be2015-03-09 11:49:46 +0800399 case PM_SUSPEND_MEM:
Alexandre Belloni7693e182017-04-26 16:31:03 +0200400 case PM_SUSPEND_STANDBY:
Andrew Victor907d6de2006-06-20 19:30:19 +0100401 /*
Wenyou Yang23be4be2015-03-09 11:49:46 +0800402 * Ensure that clocks are in a valid state.
Andrew Victor907d6de2006-06-20 19:30:19 +0100403 */
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000404 if (soc_pm.data.mode >= AT91_PM_ULP0 &&
Alexandre Belloni7693e182017-04-26 16:31:03 +0200405 !at91_pm_verify_clocks())
Andrew Victor907d6de2006-06-20 19:30:19 +0100406 goto error;
Wenyou Yang23be4be2015-03-09 11:49:46 +0800407
408 at91_pm_suspend(state);
409
410 break;
411
Wenyou Yang23be4be2015-03-09 11:49:46 +0800412 case PM_SUSPEND_ON:
413 cpu_do_idle();
414 break;
415
416 default:
417 pr_debug("AT91: PM - bogus suspend state %d\n", state);
418 goto error;
Andrew Victor907d6de2006-06-20 19:30:19 +0100419 }
420
Andrew Victor907d6de2006-06-20 19:30:19 +0100421error:
Ludovic Desroches84235362015-12-01 11:44:40 +0100422#ifdef CONFIG_PINCTRL_AT91
Arnd Bergmann85c4b312014-12-02 12:08:27 +0100423 at91_pinctrl_gpio_resume();
Ludovic Desroches84235362015-12-01 11:44:40 +0100424#endif
Andrew Victor907d6de2006-06-20 19:30:19 +0100425 return 0;
426}
427
Rafael J. Wysockic697eec2008-01-08 00:04:17 +0100428/*
429 * Called right prior to thawing processes.
430 */
431static void at91_pm_end(void)
432{
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000433 at91_pm_config_ws(soc_pm.data.mode, false);
Rafael J. Wysockic697eec2008-01-08 00:04:17 +0100434}
435
Andrew Victor907d6de2006-06-20 19:30:19 +0100436
Lionel Debroux2f55ac02010-11-16 14:14:02 +0100437static const struct platform_suspend_ops at91_pm_ops = {
Rafael J. Wysockic697eec2008-01-08 00:04:17 +0100438 .valid = at91_pm_valid_state,
439 .begin = at91_pm_begin,
440 .enter = at91_pm_enter,
441 .end = at91_pm_end,
Andrew Victor907d6de2006-06-20 19:30:19 +0100442};
443
Daniel Lezcano5ad945e2013-09-22 22:29:57 +0200444static struct platform_device at91_cpuidle_device = {
445 .name = "cpuidle-at91",
446};
447
Alexandre Bellonia18d0692015-03-16 23:44:37 +0100448/*
449 * The AT91RM9200 goes into self-refresh mode with this command, and will
450 * terminate self-refresh automatically on the next SDRAM access.
451 *
452 * Self-refresh mode is exited as soon as a memory access is made, but we don't
453 * know for sure when that happens. However, we need to restore the low-power
454 * mode if it was enabled before going idle. Restoring low-power mode while
455 * still in self-refresh is "not recommended", but seems to work.
456 */
457static void at91rm9200_standby(void)
458{
Alexandre Bellonia18d0692015-03-16 23:44:37 +0100459 asm volatile(
460 "b 1f\n\t"
461 ".align 5\n\t"
462 "1: mcr p15, 0, %0, c7, c10, 4\n\t"
Alexandre Belloni5a2d4f02017-02-01 21:32:43 +0100463 " str %2, [%1, %3]\n\t"
Alexandre Bellonia18d0692015-03-16 23:44:37 +0100464 " mcr p15, 0, %0, c7, c0, 4\n\t"
Alexandre Bellonia18d0692015-03-16 23:44:37 +0100465 :
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000466 : "r" (0), "r" (soc_pm.data.ramc[0]),
Alexandre Belloni5a2d4f02017-02-01 21:32:43 +0100467 "r" (1), "r" (AT91_MC_SDRAMC_SRR));
Alexandre Bellonia18d0692015-03-16 23:44:37 +0100468}
469
470/* We manage both DDRAM/SDRAM controllers, we need more than one value to
471 * remember.
472 */
473static void at91_ddr_standby(void)
474{
475 /* Those two values allow us to delay self-refresh activation
476 * to the maximum. */
477 u32 lpr0, lpr1 = 0;
Alexandre Belloni56387632017-02-01 22:10:34 +0100478 u32 mdr, saved_mdr0, saved_mdr1 = 0;
Alexandre Bellonia18d0692015-03-16 23:44:37 +0100479 u32 saved_lpr0, saved_lpr1 = 0;
480
Alexandre Belloni56387632017-02-01 22:10:34 +0100481 /* LPDDR1 --> force DDR2 mode during self-refresh */
482 saved_mdr0 = at91_ramc_read(0, AT91_DDRSDRC_MDR);
483 if ((saved_mdr0 & AT91_DDRSDRC_MD) == AT91_DDRSDRC_MD_LOW_POWER_DDR) {
484 mdr = saved_mdr0 & ~AT91_DDRSDRC_MD;
485 mdr |= AT91_DDRSDRC_MD_DDR2;
486 at91_ramc_write(0, AT91_DDRSDRC_MDR, mdr);
487 }
488
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000489 if (soc_pm.data.ramc[1]) {
Alexandre Bellonia18d0692015-03-16 23:44:37 +0100490 saved_lpr1 = at91_ramc_read(1, AT91_DDRSDRC_LPR);
491 lpr1 = saved_lpr1 & ~AT91_DDRSDRC_LPCB;
492 lpr1 |= AT91_DDRSDRC_LPCB_SELF_REFRESH;
Alexandre Belloni56387632017-02-01 22:10:34 +0100493 saved_mdr1 = at91_ramc_read(1, AT91_DDRSDRC_MDR);
494 if ((saved_mdr1 & AT91_DDRSDRC_MD) == AT91_DDRSDRC_MD_LOW_POWER_DDR) {
495 mdr = saved_mdr1 & ~AT91_DDRSDRC_MD;
496 mdr |= AT91_DDRSDRC_MD_DDR2;
497 at91_ramc_write(1, AT91_DDRSDRC_MDR, mdr);
498 }
Alexandre Bellonia18d0692015-03-16 23:44:37 +0100499 }
500
501 saved_lpr0 = at91_ramc_read(0, AT91_DDRSDRC_LPR);
502 lpr0 = saved_lpr0 & ~AT91_DDRSDRC_LPCB;
503 lpr0 |= AT91_DDRSDRC_LPCB_SELF_REFRESH;
504
505 /* self-refresh mode now */
506 at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr0);
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000507 if (soc_pm.data.ramc[1])
Alexandre Bellonia18d0692015-03-16 23:44:37 +0100508 at91_ramc_write(1, AT91_DDRSDRC_LPR, lpr1);
509
510 cpu_do_idle();
511
Alexandre Belloni56387632017-02-01 22:10:34 +0100512 at91_ramc_write(0, AT91_DDRSDRC_MDR, saved_mdr0);
Alexandre Bellonia18d0692015-03-16 23:44:37 +0100513 at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0);
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000514 if (soc_pm.data.ramc[1]) {
Alexandre Belloni56387632017-02-01 22:10:34 +0100515 at91_ramc_write(0, AT91_DDRSDRC_MDR, saved_mdr1);
Alexandre Bellonia18d0692015-03-16 23:44:37 +0100516 at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1);
Alexandre Belloni56387632017-02-01 22:10:34 +0100517 }
Alexandre Bellonia18d0692015-03-16 23:44:37 +0100518}
519
Nicolas Ferre60b89f12017-03-14 09:38:04 +0100520static void sama5d3_ddr_standby(void)
521{
522 u32 lpr0;
523 u32 saved_lpr0;
524
525 saved_lpr0 = at91_ramc_read(0, AT91_DDRSDRC_LPR);
526 lpr0 = saved_lpr0 & ~AT91_DDRSDRC_LPCB;
527 lpr0 |= AT91_DDRSDRC_LPCB_POWER_DOWN;
528
529 at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr0);
530
531 cpu_do_idle();
532
533 at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0);
534}
535
Alexandre Bellonia18d0692015-03-16 23:44:37 +0100536/* We manage both DDRAM/SDRAM controllers, we need more than one value to
537 * remember.
538 */
539static void at91sam9_sdram_standby(void)
540{
541 u32 lpr0, lpr1 = 0;
542 u32 saved_lpr0, saved_lpr1 = 0;
543
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000544 if (soc_pm.data.ramc[1]) {
Alexandre Bellonia18d0692015-03-16 23:44:37 +0100545 saved_lpr1 = at91_ramc_read(1, AT91_SDRAMC_LPR);
546 lpr1 = saved_lpr1 & ~AT91_SDRAMC_LPCB;
547 lpr1 |= AT91_SDRAMC_LPCB_SELF_REFRESH;
548 }
549
550 saved_lpr0 = at91_ramc_read(0, AT91_SDRAMC_LPR);
551 lpr0 = saved_lpr0 & ~AT91_SDRAMC_LPCB;
552 lpr0 |= AT91_SDRAMC_LPCB_SELF_REFRESH;
553
554 /* self-refresh mode now */
555 at91_ramc_write(0, AT91_SDRAMC_LPR, lpr0);
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000556 if (soc_pm.data.ramc[1])
Alexandre Bellonia18d0692015-03-16 23:44:37 +0100557 at91_ramc_write(1, AT91_SDRAMC_LPR, lpr1);
558
559 cpu_do_idle();
560
561 at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr0);
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000562 if (soc_pm.data.ramc[1])
Alexandre Bellonia18d0692015-03-16 23:44:37 +0100563 at91_ramc_write(1, AT91_SDRAMC_LPR, saved_lpr1);
564}
565
Alexandre Belloniaab02d612017-02-01 22:41:50 +0100566struct ramc_info {
567 void (*idle)(void);
568 unsigned int memctrl;
569};
570
571static const struct ramc_info ramc_infos[] __initconst = {
572 { .idle = at91rm9200_standby, .memctrl = AT91_MEMCTRL_MC},
573 { .idle = at91sam9_sdram_standby, .memctrl = AT91_MEMCTRL_SDRAMC},
574 { .idle = at91_ddr_standby, .memctrl = AT91_MEMCTRL_DDRSDR},
575 { .idle = sama5d3_ddr_standby, .memctrl = AT91_MEMCTRL_DDRSDR},
576};
577
Arnd Bergmann05278732017-05-11 13:50:16 +0200578static const struct of_device_id ramc_ids[] __initconst = {
Alexandre Belloniaab02d612017-02-01 22:41:50 +0100579 { .compatible = "atmel,at91rm9200-sdramc", .data = &ramc_infos[0] },
580 { .compatible = "atmel,at91sam9260-sdramc", .data = &ramc_infos[1] },
581 { .compatible = "atmel,at91sam9g45-ddramc", .data = &ramc_infos[2] },
582 { .compatible = "atmel,sama5d3-ddramc", .data = &ramc_infos[3] },
Claudiu Beznea2c26cb42021-04-15 13:50:03 +0300583 { .compatible = "microchip,sama7g5-uddrc", },
Alexandre Belloni827de1f2015-01-27 17:38:46 +0100584 { /*sentinel*/ }
585};
586
Claudiu Beznea892e1f42021-04-15 13:50:04 +0300587static const struct of_device_id ramc_phy_ids[] __initconst = {
588 { .compatible = "microchip,sama7g5-ddr3phy", },
589 { /* Sentinel. */ },
590};
591
592static __init void at91_dt_ramc(bool phy_mandatory)
Alexandre Belloni827de1f2015-01-27 17:38:46 +0100593{
594 struct device_node *np;
595 const struct of_device_id *of_id;
596 int idx = 0;
Alexandre Bellonie56d75a2017-02-01 23:55:10 +0100597 void *standby = NULL;
Alexandre Belloniaab02d612017-02-01 22:41:50 +0100598 const struct ramc_info *ramc;
Alexandre Belloni827de1f2015-01-27 17:38:46 +0100599
600 for_each_matching_node_and_match(np, ramc_ids, &of_id) {
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000601 soc_pm.data.ramc[idx] = of_iomap(np, 0);
602 if (!soc_pm.data.ramc[idx])
Alexandre Belloni827de1f2015-01-27 17:38:46 +0100603 panic(pr_fmt("unable to map ramc[%d] cpu registers\n"), idx);
604
Alexandre Belloniaab02d612017-02-01 22:41:50 +0100605 ramc = of_id->data;
Claudiu Beznea2c26cb42021-04-15 13:50:03 +0300606 if (ramc) {
607 if (!standby)
608 standby = ramc->idle;
609 soc_pm.data.memctrl = ramc->memctrl;
610 }
Alexandre Belloni827de1f2015-01-27 17:38:46 +0100611
612 idx++;
613 }
614
615 if (!idx)
616 panic(pr_fmt("unable to find compatible ram controller node in dtb\n"));
617
Claudiu Beznea892e1f42021-04-15 13:50:04 +0300618 /* Lookup for DDR PHY node, if any. */
619 for_each_matching_node_and_match(np, ramc_phy_ids, &of_id) {
620 soc_pm.data.ramc_phy = of_iomap(np, 0);
621 if (!soc_pm.data.ramc_phy)
622 panic(pr_fmt("unable to map ramc phy cpu registers\n"));
623 }
624
625 if (phy_mandatory && !soc_pm.data.ramc_phy)
626 panic(pr_fmt("DDR PHY is mandatory!\n"));
627
Alexandre Belloni827de1f2015-01-27 17:38:46 +0100628 if (!standby) {
629 pr_warn("ramc no standby function available\n");
630 return;
631 }
632
Alexandre Bellonie56d75a2017-02-01 23:55:10 +0100633 at91_cpuidle_device.dev.platform_data = standby;
Alexandre Belloni827de1f2015-01-27 17:38:46 +0100634}
635
Ben Dooksab6778e2016-06-17 16:34:18 +0100636static void at91rm9200_idle(void)
Alexandre Bellonifbc7edc2015-09-30 01:58:40 +0200637{
638 /*
639 * Disable the processor clock. The processor will be automatically
640 * re-enabled by an interrupt or by a reset.
641 */
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000642 writel(AT91_PMC_PCK, soc_pm.data.pmc + AT91_PMC_SCDR);
Alexandre Bellonifbc7edc2015-09-30 01:58:40 +0200643}
644
Ben Dooksab6778e2016-06-17 16:34:18 +0100645static void at91sam9_idle(void)
Alexandre Bellonifbc7edc2015-09-30 01:58:40 +0200646{
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000647 writel(AT91_PMC_PCK, soc_pm.data.pmc + AT91_PMC_SCDR);
Alexandre Bellonifbc7edc2015-09-30 01:58:40 +0200648 cpu_do_idle();
649}
650
Alexandre Bellonid2e46792015-01-15 15:59:25 +0100651static void __init at91_pm_sram_init(void)
652{
653 struct gen_pool *sram_pool;
654 phys_addr_t sram_pbase;
655 unsigned long sram_base;
656 struct device_node *node;
Alexandre Belloni4a031f72015-03-03 08:38:07 +0100657 struct platform_device *pdev = NULL;
Alexandre Bellonid2e46792015-01-15 15:59:25 +0100658
Alexandre Belloni4a031f72015-03-03 08:38:07 +0100659 for_each_compatible_node(node, NULL, "mmio-sram") {
660 pdev = of_find_device_by_node(node);
661 if (pdev) {
662 of_node_put(node);
663 break;
664 }
Alexandre Bellonid2e46792015-01-15 15:59:25 +0100665 }
666
Alexandre Bellonid2e46792015-01-15 15:59:25 +0100667 if (!pdev) {
668 pr_warn("%s: failed to find sram device!\n", __func__);
Alexandre Belloni4a031f72015-03-03 08:38:07 +0100669 return;
Alexandre Bellonid2e46792015-01-15 15:59:25 +0100670 }
671
Vladimir Zapolskiy73858172015-09-04 15:47:43 -0700672 sram_pool = gen_pool_get(&pdev->dev, NULL);
Alexandre Bellonid2e46792015-01-15 15:59:25 +0100673 if (!sram_pool) {
674 pr_warn("%s: sram pool unavailable!\n", __func__);
yu kuaif87a4f02020-06-04 20:33:01 +0800675 goto out_put_device;
Alexandre Bellonid2e46792015-01-15 15:59:25 +0100676 }
677
Wenyou Yang5726a8b2015-03-09 11:51:09 +0800678 sram_base = gen_pool_alloc(sram_pool, at91_pm_suspend_in_sram_sz);
Alexandre Bellonid2e46792015-01-15 15:59:25 +0100679 if (!sram_base) {
Wenyou Yang5726a8b2015-03-09 11:51:09 +0800680 pr_warn("%s: unable to alloc sram!\n", __func__);
yu kuaif87a4f02020-06-04 20:33:01 +0800681 goto out_put_device;
Alexandre Bellonid2e46792015-01-15 15:59:25 +0100682 }
683
684 sram_pbase = gen_pool_virt_to_phys(sram_pool, sram_base);
Wenyou Yang5726a8b2015-03-09 11:51:09 +0800685 at91_suspend_sram_fn = __arm_ioremap_exec(sram_pbase,
686 at91_pm_suspend_in_sram_sz, false);
687 if (!at91_suspend_sram_fn) {
Wenyou Yangd94e6882015-03-09 11:49:01 +0800688 pr_warn("SRAM: Could not map\n");
yu kuaif87a4f02020-06-04 20:33:01 +0800689 goto out_put_device;
Wenyou Yangd94e6882015-03-09 11:49:01 +0800690 }
691
Wenyou Yang5726a8b2015-03-09 11:51:09 +0800692 /* Copy the pm suspend handler to SRAM */
693 at91_suspend_sram_fn = fncpy(at91_suspend_sram_fn,
694 &at91_pm_suspend_in_sram, at91_pm_suspend_in_sram_sz);
yu kuaif87a4f02020-06-04 20:33:01 +0800695 return;
696
697out_put_device:
698 put_device(&pdev->dev);
699 return;
Alexandre Bellonid2e46792015-01-15 15:59:25 +0100700}
Alexandre Bellonid2e46792015-01-15 15:59:25 +0100701
Claudiu Beznead7484f52018-07-17 14:06:24 +0300702static bool __init at91_is_pm_mode_active(int pm_mode)
703{
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000704 return (soc_pm.data.standby_mode == pm_mode ||
705 soc_pm.data.suspend_mode == pm_mode);
Claudiu Beznead7484f52018-07-17 14:06:24 +0300706}
707
Claudiu Beznead2d47162021-04-15 13:50:05 +0300708static int __init at91_pm_backup_scan_memcs(unsigned long node,
709 const char *uname, int depth,
710 void *data)
711{
712 const char *type;
713 const __be32 *reg;
714 int *located = data;
715 int size;
716
717 /* Memory node already located. */
718 if (*located)
719 return 0;
720
721 type = of_get_flat_dt_prop(node, "device_type", NULL);
722
723 /* We are scanning "memory" nodes only. */
724 if (!type || strcmp(type, "memory"))
725 return 0;
726
727 reg = of_get_flat_dt_prop(node, "reg", &size);
728 if (reg) {
729 soc_pm.memcs = __va((phys_addr_t)be32_to_cpu(*reg));
730 *located = 1;
731 }
732
733 return 0;
734}
735
Claudiu Beznead7484f52018-07-17 14:06:24 +0300736static int __init at91_pm_backup_init(void)
Alexandre Belloni24a0f5c2016-09-27 12:29:50 +0200737{
738 struct gen_pool *sram_pool;
739 struct device_node *np;
Claudiu Beznea629ba8e2021-04-15 13:49:51 +0300740 struct platform_device *pdev;
Claudiu Beznead2d47162021-04-15 13:50:05 +0300741 int ret = -ENODEV, located = 0;
Alexandre Belloni24a0f5c2016-09-27 12:29:50 +0200742
Claudiu Bezneaf205adb2021-04-15 13:50:06 +0300743 if (!IS_ENABLED(CONFIG_SOC_SAMA5D2) &&
744 !IS_ENABLED(CONFIG_SOC_SAMA7G5))
Claudiu Beznea2fa86e52019-02-14 15:54:47 +0000745 return -EPERM;
746
Claudiu Beznead7484f52018-07-17 14:06:24 +0300747 if (!at91_is_pm_mode_active(AT91_PM_BACKUP))
748 return 0;
Alexandre Belloni7693e182017-04-26 16:31:03 +0200749
Alexandre Belloni24a0f5c2016-09-27 12:29:50 +0200750 np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-securam");
751 if (!np)
Claudiu Beznea404956f2021-04-15 13:49:50 +0300752 return ret;
Alexandre Belloni24a0f5c2016-09-27 12:29:50 +0200753
754 pdev = of_find_device_by_node(np);
755 of_node_put(np);
756 if (!pdev) {
757 pr_warn("%s: failed to find securam device!\n", __func__);
Claudiu Beznea404956f2021-04-15 13:49:50 +0300758 return ret;
Alexandre Belloni24a0f5c2016-09-27 12:29:50 +0200759 }
760
761 sram_pool = gen_pool_get(&pdev->dev, NULL);
762 if (!sram_pool) {
763 pr_warn("%s: securam pool unavailable!\n", __func__);
764 goto securam_fail;
765 }
766
Claudiu Bezneaf19dd1d2021-04-15 13:49:47 +0300767 soc_pm.bu = (void *)gen_pool_alloc(sram_pool, sizeof(struct at91_pm_bu));
768 if (!soc_pm.bu) {
Alexandre Belloni24a0f5c2016-09-27 12:29:50 +0200769 pr_warn("%s: unable to alloc securam!\n", __func__);
Claudiu Beznead7484f52018-07-17 14:06:24 +0300770 ret = -ENOMEM;
Alexandre Belloni24a0f5c2016-09-27 12:29:50 +0200771 goto securam_fail;
772 }
773
Claudiu Bezneaf19dd1d2021-04-15 13:49:47 +0300774 soc_pm.bu->suspended = 0;
775 soc_pm.bu->canary = __pa_symbol(&canary);
776 soc_pm.bu->resume = __pa_symbol(cpu_resume);
Claudiu Beznead2d47162021-04-15 13:50:05 +0300777 if (soc_pm.data.ramc_phy) {
778 of_scan_flat_dt(at91_pm_backup_scan_memcs, &located);
779 if (!located)
780 goto securam_fail;
781
782 /* DDR3PHY_ZQ0SR0 */
783 soc_pm.bu->ddr_phy_calibration[0] = readl(soc_pm.data.ramc_phy +
784 0x188);
785 }
Alexandre Belloni24a0f5c2016-09-27 12:29:50 +0200786
Claudiu Beznead7484f52018-07-17 14:06:24 +0300787 return 0;
Alexandre Belloni24a0f5c2016-09-27 12:29:50 +0200788
Alexandre Belloni24a0f5c2016-09-27 12:29:50 +0200789securam_fail:
Peng Haoba5e60c2019-04-02 22:12:38 +0800790 put_device(&pdev->dev);
Claudiu Beznead7484f52018-07-17 14:06:24 +0300791 return ret;
792}
Alexandre Belloni28732232017-04-26 16:34:24 +0200793
Claudiu Bezneaec6e6182019-12-11 13:04:08 +0200794static const struct of_device_id atmel_shdwc_ids[] = {
795 { .compatible = "atmel,sama5d2-shdwc" },
796 { .compatible = "microchip,sam9x60-shdwc" },
Claudiu Bezneaad9bc2e2021-04-15 13:50:10 +0300797 { .compatible = "microchip,sama7g5-shdwc" },
Claudiu Bezneaec6e6182019-12-11 13:04:08 +0200798 { /* sentinel. */ }
799};
800
Claudiu Beznea404956f2021-04-15 13:49:50 +0300801static void __init at91_pm_modes_init(const u32 *maps, int len)
Claudiu Beznead7484f52018-07-17 14:06:24 +0300802{
803 struct device_node *np;
Claudiu Beznea404956f2021-04-15 13:49:50 +0300804 int ret, mode;
Claudiu Beznead7484f52018-07-17 14:06:24 +0300805
806 ret = at91_pm_backup_init();
807 if (ret) {
Claudiu Beznea404956f2021-04-15 13:49:50 +0300808 if (soc_pm.data.standby_mode == AT91_PM_BACKUP)
809 soc_pm.data.standby_mode = AT91_PM_ULP0;
810 if (soc_pm.data.suspend_mode == AT91_PM_BACKUP)
811 soc_pm.data.suspend_mode = AT91_PM_ULP0;
812 }
813
814 if (maps[soc_pm.data.standby_mode] & AT91_PM_IOMAP(SHDWC) ||
815 maps[soc_pm.data.suspend_mode] & AT91_PM_IOMAP(SHDWC)) {
816 np = of_find_matching_node(NULL, atmel_shdwc_ids);
817 if (!np) {
818 pr_warn("%s: failed to find shdwc!\n", __func__);
819
820 /* Use ULP0 if it doesn't needs SHDWC.*/
821 if (!(maps[AT91_PM_ULP0] & AT91_PM_IOMAP(SHDWC)))
822 mode = AT91_PM_ULP0;
823 else
824 mode = AT91_PM_STANDBY;
825
826 if (maps[soc_pm.data.standby_mode] & AT91_PM_IOMAP(SHDWC))
827 soc_pm.data.standby_mode = mode;
828 if (maps[soc_pm.data.suspend_mode] & AT91_PM_IOMAP(SHDWC))
829 soc_pm.data.suspend_mode = mode;
830 } else {
831 soc_pm.data.shdwc = of_iomap(np, 0);
832 of_node_put(np);
833 }
834 }
835
836 if (maps[soc_pm.data.standby_mode] & AT91_PM_IOMAP(SFRBU) ||
837 maps[soc_pm.data.suspend_mode] & AT91_PM_IOMAP(SFRBU)) {
838 np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-sfrbu");
839 if (!np) {
840 pr_warn("%s: failed to find sfrbu!\n", __func__);
841
842 /*
843 * Use ULP0 if it doesn't need SHDWC or if SHDWC
844 * was already located.
845 */
846 if (!(maps[AT91_PM_ULP0] & AT91_PM_IOMAP(SHDWC)) ||
847 soc_pm.data.shdwc)
848 mode = AT91_PM_ULP0;
849 else
850 mode = AT91_PM_STANDBY;
851
852 if (maps[soc_pm.data.standby_mode] & AT91_PM_IOMAP(SFRBU))
853 soc_pm.data.standby_mode = mode;
854 if (maps[soc_pm.data.suspend_mode] & AT91_PM_IOMAP(SFRBU))
855 soc_pm.data.suspend_mode = mode;
856 } else {
857 soc_pm.data.sfrbu = of_iomap(np, 0);
858 of_node_put(np);
859 }
860 }
861
862 /* Unmap all unnecessary. */
863 if (soc_pm.data.shdwc &&
864 !(maps[soc_pm.data.standby_mode] & AT91_PM_IOMAP(SHDWC) ||
865 maps[soc_pm.data.suspend_mode] & AT91_PM_IOMAP(SHDWC))) {
866 iounmap(soc_pm.data.shdwc);
867 soc_pm.data.shdwc = NULL;
868 }
869
870 if (soc_pm.data.sfrbu &&
871 !(maps[soc_pm.data.standby_mode] & AT91_PM_IOMAP(SFRBU) ||
872 maps[soc_pm.data.suspend_mode] & AT91_PM_IOMAP(SFRBU))) {
873 iounmap(soc_pm.data.sfrbu);
874 soc_pm.data.sfrbu = NULL;
Claudiu Beznead7484f52018-07-17 14:06:24 +0300875 }
876
877 return;
Claudiu Beznead7484f52018-07-17 14:06:24 +0300878}
879
Alexandre Belloni13f16012017-02-01 23:35:18 +0100880struct pmc_info {
881 unsigned long uhp_udp_mask;
Claudiu Beznea6ec15872020-01-20 14:10:01 +0200882 unsigned long mckr;
Claudiu Beznea0be298a2020-01-20 14:10:04 +0200883 unsigned long version;
Alexandre Belloni13f16012017-02-01 23:35:18 +0100884};
885
886static const struct pmc_info pmc_infos[] __initconst = {
Claudiu Beznea6ec15872020-01-20 14:10:01 +0200887 {
888 .uhp_udp_mask = AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP,
889 .mckr = 0x30,
Claudiu Beznea0be298a2020-01-20 14:10:04 +0200890 .version = AT91_PMC_V1,
Claudiu Beznea6ec15872020-01-20 14:10:01 +0200891 },
892
893 {
894 .uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP,
895 .mckr = 0x30,
Claudiu Beznea0be298a2020-01-20 14:10:04 +0200896 .version = AT91_PMC_V1,
Claudiu Beznea6ec15872020-01-20 14:10:01 +0200897 },
898 {
899 .uhp_udp_mask = AT91SAM926x_PMC_UHP,
900 .mckr = 0x30,
Claudiu Beznea0be298a2020-01-20 14:10:04 +0200901 .version = AT91_PMC_V1,
Claudiu Beznea6ec15872020-01-20 14:10:01 +0200902 },
903 { .uhp_udp_mask = 0,
904 .mckr = 0x30,
Claudiu Beznea0be298a2020-01-20 14:10:04 +0200905 .version = AT91_PMC_V1,
Claudiu Beznea6ec15872020-01-20 14:10:01 +0200906 },
907 {
908 .uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP,
909 .mckr = 0x28,
Claudiu Beznea0be298a2020-01-20 14:10:04 +0200910 .version = AT91_PMC_V2,
Claudiu Beznea6ec15872020-01-20 14:10:01 +0200911 },
Claudiu Bezneaccdbdf32021-04-15 13:50:07 +0300912 {
913 .mckr = 0x28,
914 .version = AT91_PMC_V2,
915 },
916
Alexandre Belloni13f16012017-02-01 23:35:18 +0100917};
918
Alexandre Belloni5737b732015-09-30 01:31:34 +0200919static const struct of_device_id atmel_pmc_ids[] __initconst = {
Alexandre Belloni13f16012017-02-01 23:35:18 +0100920 { .compatible = "atmel,at91rm9200-pmc", .data = &pmc_infos[0] },
921 { .compatible = "atmel,at91sam9260-pmc", .data = &pmc_infos[1] },
Alexandre Belloni91f87182018-06-07 10:41:06 +0200922 { .compatible = "atmel,at91sam9261-pmc", .data = &pmc_infos[1] },
923 { .compatible = "atmel,at91sam9263-pmc", .data = &pmc_infos[1] },
Alexandre Belloni13f16012017-02-01 23:35:18 +0100924 { .compatible = "atmel,at91sam9g45-pmc", .data = &pmc_infos[2] },
925 { .compatible = "atmel,at91sam9n12-pmc", .data = &pmc_infos[1] },
Alexandre Belloni91f87182018-06-07 10:41:06 +0200926 { .compatible = "atmel,at91sam9rl-pmc", .data = &pmc_infos[3] },
Alexandre Belloni13f16012017-02-01 23:35:18 +0100927 { .compatible = "atmel,at91sam9x5-pmc", .data = &pmc_infos[1] },
928 { .compatible = "atmel,sama5d3-pmc", .data = &pmc_infos[1] },
Alexandre Belloni91f87182018-06-07 10:41:06 +0200929 { .compatible = "atmel,sama5d4-pmc", .data = &pmc_infos[1] },
Alexandre Belloni13f16012017-02-01 23:35:18 +0100930 { .compatible = "atmel,sama5d2-pmc", .data = &pmc_infos[1] },
Claudiu Beznea6ec15872020-01-20 14:10:01 +0200931 { .compatible = "microchip,sam9x60-pmc", .data = &pmc_infos[4] },
Claudiu Bezneaccdbdf32021-04-15 13:50:07 +0300932 { .compatible = "microchip,sama7g5-pmc", .data = &pmc_infos[5] },
Alexandre Belloni5737b732015-09-30 01:31:34 +0200933 { /* sentinel */ },
934};
935
Claudiu Beznea39add362020-08-05 11:36:49 +0300936static void __init at91_pm_modes_validate(const int *modes, int len)
937{
938 u8 i, standby = 0, suspend = 0;
939 int mode;
940
941 for (i = 0; i < len; i++) {
942 if (standby && suspend)
943 break;
944
945 if (modes[i] == soc_pm.data.standby_mode && !standby) {
946 standby = 1;
947 continue;
948 }
949
950 if (modes[i] == soc_pm.data.suspend_mode && !suspend) {
951 suspend = 1;
952 continue;
953 }
954 }
955
956 if (!standby) {
957 if (soc_pm.data.suspend_mode == AT91_PM_STANDBY)
958 mode = AT91_PM_ULP0;
959 else
960 mode = AT91_PM_STANDBY;
961
962 pr_warn("AT91: PM: %s mode not supported! Using %s.\n",
963 pm_modes[soc_pm.data.standby_mode].pattern,
964 pm_modes[mode].pattern);
965 soc_pm.data.standby_mode = mode;
966 }
967
968 if (!suspend) {
969 if (soc_pm.data.standby_mode == AT91_PM_ULP0)
970 mode = AT91_PM_STANDBY;
971 else
972 mode = AT91_PM_ULP0;
973
974 pr_warn("AT91: PM: %s mode not supported! Using %s.\n",
975 pm_modes[soc_pm.data.suspend_mode].pattern,
976 pm_modes[mode].pattern);
977 soc_pm.data.suspend_mode = mode;
978 }
979}
980
Alexandre Bellonifbc7edc2015-09-30 01:58:40 +0200981static void __init at91_pm_init(void (*pm_idle)(void))
Andrew Victor907d6de2006-06-20 19:30:19 +0100982{
Alexandre Belloni5737b732015-09-30 01:31:34 +0200983 struct device_node *pmc_np;
Alexandre Belloni13f16012017-02-01 23:35:18 +0100984 const struct of_device_id *of_id;
985 const struct pmc_info *pmc;
Andrew Victorf5d0f452008-04-02 21:50:16 +0100986
Daniel Lezcano5ad945e2013-09-22 22:29:57 +0200987 if (at91_cpuidle_device.dev.platform_data)
988 platform_device_register(&at91_cpuidle_device);
Andrew Victor907d6de2006-06-20 19:30:19 +0100989
Alexandre Belloni13f16012017-02-01 23:35:18 +0100990 pmc_np = of_find_matching_node_and_match(NULL, atmel_pmc_ids, &of_id);
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000991 soc_pm.data.pmc = of_iomap(pmc_np, 0);
Claudiu Bezneae222f942020-08-05 11:36:50 +0300992 of_node_put(pmc_np);
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000993 if (!soc_pm.data.pmc) {
Alexandre Belloni5737b732015-09-30 01:31:34 +0200994 pr_err("AT91: PM not supported, PMC not found\n");
995 return;
996 }
997
Alexandre Belloni13f16012017-02-01 23:35:18 +0100998 pmc = of_id->data;
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +0000999 soc_pm.data.uhp_udp_mask = pmc->uhp_udp_mask;
Claudiu Beznea6ec15872020-01-20 14:10:01 +02001000 soc_pm.data.pmc_mckr_offset = pmc->mckr;
Claudiu Beznea0be298a2020-01-20 14:10:04 +02001001 soc_pm.data.pmc_version = pmc->version;
Alexandre Belloni13f16012017-02-01 23:35:18 +01001002
Alexandre Bellonifbc7edc2015-09-30 01:58:40 +02001003 if (pm_idle)
1004 arm_pm_idle = pm_idle;
1005
Alexandre Belloni5737b732015-09-30 01:31:34 +02001006 at91_pm_sram_init();
1007
Alexandre Belloni7693e182017-04-26 16:31:03 +02001008 if (at91_suspend_sram_fn) {
Wenyou Yangd94e6882015-03-09 11:49:01 +08001009 suspend_set_ops(&at91_pm_ops);
Alexandre Belloni7693e182017-04-26 16:31:03 +02001010 pr_info("AT91: PM: standby: %s, suspend: %s\n",
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +00001011 pm_modes[soc_pm.data.standby_mode].pattern,
1012 pm_modes[soc_pm.data.suspend_mode].pattern);
Alexandre Belloni7693e182017-04-26 16:31:03 +02001013 } else {
Wenyou Yangd94e6882015-03-09 11:49:01 +08001014 pr_info("AT91: PM not supported, due to no SRAM allocated\n");
Alexandre Belloni7693e182017-04-26 16:31:03 +02001015 }
Andrew Victor907d6de2006-06-20 19:30:19 +01001016}
Alexandre Belloni4db0ba22015-01-15 15:59:27 +01001017
Nicolas Ferread3fc3e2015-01-27 18:41:33 +01001018void __init at91rm9200_pm_init(void)
Alexandre Belloni4db0ba22015-01-15 15:59:27 +01001019{
Arnd Bergmanndbeb0c82017-08-23 16:46:15 +02001020 if (!IS_ENABLED(CONFIG_SOC_AT91RM9200))
1021 return;
1022
Claudiu Beznea39add362020-08-05 11:36:49 +03001023 /*
1024 * Force STANDBY and ULP0 mode to avoid calling
1025 * at91_pm_modes_validate() which may increase booting time.
1026 * Platform supports anyway only STANDBY and ULP0 modes.
1027 */
1028 soc_pm.data.standby_mode = AT91_PM_STANDBY;
1029 soc_pm.data.suspend_mode = AT91_PM_ULP0;
1030
Claudiu Beznea892e1f42021-04-15 13:50:04 +03001031 at91_dt_ramc(false);
Alexandre Belloni827de1f2015-01-27 17:38:46 +01001032
Alexandre Belloni4db0ba22015-01-15 15:59:27 +01001033 /*
1034 * AT91RM9200 SDRAM low-power mode cannot be used with self-refresh.
1035 */
Alexandre Bellonid7d45f22015-03-16 15:14:50 +01001036 at91_ramc_write(0, AT91_MC_SDRAMC_LPR, 0);
Alexandre Belloni4db0ba22015-01-15 15:59:27 +01001037
Alexandre Bellonifbc7edc2015-09-30 01:58:40 +02001038 at91_pm_init(at91rm9200_idle);
Alexandre Belloni4db0ba22015-01-15 15:59:27 +01001039}
1040
Claudiu Beznea01c70312019-02-14 15:54:41 +00001041void __init sam9x60_pm_init(void)
1042{
Claudiu Beznea39add362020-08-05 11:36:49 +03001043 static const int modes[] __initconst = {
1044 AT91_PM_STANDBY, AT91_PM_ULP0, AT91_PM_ULP0_FAST, AT91_PM_ULP1,
1045 };
Claudiu Beznea404956f2021-04-15 13:49:50 +03001046 static const int iomaps[] __initconst = {
1047 [AT91_PM_ULP1] = AT91_PM_IOMAP(SHDWC),
1048 };
Claudiu Beznea39add362020-08-05 11:36:49 +03001049
Claudiu Bezneaeb0df9b2019-11-29 15:51:39 +02001050 if (!IS_ENABLED(CONFIG_SOC_SAM9X60))
Claudiu Beznea01c70312019-02-14 15:54:41 +00001051 return;
1052
Claudiu Beznea39add362020-08-05 11:36:49 +03001053 at91_pm_modes_validate(modes, ARRAY_SIZE(modes));
Claudiu Beznea404956f2021-04-15 13:49:50 +03001054 at91_pm_modes_init(iomaps, ARRAY_SIZE(iomaps));
Claudiu Beznea892e1f42021-04-15 13:50:04 +03001055 at91_dt_ramc(false);
Alexandre Bellonifaf6dc62020-08-04 13:56:22 +02001056 at91_pm_init(NULL);
Claudiu Bezneaeaedc0d2019-02-14 15:54:57 +00001057
1058 soc_pm.ws_ids = sam9x60_ws_ids;
1059 soc_pm.config_pmc_ws = at91_sam9x60_config_pmc_ws;
Claudiu Beznea01c70312019-02-14 15:54:41 +00001060}
1061
Alexandre Belloni13469192017-02-01 23:43:03 +01001062void __init at91sam9_pm_init(void)
Nicolas Ferrebf022802015-01-22 16:54:50 +01001063{
Arnd Bergmanndbeb0c82017-08-23 16:46:15 +02001064 if (!IS_ENABLED(CONFIG_SOC_AT91SAM9))
1065 return;
1066
Claudiu Beznea39add362020-08-05 11:36:49 +03001067 /*
1068 * Force STANDBY and ULP0 mode to avoid calling
1069 * at91_pm_modes_validate() which may increase booting time.
1070 * Platform supports anyway only STANDBY and ULP0 modes.
1071 */
1072 soc_pm.data.standby_mode = AT91_PM_STANDBY;
1073 soc_pm.data.suspend_mode = AT91_PM_ULP0;
1074
Claudiu Beznea892e1f42021-04-15 13:50:04 +03001075 at91_dt_ramc(false);
Alexandre Bellonifbc7edc2015-09-30 01:58:40 +02001076 at91_pm_init(at91sam9_idle);
1077}
1078
1079void __init sama5_pm_init(void)
1080{
Claudiu Beznea39add362020-08-05 11:36:49 +03001081 static const int modes[] __initconst = {
1082 AT91_PM_STANDBY, AT91_PM_ULP0, AT91_PM_ULP0_FAST,
1083 };
1084
Arnd Bergmanndbeb0c82017-08-23 16:46:15 +02001085 if (!IS_ENABLED(CONFIG_SOC_SAMA5))
1086 return;
1087
Claudiu Beznea39add362020-08-05 11:36:49 +03001088 at91_pm_modes_validate(modes, ARRAY_SIZE(modes));
Claudiu Beznea892e1f42021-04-15 13:50:04 +03001089 at91_dt_ramc(false);
Alexandre Bellonifbc7edc2015-09-30 01:58:40 +02001090 at91_pm_init(NULL);
Nicolas Ferrebf022802015-01-22 16:54:50 +01001091}
Alexandre Belloni24a0f5c2016-09-27 12:29:50 +02001092
1093void __init sama5d2_pm_init(void)
1094{
Claudiu Beznea39add362020-08-05 11:36:49 +03001095 static const int modes[] __initconst = {
1096 AT91_PM_STANDBY, AT91_PM_ULP0, AT91_PM_ULP0_FAST, AT91_PM_ULP1,
1097 AT91_PM_BACKUP,
1098 };
Claudiu Beznea404956f2021-04-15 13:49:50 +03001099 static const u32 iomaps[] __initconst = {
1100 [AT91_PM_ULP1] = AT91_PM_IOMAP(SHDWC),
1101 [AT91_PM_BACKUP] = AT91_PM_IOMAP(SHDWC) |
1102 AT91_PM_IOMAP(SFRBU),
1103 };
Claudiu Beznea39add362020-08-05 11:36:49 +03001104
Arnd Bergmanndbeb0c82017-08-23 16:46:15 +02001105 if (!IS_ENABLED(CONFIG_SOC_SAMA5D2))
1106 return;
1107
Claudiu Beznea39add362020-08-05 11:36:49 +03001108 at91_pm_modes_validate(modes, ARRAY_SIZE(modes));
Claudiu Beznea404956f2021-04-15 13:49:50 +03001109 at91_pm_modes_init(iomaps, ARRAY_SIZE(iomaps));
Claudiu Beznea892e1f42021-04-15 13:50:04 +03001110 at91_dt_ramc(false);
Claudiu Beznea39add362020-08-05 11:36:49 +03001111 at91_pm_init(NULL);
Claudiu Bezneaa9581562019-02-14 15:54:51 +00001112
1113 soc_pm.ws_ids = sama5d2_ws_ids;
1114 soc_pm.config_shdwc_ws = at91_sama5d2_config_shdwc_ws;
1115 soc_pm.config_pmc_ws = at91_sama5d2_config_pmc_ws;
Alexandre Belloni24a0f5c2016-09-27 12:29:50 +02001116}
Alexandre Belloni7693e182017-04-26 16:31:03 +02001117
Claudiu Beznea65013302021-04-15 13:50:09 +03001118void __init sama7_pm_init(void)
1119{
1120 static const int modes[] __initconst = {
1121 AT91_PM_STANDBY, AT91_PM_ULP0, AT91_PM_ULP1, AT91_PM_BACKUP,
1122 };
1123 static const u32 iomaps[] __initconst = {
1124 [AT91_PM_ULP0] = AT91_PM_IOMAP(SFRBU),
1125 [AT91_PM_ULP1] = AT91_PM_IOMAP(SFRBU) |
1126 AT91_PM_IOMAP(SHDWC),
1127 [AT91_PM_BACKUP] = AT91_PM_IOMAP(SFRBU) |
1128 AT91_PM_IOMAP(SHDWC),
1129 };
1130
1131 if (!IS_ENABLED(CONFIG_SOC_SAMA7))
1132 return;
1133
1134 at91_pm_modes_validate(modes, ARRAY_SIZE(modes));
1135
1136 at91_dt_ramc(true);
1137 at91_pm_modes_init(iomaps, ARRAY_SIZE(iomaps));
1138 at91_pm_init(NULL);
1139
1140 soc_pm.ws_ids = sama7g5_ws_ids;
1141 soc_pm.config_pmc_ws = at91_sam9x60_config_pmc_ws;
1142}
1143
Alexandre Belloni7693e182017-04-26 16:31:03 +02001144static int __init at91_pm_modes_select(char *str)
1145{
1146 char *s;
1147 substring_t args[MAX_OPT_ARGS];
1148 int standby, suspend;
1149
1150 if (!str)
1151 return 0;
1152
1153 s = strsep(&str, ",");
1154 standby = match_token(s, pm_modes, args);
1155 if (standby < 0)
1156 return 0;
1157
1158 suspend = match_token(str, pm_modes, args);
1159 if (suspend < 0)
1160 return 0;
1161
Claudiu Bezneac3f5b8f2019-02-14 15:54:31 +00001162 soc_pm.data.standby_mode = standby;
1163 soc_pm.data.suspend_mode = suspend;
Alexandre Belloni7693e182017-04-26 16:31:03 +02001164
1165 return 0;
1166}
1167early_param("atmel.pm_modes", at91_pm_modes_select);