.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * arch/arm/mach-at91/pm.c |
---|
3 | 4 | * AT91 Power Management |
---|
4 | 5 | * |
---|
5 | 6 | * Copyright (C) 2005 David Brownell |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or modify |
---|
8 | | - * it under the terms of the GNU General Public License as published by |
---|
9 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
10 | | - * (at your option) any later version. |
---|
11 | 7 | */ |
---|
12 | 8 | |
---|
13 | 9 | #include <linux/genalloc.h> |
---|
.. | .. |
---|
19 | 15 | #include <linux/suspend.h> |
---|
20 | 16 | |
---|
21 | 17 | #include <linux/clk/at91_pmc.h> |
---|
| 18 | +#include <linux/platform_data/atmel.h> |
---|
22 | 19 | |
---|
23 | 20 | #include <asm/cacheflush.h> |
---|
24 | 21 | #include <asm/fncpy.h> |
---|
.. | .. |
---|
39 | 36 | extern void at91_pinctrl_gpio_resume(void); |
---|
40 | 37 | #endif |
---|
41 | 38 | |
---|
| 39 | +struct at91_soc_pm { |
---|
| 40 | + int (*config_shdwc_ws)(void __iomem *shdwc, u32 *mode, u32 *polarity); |
---|
| 41 | + int (*config_pmc_ws)(void __iomem *pmc, u32 mode, u32 polarity); |
---|
| 42 | + const struct of_device_id *ws_ids; |
---|
| 43 | + struct at91_pm_data data; |
---|
| 44 | +}; |
---|
| 45 | + |
---|
| 46 | +static struct at91_soc_pm soc_pm = { |
---|
| 47 | + .data = { |
---|
| 48 | + .standby_mode = AT91_PM_STANDBY, |
---|
| 49 | + .suspend_mode = AT91_PM_ULP0, |
---|
| 50 | + }, |
---|
| 51 | +}; |
---|
| 52 | + |
---|
42 | 53 | static const match_table_t pm_modes __initconst = { |
---|
43 | | - { AT91_PM_STANDBY, "standby" }, |
---|
44 | | - { AT91_PM_ULP0, "ulp0" }, |
---|
45 | | - { AT91_PM_ULP1, "ulp1" }, |
---|
46 | | - { AT91_PM_BACKUP, "backup" }, |
---|
| 54 | + { AT91_PM_STANDBY, "standby" }, |
---|
| 55 | + { AT91_PM_ULP0, "ulp0" }, |
---|
| 56 | + { AT91_PM_ULP0_FAST, "ulp0-fast" }, |
---|
| 57 | + { AT91_PM_ULP1, "ulp1" }, |
---|
| 58 | + { AT91_PM_BACKUP, "backup" }, |
---|
47 | 59 | { -1, NULL }, |
---|
48 | 60 | }; |
---|
49 | 61 | |
---|
50 | | -static struct at91_pm_data pm_data = { |
---|
51 | | - .standby_mode = AT91_PM_STANDBY, |
---|
52 | | - .suspend_mode = AT91_PM_ULP0, |
---|
53 | | -}; |
---|
54 | | - |
---|
55 | 62 | #define at91_ramc_read(id, field) \ |
---|
56 | | - __raw_readl(pm_data.ramc[id] + field) |
---|
| 63 | + __raw_readl(soc_pm.data.ramc[id] + field) |
---|
57 | 64 | |
---|
58 | 65 | #define at91_ramc_write(id, field, value) \ |
---|
59 | | - __raw_writel(value, pm_data.ramc[id] + field) |
---|
| 66 | + __raw_writel(value, soc_pm.data.ramc[id] + field) |
---|
60 | 67 | |
---|
61 | 68 | static int at91_pm_valid_state(suspend_state_t state) |
---|
62 | 69 | { |
---|
.. | .. |
---|
91 | 98 | { .pmc_fsmr_bit = AT91_PMC_RTCAL, .shdwc_mr_bit = BIT(17) }, |
---|
92 | 99 | { .pmc_fsmr_bit = AT91_PMC_USBAL }, |
---|
93 | 100 | { .pmc_fsmr_bit = AT91_PMC_SDMMC_CD }, |
---|
| 101 | + { .pmc_fsmr_bit = AT91_PMC_RTTAL }, |
---|
| 102 | + { .pmc_fsmr_bit = AT91_PMC_RXLP_MCE }, |
---|
94 | 103 | }; |
---|
95 | 104 | |
---|
96 | 105 | static const struct of_device_id sama5d2_ws_ids[] = { |
---|
97 | 106 | { .compatible = "atmel,sama5d2-gem", .data = &ws_info[0] }, |
---|
98 | | - { .compatible = "atmel,at91rm9200-rtc", .data = &ws_info[1] }, |
---|
| 107 | + { .compatible = "atmel,sama5d2-rtc", .data = &ws_info[1] }, |
---|
99 | 108 | { .compatible = "atmel,sama5d3-udc", .data = &ws_info[2] }, |
---|
100 | 109 | { .compatible = "atmel,at91rm9200-ohci", .data = &ws_info[2] }, |
---|
101 | 110 | { .compatible = "usb-ohci", .data = &ws_info[2] }, |
---|
102 | 111 | { .compatible = "atmel,at91sam9g45-ehci", .data = &ws_info[2] }, |
---|
103 | 112 | { .compatible = "usb-ehci", .data = &ws_info[2] }, |
---|
104 | 113 | { .compatible = "atmel,sama5d2-sdhci", .data = &ws_info[3] }, |
---|
| 114 | + { /* sentinel */ } |
---|
| 115 | +}; |
---|
| 116 | + |
---|
| 117 | +static const struct of_device_id sam9x60_ws_ids[] = { |
---|
| 118 | + { .compatible = "microchip,sam9x60-rtc", .data = &ws_info[1] }, |
---|
| 119 | + { .compatible = "atmel,at91rm9200-ohci", .data = &ws_info[2] }, |
---|
| 120 | + { .compatible = "usb-ohci", .data = &ws_info[2] }, |
---|
| 121 | + { .compatible = "atmel,at91sam9g45-ehci", .data = &ws_info[2] }, |
---|
| 122 | + { .compatible = "usb-ehci", .data = &ws_info[2] }, |
---|
| 123 | + { .compatible = "microchip,sam9x60-rtt", .data = &ws_info[4] }, |
---|
| 124 | + { .compatible = "cdns,sam9x60-macb", .data = &ws_info[5] }, |
---|
105 | 125 | { /* sentinel */ } |
---|
106 | 126 | }; |
---|
107 | 127 | |
---|
.. | .. |
---|
116 | 136 | if (pm_mode != AT91_PM_ULP1) |
---|
117 | 137 | return 0; |
---|
118 | 138 | |
---|
119 | | - if (!pm_data.pmc || !pm_data.shdwc) |
---|
| 139 | + if (!soc_pm.data.pmc || !soc_pm.data.shdwc || !soc_pm.ws_ids) |
---|
120 | 140 | return -EPERM; |
---|
121 | 141 | |
---|
122 | 142 | if (!set) { |
---|
123 | | - writel(mode, pm_data.pmc + AT91_PMC_FSMR); |
---|
| 143 | + writel(mode, soc_pm.data.pmc + AT91_PMC_FSMR); |
---|
124 | 144 | return 0; |
---|
125 | 145 | } |
---|
126 | 146 | |
---|
127 | | - /* SHDWC.WUIR */ |
---|
128 | | - val = readl(pm_data.shdwc + 0x0c); |
---|
129 | | - mode |= (val & 0x3ff); |
---|
130 | | - polarity |= ((val >> 16) & 0x3ff); |
---|
| 147 | + if (soc_pm.config_shdwc_ws) |
---|
| 148 | + soc_pm.config_shdwc_ws(soc_pm.data.shdwc, &mode, &polarity); |
---|
131 | 149 | |
---|
132 | 150 | /* SHDWC.MR */ |
---|
133 | | - val = readl(pm_data.shdwc + 0x04); |
---|
| 151 | + val = readl(soc_pm.data.shdwc + 0x04); |
---|
134 | 152 | |
---|
135 | 153 | /* Loop through defined wakeup sources. */ |
---|
136 | | - for_each_matching_node_and_match(np, sama5d2_ws_ids, &match) { |
---|
| 154 | + for_each_matching_node_and_match(np, soc_pm.ws_ids, &match) { |
---|
137 | 155 | pdev = of_find_device_by_node(np); |
---|
138 | 156 | if (!pdev) |
---|
139 | 157 | continue; |
---|
.. | .. |
---|
155 | 173 | } |
---|
156 | 174 | |
---|
157 | 175 | if (mode) { |
---|
158 | | - writel(mode, pm_data.pmc + AT91_PMC_FSMR); |
---|
159 | | - writel(polarity, pm_data.pmc + AT91_PMC_FSPR); |
---|
| 176 | + if (soc_pm.config_pmc_ws) |
---|
| 177 | + soc_pm.config_pmc_ws(soc_pm.data.pmc, mode, polarity); |
---|
160 | 178 | } else { |
---|
161 | 179 | pr_err("AT91: PM: no ULP1 wakeup sources found!"); |
---|
162 | 180 | } |
---|
163 | 181 | |
---|
164 | 182 | return mode ? 0 : -EPERM; |
---|
| 183 | +} |
---|
| 184 | + |
---|
| 185 | +static int at91_sama5d2_config_shdwc_ws(void __iomem *shdwc, u32 *mode, |
---|
| 186 | + u32 *polarity) |
---|
| 187 | +{ |
---|
| 188 | + u32 val; |
---|
| 189 | + |
---|
| 190 | + /* SHDWC.WUIR */ |
---|
| 191 | + val = readl(shdwc + 0x0c); |
---|
| 192 | + *mode |= (val & 0x3ff); |
---|
| 193 | + *polarity |= ((val >> 16) & 0x3ff); |
---|
| 194 | + |
---|
| 195 | + return 0; |
---|
| 196 | +} |
---|
| 197 | + |
---|
| 198 | +static int at91_sama5d2_config_pmc_ws(void __iomem *pmc, u32 mode, u32 polarity) |
---|
| 199 | +{ |
---|
| 200 | + writel(mode, pmc + AT91_PMC_FSMR); |
---|
| 201 | + writel(polarity, pmc + AT91_PMC_FSPR); |
---|
| 202 | + |
---|
| 203 | + return 0; |
---|
| 204 | +} |
---|
| 205 | + |
---|
| 206 | +static int at91_sam9x60_config_pmc_ws(void __iomem *pmc, u32 mode, u32 polarity) |
---|
| 207 | +{ |
---|
| 208 | + writel(mode, pmc + AT91_PMC_FSMR); |
---|
| 209 | + |
---|
| 210 | + return 0; |
---|
165 | 211 | } |
---|
166 | 212 | |
---|
167 | 213 | /* |
---|
.. | .. |
---|
171 | 217 | { |
---|
172 | 218 | switch (state) { |
---|
173 | 219 | case PM_SUSPEND_MEM: |
---|
174 | | - pm_data.mode = pm_data.suspend_mode; |
---|
| 220 | + soc_pm.data.mode = soc_pm.data.suspend_mode; |
---|
175 | 221 | break; |
---|
176 | 222 | |
---|
177 | 223 | case PM_SUSPEND_STANDBY: |
---|
178 | | - pm_data.mode = pm_data.standby_mode; |
---|
| 224 | + soc_pm.data.mode = soc_pm.data.standby_mode; |
---|
179 | 225 | break; |
---|
180 | 226 | |
---|
181 | 227 | default: |
---|
182 | | - pm_data.mode = -1; |
---|
| 228 | + soc_pm.data.mode = -1; |
---|
183 | 229 | } |
---|
184 | 230 | |
---|
185 | | - return at91_pm_config_ws(pm_data.mode, true); |
---|
| 231 | + return at91_pm_config_ws(soc_pm.data.mode, true); |
---|
186 | 232 | } |
---|
187 | 233 | |
---|
188 | 234 | /* |
---|
.. | .. |
---|
194 | 240 | unsigned long scsr; |
---|
195 | 241 | int i; |
---|
196 | 242 | |
---|
197 | | - scsr = readl(pm_data.pmc + AT91_PMC_SCSR); |
---|
| 243 | + scsr = readl(soc_pm.data.pmc + AT91_PMC_SCSR); |
---|
198 | 244 | |
---|
199 | 245 | /* USB must not be using PLLB */ |
---|
200 | | - if ((scsr & pm_data.uhp_udp_mask) != 0) { |
---|
| 246 | + if ((scsr & soc_pm.data.uhp_udp_mask) != 0) { |
---|
201 | 247 | pr_err("AT91: PM - Suspend-to-RAM with USB still active\n"); |
---|
202 | 248 | return 0; |
---|
203 | 249 | } |
---|
.. | .. |
---|
208 | 254 | |
---|
209 | 255 | if ((scsr & (AT91_PMC_PCK0 << i)) == 0) |
---|
210 | 256 | continue; |
---|
211 | | - css = readl(pm_data.pmc + AT91_PMC_PCKR(i)) & AT91_PMC_CSS; |
---|
| 257 | + css = readl(soc_pm.data.pmc + AT91_PMC_PCKR(i)) & AT91_PMC_CSS; |
---|
212 | 258 | if (css != AT91_PMC_CSS_SLOW) { |
---|
213 | 259 | pr_err("AT91: PM - Suspend-to-RAM with PCK%d src %d\n", i, css); |
---|
214 | 260 | return 0; |
---|
.. | .. |
---|
230 | 276 | */ |
---|
231 | 277 | int at91_suspend_entering_slow_clock(void) |
---|
232 | 278 | { |
---|
233 | | - return (pm_data.mode >= AT91_PM_ULP0); |
---|
| 279 | + return (soc_pm.data.mode >= AT91_PM_ULP0); |
---|
234 | 280 | } |
---|
235 | 281 | EXPORT_SYMBOL(at91_suspend_entering_slow_clock); |
---|
236 | 282 | |
---|
.. | .. |
---|
243 | 289 | flush_cache_all(); |
---|
244 | 290 | outer_disable(); |
---|
245 | 291 | |
---|
246 | | - at91_suspend_sram_fn(&pm_data); |
---|
| 292 | + at91_suspend_sram_fn(&soc_pm.data); |
---|
247 | 293 | |
---|
248 | 294 | return 0; |
---|
249 | 295 | } |
---|
250 | 296 | |
---|
251 | 297 | static void at91_pm_suspend(suspend_state_t state) |
---|
252 | 298 | { |
---|
253 | | - if (pm_data.mode == AT91_PM_BACKUP) { |
---|
| 299 | + if (soc_pm.data.mode == AT91_PM_BACKUP) { |
---|
254 | 300 | pm_bu->suspended = 1; |
---|
255 | 301 | |
---|
256 | 302 | cpu_suspend(0, at91_suspend_finish); |
---|
.. | .. |
---|
289 | 335 | /* |
---|
290 | 336 | * Ensure that clocks are in a valid state. |
---|
291 | 337 | */ |
---|
292 | | - if (pm_data.mode >= AT91_PM_ULP0 && |
---|
| 338 | + if (soc_pm.data.mode >= AT91_PM_ULP0 && |
---|
293 | 339 | !at91_pm_verify_clocks()) |
---|
294 | 340 | goto error; |
---|
295 | 341 | |
---|
.. | .. |
---|
318 | 364 | */ |
---|
319 | 365 | static void at91_pm_end(void) |
---|
320 | 366 | { |
---|
321 | | - at91_pm_config_ws(pm_data.mode, false); |
---|
| 367 | + at91_pm_config_ws(soc_pm.data.mode, false); |
---|
322 | 368 | } |
---|
323 | 369 | |
---|
324 | 370 | |
---|
.. | .. |
---|
351 | 397 | " str %2, [%1, %3]\n\t" |
---|
352 | 398 | " mcr p15, 0, %0, c7, c0, 4\n\t" |
---|
353 | 399 | : |
---|
354 | | - : "r" (0), "r" (pm_data.ramc[0]), |
---|
| 400 | + : "r" (0), "r" (soc_pm.data.ramc[0]), |
---|
355 | 401 | "r" (1), "r" (AT91_MC_SDRAMC_SRR)); |
---|
356 | 402 | } |
---|
357 | 403 | |
---|
.. | .. |
---|
374 | 420 | at91_ramc_write(0, AT91_DDRSDRC_MDR, mdr); |
---|
375 | 421 | } |
---|
376 | 422 | |
---|
377 | | - if (pm_data.ramc[1]) { |
---|
| 423 | + if (soc_pm.data.ramc[1]) { |
---|
378 | 424 | saved_lpr1 = at91_ramc_read(1, AT91_DDRSDRC_LPR); |
---|
379 | 425 | lpr1 = saved_lpr1 & ~AT91_DDRSDRC_LPCB; |
---|
380 | 426 | lpr1 |= AT91_DDRSDRC_LPCB_SELF_REFRESH; |
---|
.. | .. |
---|
392 | 438 | |
---|
393 | 439 | /* self-refresh mode now */ |
---|
394 | 440 | at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr0); |
---|
395 | | - if (pm_data.ramc[1]) |
---|
| 441 | + if (soc_pm.data.ramc[1]) |
---|
396 | 442 | at91_ramc_write(1, AT91_DDRSDRC_LPR, lpr1); |
---|
397 | 443 | |
---|
398 | 444 | cpu_do_idle(); |
---|
399 | 445 | |
---|
400 | 446 | at91_ramc_write(0, AT91_DDRSDRC_MDR, saved_mdr0); |
---|
401 | 447 | at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0); |
---|
402 | | - if (pm_data.ramc[1]) { |
---|
| 448 | + if (soc_pm.data.ramc[1]) { |
---|
403 | 449 | at91_ramc_write(0, AT91_DDRSDRC_MDR, saved_mdr1); |
---|
404 | 450 | at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1); |
---|
405 | 451 | } |
---|
.. | .. |
---|
429 | 475 | u32 lpr0, lpr1 = 0; |
---|
430 | 476 | u32 saved_lpr0, saved_lpr1 = 0; |
---|
431 | 477 | |
---|
432 | | - if (pm_data.ramc[1]) { |
---|
| 478 | + if (soc_pm.data.ramc[1]) { |
---|
433 | 479 | saved_lpr1 = at91_ramc_read(1, AT91_SDRAMC_LPR); |
---|
434 | 480 | lpr1 = saved_lpr1 & ~AT91_SDRAMC_LPCB; |
---|
435 | 481 | lpr1 |= AT91_SDRAMC_LPCB_SELF_REFRESH; |
---|
.. | .. |
---|
441 | 487 | |
---|
442 | 488 | /* self-refresh mode now */ |
---|
443 | 489 | at91_ramc_write(0, AT91_SDRAMC_LPR, lpr0); |
---|
444 | | - if (pm_data.ramc[1]) |
---|
| 490 | + if (soc_pm.data.ramc[1]) |
---|
445 | 491 | at91_ramc_write(1, AT91_SDRAMC_LPR, lpr1); |
---|
446 | 492 | |
---|
447 | 493 | cpu_do_idle(); |
---|
448 | 494 | |
---|
449 | 495 | at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr0); |
---|
450 | | - if (pm_data.ramc[1]) |
---|
| 496 | + if (soc_pm.data.ramc[1]) |
---|
451 | 497 | at91_ramc_write(1, AT91_SDRAMC_LPR, saved_lpr1); |
---|
452 | 498 | } |
---|
453 | 499 | |
---|
.. | .. |
---|
471 | 517 | { /*sentinel*/ } |
---|
472 | 518 | }; |
---|
473 | 519 | |
---|
474 | | -static __init void at91_dt_ramc(void) |
---|
| 520 | +static __init int at91_dt_ramc(void) |
---|
475 | 521 | { |
---|
476 | 522 | struct device_node *np; |
---|
477 | 523 | const struct of_device_id *of_id; |
---|
478 | 524 | int idx = 0; |
---|
479 | 525 | void *standby = NULL; |
---|
480 | 526 | const struct ramc_info *ramc; |
---|
| 527 | + int ret; |
---|
481 | 528 | |
---|
482 | 529 | for_each_matching_node_and_match(np, ramc_ids, &of_id) { |
---|
483 | | - pm_data.ramc[idx] = of_iomap(np, 0); |
---|
484 | | - if (!pm_data.ramc[idx]) |
---|
485 | | - panic(pr_fmt("unable to map ramc[%d] cpu registers\n"), idx); |
---|
| 530 | + soc_pm.data.ramc[idx] = of_iomap(np, 0); |
---|
| 531 | + if (!soc_pm.data.ramc[idx]) { |
---|
| 532 | + pr_err("unable to map ramc[%d] cpu registers\n", idx); |
---|
| 533 | + ret = -ENOMEM; |
---|
| 534 | + goto unmap_ramc; |
---|
| 535 | + } |
---|
486 | 536 | |
---|
487 | 537 | ramc = of_id->data; |
---|
488 | 538 | if (!standby) |
---|
489 | 539 | standby = ramc->idle; |
---|
490 | | - pm_data.memctrl = ramc->memctrl; |
---|
| 540 | + soc_pm.data.memctrl = ramc->memctrl; |
---|
491 | 541 | |
---|
492 | 542 | idx++; |
---|
493 | 543 | } |
---|
494 | 544 | |
---|
495 | | - if (!idx) |
---|
496 | | - panic(pr_fmt("unable to find compatible ram controller node in dtb\n")); |
---|
| 545 | + if (!idx) { |
---|
| 546 | + pr_err("unable to find compatible ram controller node in dtb\n"); |
---|
| 547 | + ret = -ENODEV; |
---|
| 548 | + goto unmap_ramc; |
---|
| 549 | + } |
---|
497 | 550 | |
---|
498 | 551 | if (!standby) { |
---|
499 | 552 | pr_warn("ramc no standby function available\n"); |
---|
500 | | - return; |
---|
| 553 | + return 0; |
---|
501 | 554 | } |
---|
502 | 555 | |
---|
503 | 556 | at91_cpuidle_device.dev.platform_data = standby; |
---|
| 557 | + |
---|
| 558 | + return 0; |
---|
| 559 | + |
---|
| 560 | +unmap_ramc: |
---|
| 561 | + while (idx) |
---|
| 562 | + iounmap(soc_pm.data.ramc[--idx]); |
---|
| 563 | + |
---|
| 564 | + return ret; |
---|
504 | 565 | } |
---|
505 | 566 | |
---|
506 | 567 | static void at91rm9200_idle(void) |
---|
.. | .. |
---|
509 | 570 | * Disable the processor clock. The processor will be automatically |
---|
510 | 571 | * re-enabled by an interrupt or by a reset. |
---|
511 | 572 | */ |
---|
512 | | - writel(AT91_PMC_PCK, pm_data.pmc + AT91_PMC_SCDR); |
---|
| 573 | + writel(AT91_PMC_PCK, soc_pm.data.pmc + AT91_PMC_SCDR); |
---|
513 | 574 | } |
---|
514 | 575 | |
---|
515 | 576 | static void at91sam9_idle(void) |
---|
516 | 577 | { |
---|
517 | | - writel(AT91_PMC_PCK, pm_data.pmc + AT91_PMC_SCDR); |
---|
| 578 | + writel(AT91_PMC_PCK, soc_pm.data.pmc + AT91_PMC_SCDR); |
---|
518 | 579 | cpu_do_idle(); |
---|
519 | 580 | } |
---|
520 | 581 | |
---|
.. | .. |
---|
571 | 632 | |
---|
572 | 633 | static bool __init at91_is_pm_mode_active(int pm_mode) |
---|
573 | 634 | { |
---|
574 | | - return (pm_data.standby_mode == pm_mode || |
---|
575 | | - pm_data.suspend_mode == pm_mode); |
---|
| 635 | + return (soc_pm.data.standby_mode == pm_mode || |
---|
| 636 | + soc_pm.data.suspend_mode == pm_mode); |
---|
576 | 637 | } |
---|
577 | 638 | |
---|
578 | 639 | static int __init at91_pm_backup_init(void) |
---|
.. | .. |
---|
582 | 643 | struct platform_device *pdev = NULL; |
---|
583 | 644 | int ret = -ENODEV; |
---|
584 | 645 | |
---|
| 646 | + if (!IS_ENABLED(CONFIG_SOC_SAMA5D2)) |
---|
| 647 | + return -EPERM; |
---|
| 648 | + |
---|
585 | 649 | if (!at91_is_pm_mode_active(AT91_PM_BACKUP)) |
---|
586 | 650 | return 0; |
---|
587 | | - |
---|
588 | | - pm_bu = NULL; |
---|
589 | 651 | |
---|
590 | 652 | np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-sfrbu"); |
---|
591 | 653 | if (!np) { |
---|
.. | .. |
---|
593 | 655 | return ret; |
---|
594 | 656 | } |
---|
595 | 657 | |
---|
596 | | - pm_data.sfrbu = of_iomap(np, 0); |
---|
| 658 | + soc_pm.data.sfrbu = of_iomap(np, 0); |
---|
597 | 659 | of_node_put(np); |
---|
598 | | - pm_bu = NULL; |
---|
599 | 660 | |
---|
600 | 661 | np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-securam"); |
---|
601 | 662 | if (!np) |
---|
.. | .. |
---|
630 | 691 | securam_fail: |
---|
631 | 692 | put_device(&pdev->dev); |
---|
632 | 693 | securam_fail_no_ref_dev: |
---|
633 | | - iounmap(pm_data.sfrbu); |
---|
634 | | - pm_data.sfrbu = NULL; |
---|
| 694 | + iounmap(soc_pm.data.sfrbu); |
---|
| 695 | + soc_pm.data.sfrbu = NULL; |
---|
635 | 696 | return ret; |
---|
636 | 697 | } |
---|
637 | 698 | |
---|
.. | .. |
---|
640 | 701 | if (pm_mode != AT91_PM_ULP1 && pm_mode != AT91_PM_BACKUP) |
---|
641 | 702 | return; |
---|
642 | 703 | |
---|
643 | | - if (pm_data.standby_mode == pm_mode) |
---|
644 | | - pm_data.standby_mode = AT91_PM_ULP0; |
---|
645 | | - if (pm_data.suspend_mode == pm_mode) |
---|
646 | | - pm_data.suspend_mode = AT91_PM_ULP0; |
---|
| 704 | + if (soc_pm.data.standby_mode == pm_mode) |
---|
| 705 | + soc_pm.data.standby_mode = AT91_PM_ULP0; |
---|
| 706 | + if (soc_pm.data.suspend_mode == pm_mode) |
---|
| 707 | + soc_pm.data.suspend_mode = AT91_PM_ULP0; |
---|
647 | 708 | } |
---|
| 709 | + |
---|
| 710 | +static const struct of_device_id atmel_shdwc_ids[] = { |
---|
| 711 | + { .compatible = "atmel,sama5d2-shdwc" }, |
---|
| 712 | + { .compatible = "microchip,sam9x60-shdwc" }, |
---|
| 713 | + { /* sentinel. */ } |
---|
| 714 | +}; |
---|
648 | 715 | |
---|
649 | 716 | static void __init at91_pm_modes_init(void) |
---|
650 | 717 | { |
---|
.. | .. |
---|
655 | 722 | !at91_is_pm_mode_active(AT91_PM_ULP1)) |
---|
656 | 723 | return; |
---|
657 | 724 | |
---|
658 | | - np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-shdwc"); |
---|
| 725 | + np = of_find_matching_node(NULL, atmel_shdwc_ids); |
---|
659 | 726 | if (!np) { |
---|
660 | 727 | pr_warn("%s: failed to find shdwc!\n", __func__); |
---|
661 | 728 | goto ulp1_default; |
---|
662 | 729 | } |
---|
663 | 730 | |
---|
664 | | - pm_data.shdwc = of_iomap(np, 0); |
---|
| 731 | + soc_pm.data.shdwc = of_iomap(np, 0); |
---|
665 | 732 | of_node_put(np); |
---|
666 | 733 | |
---|
667 | 734 | ret = at91_pm_backup_init(); |
---|
.. | .. |
---|
675 | 742 | return; |
---|
676 | 743 | |
---|
677 | 744 | unmap: |
---|
678 | | - iounmap(pm_data.shdwc); |
---|
679 | | - pm_data.shdwc = NULL; |
---|
| 745 | + iounmap(soc_pm.data.shdwc); |
---|
| 746 | + soc_pm.data.shdwc = NULL; |
---|
680 | 747 | ulp1_default: |
---|
681 | 748 | at91_pm_use_default_mode(AT91_PM_ULP1); |
---|
682 | 749 | backup_default: |
---|
.. | .. |
---|
685 | 752 | |
---|
686 | 753 | struct pmc_info { |
---|
687 | 754 | unsigned long uhp_udp_mask; |
---|
| 755 | + unsigned long mckr; |
---|
| 756 | + unsigned long version; |
---|
688 | 757 | }; |
---|
689 | 758 | |
---|
690 | 759 | static const struct pmc_info pmc_infos[] __initconst = { |
---|
691 | | - { .uhp_udp_mask = AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP }, |
---|
692 | | - { .uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP }, |
---|
693 | | - { .uhp_udp_mask = AT91SAM926x_PMC_UHP }, |
---|
694 | | - { .uhp_udp_mask = 0 }, |
---|
| 760 | + { |
---|
| 761 | + .uhp_udp_mask = AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP, |
---|
| 762 | + .mckr = 0x30, |
---|
| 763 | + .version = AT91_PMC_V1, |
---|
| 764 | + }, |
---|
| 765 | + |
---|
| 766 | + { |
---|
| 767 | + .uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP, |
---|
| 768 | + .mckr = 0x30, |
---|
| 769 | + .version = AT91_PMC_V1, |
---|
| 770 | + }, |
---|
| 771 | + { |
---|
| 772 | + .uhp_udp_mask = AT91SAM926x_PMC_UHP, |
---|
| 773 | + .mckr = 0x30, |
---|
| 774 | + .version = AT91_PMC_V1, |
---|
| 775 | + }, |
---|
| 776 | + { .uhp_udp_mask = 0, |
---|
| 777 | + .mckr = 0x30, |
---|
| 778 | + .version = AT91_PMC_V1, |
---|
| 779 | + }, |
---|
| 780 | + { |
---|
| 781 | + .uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP, |
---|
| 782 | + .mckr = 0x28, |
---|
| 783 | + .version = AT91_PMC_V2, |
---|
| 784 | + }, |
---|
695 | 785 | }; |
---|
696 | 786 | |
---|
697 | 787 | static const struct of_device_id atmel_pmc_ids[] __initconst = { |
---|
.. | .. |
---|
706 | 796 | { .compatible = "atmel,sama5d3-pmc", .data = &pmc_infos[1] }, |
---|
707 | 797 | { .compatible = "atmel,sama5d4-pmc", .data = &pmc_infos[1] }, |
---|
708 | 798 | { .compatible = "atmel,sama5d2-pmc", .data = &pmc_infos[1] }, |
---|
| 799 | + { .compatible = "microchip,sam9x60-pmc", .data = &pmc_infos[4] }, |
---|
709 | 800 | { /* sentinel */ }, |
---|
710 | 801 | }; |
---|
| 802 | + |
---|
| 803 | +static void __init at91_pm_modes_validate(const int *modes, int len) |
---|
| 804 | +{ |
---|
| 805 | + u8 i, standby = 0, suspend = 0; |
---|
| 806 | + int mode; |
---|
| 807 | + |
---|
| 808 | + for (i = 0; i < len; i++) { |
---|
| 809 | + if (standby && suspend) |
---|
| 810 | + break; |
---|
| 811 | + |
---|
| 812 | + if (modes[i] == soc_pm.data.standby_mode && !standby) { |
---|
| 813 | + standby = 1; |
---|
| 814 | + continue; |
---|
| 815 | + } |
---|
| 816 | + |
---|
| 817 | + if (modes[i] == soc_pm.data.suspend_mode && !suspend) { |
---|
| 818 | + suspend = 1; |
---|
| 819 | + continue; |
---|
| 820 | + } |
---|
| 821 | + } |
---|
| 822 | + |
---|
| 823 | + if (!standby) { |
---|
| 824 | + if (soc_pm.data.suspend_mode == AT91_PM_STANDBY) |
---|
| 825 | + mode = AT91_PM_ULP0; |
---|
| 826 | + else |
---|
| 827 | + mode = AT91_PM_STANDBY; |
---|
| 828 | + |
---|
| 829 | + pr_warn("AT91: PM: %s mode not supported! Using %s.\n", |
---|
| 830 | + pm_modes[soc_pm.data.standby_mode].pattern, |
---|
| 831 | + pm_modes[mode].pattern); |
---|
| 832 | + soc_pm.data.standby_mode = mode; |
---|
| 833 | + } |
---|
| 834 | + |
---|
| 835 | + if (!suspend) { |
---|
| 836 | + if (soc_pm.data.standby_mode == AT91_PM_ULP0) |
---|
| 837 | + mode = AT91_PM_STANDBY; |
---|
| 838 | + else |
---|
| 839 | + mode = AT91_PM_ULP0; |
---|
| 840 | + |
---|
| 841 | + pr_warn("AT91: PM: %s mode not supported! Using %s.\n", |
---|
| 842 | + pm_modes[soc_pm.data.suspend_mode].pattern, |
---|
| 843 | + pm_modes[mode].pattern); |
---|
| 844 | + soc_pm.data.suspend_mode = mode; |
---|
| 845 | + } |
---|
| 846 | +} |
---|
711 | 847 | |
---|
712 | 848 | static void __init at91_pm_init(void (*pm_idle)(void)) |
---|
713 | 849 | { |
---|
.. | .. |
---|
719 | 855 | platform_device_register(&at91_cpuidle_device); |
---|
720 | 856 | |
---|
721 | 857 | pmc_np = of_find_matching_node_and_match(NULL, atmel_pmc_ids, &of_id); |
---|
722 | | - pm_data.pmc = of_iomap(pmc_np, 0); |
---|
723 | | - if (!pm_data.pmc) { |
---|
| 858 | + soc_pm.data.pmc = of_iomap(pmc_np, 0); |
---|
| 859 | + of_node_put(pmc_np); |
---|
| 860 | + if (!soc_pm.data.pmc) { |
---|
724 | 861 | pr_err("AT91: PM not supported, PMC not found\n"); |
---|
725 | 862 | return; |
---|
726 | 863 | } |
---|
727 | 864 | |
---|
728 | 865 | pmc = of_id->data; |
---|
729 | | - pm_data.uhp_udp_mask = pmc->uhp_udp_mask; |
---|
| 866 | + soc_pm.data.uhp_udp_mask = pmc->uhp_udp_mask; |
---|
| 867 | + soc_pm.data.pmc_mckr_offset = pmc->mckr; |
---|
| 868 | + soc_pm.data.pmc_version = pmc->version; |
---|
730 | 869 | |
---|
731 | 870 | if (pm_idle) |
---|
732 | 871 | arm_pm_idle = pm_idle; |
---|
.. | .. |
---|
736 | 875 | if (at91_suspend_sram_fn) { |
---|
737 | 876 | suspend_set_ops(&at91_pm_ops); |
---|
738 | 877 | pr_info("AT91: PM: standby: %s, suspend: %s\n", |
---|
739 | | - pm_modes[pm_data.standby_mode].pattern, |
---|
740 | | - pm_modes[pm_data.suspend_mode].pattern); |
---|
| 878 | + pm_modes[soc_pm.data.standby_mode].pattern, |
---|
| 879 | + pm_modes[soc_pm.data.suspend_mode].pattern); |
---|
741 | 880 | } else { |
---|
742 | 881 | pr_info("AT91: PM not supported, due to no SRAM allocated\n"); |
---|
743 | 882 | } |
---|
.. | .. |
---|
745 | 884 | |
---|
746 | 885 | void __init at91rm9200_pm_init(void) |
---|
747 | 886 | { |
---|
| 887 | + int ret; |
---|
| 888 | + |
---|
748 | 889 | if (!IS_ENABLED(CONFIG_SOC_AT91RM9200)) |
---|
749 | 890 | return; |
---|
750 | 891 | |
---|
751 | | - at91_dt_ramc(); |
---|
| 892 | + /* |
---|
| 893 | + * Force STANDBY and ULP0 mode to avoid calling |
---|
| 894 | + * at91_pm_modes_validate() which may increase booting time. |
---|
| 895 | + * Platform supports anyway only STANDBY and ULP0 modes. |
---|
| 896 | + */ |
---|
| 897 | + soc_pm.data.standby_mode = AT91_PM_STANDBY; |
---|
| 898 | + soc_pm.data.suspend_mode = AT91_PM_ULP0; |
---|
| 899 | + |
---|
| 900 | + ret = at91_dt_ramc(); |
---|
| 901 | + if (ret) |
---|
| 902 | + return; |
---|
752 | 903 | |
---|
753 | 904 | /* |
---|
754 | 905 | * AT91RM9200 SDRAM low-power mode cannot be used with self-refresh. |
---|
.. | .. |
---|
758 | 909 | at91_pm_init(at91rm9200_idle); |
---|
759 | 910 | } |
---|
760 | 911 | |
---|
| 912 | +void __init sam9x60_pm_init(void) |
---|
| 913 | +{ |
---|
| 914 | + static const int modes[] __initconst = { |
---|
| 915 | + AT91_PM_STANDBY, AT91_PM_ULP0, AT91_PM_ULP0_FAST, AT91_PM_ULP1, |
---|
| 916 | + }; |
---|
| 917 | + int ret; |
---|
| 918 | + |
---|
| 919 | + if (!IS_ENABLED(CONFIG_SOC_SAM9X60)) |
---|
| 920 | + return; |
---|
| 921 | + |
---|
| 922 | + at91_pm_modes_validate(modes, ARRAY_SIZE(modes)); |
---|
| 923 | + at91_pm_modes_init(); |
---|
| 924 | + ret = at91_dt_ramc(); |
---|
| 925 | + if (ret) |
---|
| 926 | + return; |
---|
| 927 | + |
---|
| 928 | + at91_pm_init(NULL); |
---|
| 929 | + |
---|
| 930 | + soc_pm.ws_ids = sam9x60_ws_ids; |
---|
| 931 | + soc_pm.config_pmc_ws = at91_sam9x60_config_pmc_ws; |
---|
| 932 | +} |
---|
| 933 | + |
---|
761 | 934 | void __init at91sam9_pm_init(void) |
---|
762 | 935 | { |
---|
| 936 | + int ret; |
---|
| 937 | + |
---|
763 | 938 | if (!IS_ENABLED(CONFIG_SOC_AT91SAM9)) |
---|
764 | 939 | return; |
---|
765 | 940 | |
---|
766 | | - at91_dt_ramc(); |
---|
| 941 | + /* |
---|
| 942 | + * Force STANDBY and ULP0 mode to avoid calling |
---|
| 943 | + * at91_pm_modes_validate() which may increase booting time. |
---|
| 944 | + * Platform supports anyway only STANDBY and ULP0 modes. |
---|
| 945 | + */ |
---|
| 946 | + soc_pm.data.standby_mode = AT91_PM_STANDBY; |
---|
| 947 | + soc_pm.data.suspend_mode = AT91_PM_ULP0; |
---|
| 948 | + |
---|
| 949 | + ret = at91_dt_ramc(); |
---|
| 950 | + if (ret) |
---|
| 951 | + return; |
---|
| 952 | + |
---|
767 | 953 | at91_pm_init(at91sam9_idle); |
---|
768 | 954 | } |
---|
769 | 955 | |
---|
770 | 956 | void __init sama5_pm_init(void) |
---|
771 | 957 | { |
---|
| 958 | + static const int modes[] __initconst = { |
---|
| 959 | + AT91_PM_STANDBY, AT91_PM_ULP0, AT91_PM_ULP0_FAST, |
---|
| 960 | + }; |
---|
| 961 | + int ret; |
---|
| 962 | + |
---|
772 | 963 | if (!IS_ENABLED(CONFIG_SOC_SAMA5)) |
---|
773 | 964 | return; |
---|
774 | 965 | |
---|
775 | | - at91_dt_ramc(); |
---|
| 966 | + at91_pm_modes_validate(modes, ARRAY_SIZE(modes)); |
---|
| 967 | + ret = at91_dt_ramc(); |
---|
| 968 | + if (ret) |
---|
| 969 | + return; |
---|
| 970 | + |
---|
776 | 971 | at91_pm_init(NULL); |
---|
777 | 972 | } |
---|
778 | 973 | |
---|
779 | 974 | void __init sama5d2_pm_init(void) |
---|
780 | 975 | { |
---|
| 976 | + static const int modes[] __initconst = { |
---|
| 977 | + AT91_PM_STANDBY, AT91_PM_ULP0, AT91_PM_ULP0_FAST, AT91_PM_ULP1, |
---|
| 978 | + AT91_PM_BACKUP, |
---|
| 979 | + }; |
---|
| 980 | + int ret; |
---|
| 981 | + |
---|
781 | 982 | if (!IS_ENABLED(CONFIG_SOC_SAMA5D2)) |
---|
782 | 983 | return; |
---|
783 | 984 | |
---|
| 985 | + at91_pm_modes_validate(modes, ARRAY_SIZE(modes)); |
---|
784 | 986 | at91_pm_modes_init(); |
---|
785 | | - sama5_pm_init(); |
---|
| 987 | + ret = at91_dt_ramc(); |
---|
| 988 | + if (ret) |
---|
| 989 | + return; |
---|
| 990 | + |
---|
| 991 | + at91_pm_init(NULL); |
---|
| 992 | + |
---|
| 993 | + soc_pm.ws_ids = sama5d2_ws_ids; |
---|
| 994 | + soc_pm.config_shdwc_ws = at91_sama5d2_config_shdwc_ws; |
---|
| 995 | + soc_pm.config_pmc_ws = at91_sama5d2_config_pmc_ws; |
---|
786 | 996 | } |
---|
787 | 997 | |
---|
788 | 998 | static int __init at91_pm_modes_select(char *str) |
---|
.. | .. |
---|
803 | 1013 | if (suspend < 0) |
---|
804 | 1014 | return 0; |
---|
805 | 1015 | |
---|
806 | | - pm_data.standby_mode = standby; |
---|
807 | | - pm_data.suspend_mode = suspend; |
---|
| 1016 | + soc_pm.data.standby_mode = standby; |
---|
| 1017 | + soc_pm.data.suspend_mode = suspend; |
---|
808 | 1018 | |
---|
809 | 1019 | return 0; |
---|
810 | 1020 | } |
---|