3665ac6aca76441b5af1cfc7824aab9d4041a0a4
[rpmsg/hwspinlock.git] / arch / arm / mach-omap2 / pm33xx-core.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * AM33XX Arch Power Management Routines
4  *
5  * Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/
6  *      Dave Gerlach
7  */
9 #include <asm/smp_scu.h>
10 #include <asm/suspend.h>
11 #include <linux/errno.h>
12 #include <linux/platform_data/pm33xx.h>
13 #include <linux/clk.h>
14 #include <linux/platform_data/gpio-omap.h>
15 #include <linux/pinctrl/pinmux.h>
16 #include <linux/wkup_m3_ipc.h>
17 #include <linux/of.h>
18 #include <linux/rtc.h>
20 #include "cm33xx.h"
21 #include "common.h"
22 #include "control.h"
23 #include "clockdomain.h"
24 #include "iomap.h"
25 #include "omap_hwmod.h"
26 #include "pm.h"
27 #include "powerdomain.h"
28 #include "prm33xx.h"
29 #include "soc.h"
30 #include "sram.h"
32 static struct powerdomain *cefuse_pwrdm, *gfx_pwrdm, *per_pwrdm, *mpu_pwrdm;
33 static struct clockdomain *gfx_l4ls_clkdm;
34 static void __iomem *scu_base;
35 static struct omap_hwmod *rtc_oh;
37 static int __init am43xx_map_scu(void)
38 {
39         scu_base = ioremap(scu_a9_get_base(), SZ_256);
41         if (!scu_base)
42                 return -ENOMEM;
44         return 0;
45 }
47 static int am33xx_check_off_mode_enable(void)
48 {
49         if (enable_off_mode)
50                 pr_warn("WARNING: This platform does not support off-mode, entering DeepSleep suspend.\n");
52         /* off mode not supported on am335x so return 0 always */
53         return 0;
54 }
56 static int am43xx_check_off_mode_enable(void)
57 {
58         /*
59          * Check for am437x-sk-evm which due to HW design cannot support
60          * this mode reliably.
61          */
62         if (of_machine_is_compatible("ti,am437x-sk-evm") && enable_off_mode) {
63                 pr_warn("WARNING: This platform does not support off-mode, entering DeepSleep suspend.\n");
64                 return 0;
65         }
67         return enable_off_mode;
68 }
70 static int amx3_common_init(void)
71 {
72         gfx_pwrdm = pwrdm_lookup("gfx_pwrdm");
73         per_pwrdm = pwrdm_lookup("per_pwrdm");
74         mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
76         if ((!gfx_pwrdm) || (!per_pwrdm) || (!mpu_pwrdm))
77                 return -ENODEV;
79         (void)clkdm_for_each(omap_pm_clkdms_setup, NULL);
81         /* CEFUSE domain can be turned off post bootup */
82         cefuse_pwrdm = pwrdm_lookup("cefuse_pwrdm");
83         if (cefuse_pwrdm)
84                 omap_set_pwrdm_state(cefuse_pwrdm, PWRDM_POWER_OFF);
85         else
86                 pr_err("PM: Failed to get cefuse_pwrdm\n");
88         return 0;
89 }
91 static int am33xx_suspend_init(void)
92 {
93         int ret;
95         gfx_l4ls_clkdm = clkdm_lookup("gfx_l4ls_gfx_clkdm");
97         if (!gfx_l4ls_clkdm) {
98                 pr_err("PM: Cannot lookup gfx_l4ls_clkdm clockdomains\n");
99                 return -ENODEV;
100         }
102         ret = amx3_common_init();
104         return ret;
107 static int am43xx_suspend_init(void)
109         int ret = 0;
111         ret = am43xx_map_scu();
112         if (ret) {
113                 pr_err("PM: Could not ioremap SCU\n");
114                 return ret;
115         }
117         ret = amx3_common_init();
119         return ret;
122 static void amx3_pre_suspend_common(void)
124         omap_set_pwrdm_state(gfx_pwrdm, PWRDM_POWER_OFF);
127 static void amx3_post_suspend_common(void)
129         int status;
130         /*
131          * Because gfx_pwrdm is the only one under MPU control,
132          * comment on transition status
133          */
134         status = pwrdm_read_pwrst(gfx_pwrdm);
135         if (status != PWRDM_POWER_OFF)
136                 pr_err("PM: GFX domain did not transition: %x\n", status);
139 static int am33xx_suspend(unsigned int state, int (*fn)(unsigned long),
140                           unsigned long args)
142         int ret = 0;
144         amx3_pre_suspend_common();
145         ret = cpu_suspend(args, fn);
146         amx3_post_suspend_common();
148         /*
149          * BUG: GFX_L4LS clock domain needs to be woken up to
150          * ensure thet L4LS clock domain does not get stuck in
151          * transition. If that happens L3 module does not get
152          * disabled, thereby leading to PER power domain
153          * transition failing
154          */
156         clkdm_wakeup(gfx_l4ls_clkdm);
157         clkdm_sleep(gfx_l4ls_clkdm);
159         return ret;
162 static int am43xx_suspend(unsigned int state, int (*fn)(unsigned long),
163                           unsigned long args)
165         int ret = 0;
167         amx3_pre_suspend_common();
168         scu_power_mode(scu_base, SCU_PM_POWEROFF);
169         ret = cpu_suspend(args, fn);
170         scu_power_mode(scu_base, SCU_PM_NORMAL);
172         if (!am43xx_check_off_mode_enable())
173                 amx3_post_suspend_common();
175         return ret;
178 static struct am33xx_pm_sram_addr *amx3_get_sram_addrs(void)
180         if (soc_is_am33xx())
181                 return &am33xx_pm_sram;
182         else if (soc_is_am437x())
183                 return &am43xx_pm_sram;
184         else
185                 return NULL;
188 void __iomem *am43xx_get_rtc_base_addr(void)
190         rtc_oh = omap_hwmod_lookup("rtc");
192         return omap_hwmod_get_mpu_rt_va(rtc_oh);
195 static void am43xx_save_context(void)
199 static void am33xx_save_context(void)
201         omap_intc_save_context();
204 static void am33xx_restore_context(void)
206         omap_intc_restore_context();
209 static void am43xx_restore_context(void)
211         /*
212          * HACK: restore dpll_per_clkdcoldo register contents, to avoid
213          * breaking suspend-resume
214          */
215         writel_relaxed(0x0, AM33XX_L4_WK_IO_ADDRESS(0x44df2e14));
218 static void am43xx_prepare_rtc_suspend(void)
220         omap_hwmod_enable(rtc_oh);
223 static void am43xx_prepare_rtc_resume(void)
225         omap_hwmod_idle(rtc_oh);
228 static struct am33xx_pm_platform_data am33xx_ops = {
229         .init = am33xx_suspend_init,
230         .soc_suspend = am33xx_suspend,
231         .get_sram_addrs = amx3_get_sram_addrs,
232         .save_context = am33xx_save_context,
233         .restore_context = am33xx_restore_context,
234         .prepare_rtc_suspend = am43xx_prepare_rtc_suspend,
235         .prepare_rtc_resume = am43xx_prepare_rtc_resume,
236         .check_off_mode_enable = am33xx_check_off_mode_enable,
237         .get_rtc_base_addr = am43xx_get_rtc_base_addr,
238 };
240 static struct am33xx_pm_platform_data am43xx_ops = {
241         .init = am43xx_suspend_init,
242         .soc_suspend = am43xx_suspend,
243         .get_sram_addrs = amx3_get_sram_addrs,
244         .save_context = am43xx_save_context,
245         .restore_context = am43xx_restore_context,
246         .prepare_rtc_suspend = am43xx_prepare_rtc_suspend,
247         .prepare_rtc_resume = am43xx_prepare_rtc_resume,
248         .check_off_mode_enable = am43xx_check_off_mode_enable,
249         .get_rtc_base_addr = am43xx_get_rtc_base_addr,
250 };
252 static struct am33xx_pm_platform_data *am33xx_pm_get_pdata(void)
254         if (soc_is_am33xx())
255                 return &am33xx_ops;
256         else if (soc_is_am437x())
257                 return &am43xx_ops;
258         else
259                 return NULL;
262 int __init amx3_common_pm_init(void)
264         struct am33xx_pm_platform_data *pdata;
265         struct platform_device_info devinfo;
267         pdata = am33xx_pm_get_pdata();
269         memset(&devinfo, 0, sizeof(devinfo));
270         devinfo.name = "pm33xx";
271         devinfo.data = pdata;
272         devinfo.size_data = sizeof(*pdata);
273         devinfo.id = -1;
274         platform_device_register_full(&devinfo);
276         return 0;