Loading...
Note: File does not exist in v3.5.6.
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 */
8
9#include <asm/smp_scu.h>
10#include <asm/suspend.h>
11#include <linux/errno.h>
12#include <linux/platform_data/pm33xx.h>
13
14#include "cm33xx.h"
15#include "common.h"
16#include "control.h"
17#include "clockdomain.h"
18#include "iomap.h"
19#include "omap_hwmod.h"
20#include "pm.h"
21#include "powerdomain.h"
22#include "prm33xx.h"
23#include "soc.h"
24#include "sram.h"
25
26static struct powerdomain *cefuse_pwrdm, *gfx_pwrdm, *per_pwrdm, *mpu_pwrdm;
27static struct clockdomain *gfx_l4ls_clkdm;
28static void __iomem *scu_base;
29
30static int __init am43xx_map_scu(void)
31{
32 scu_base = ioremap(scu_a9_get_base(), SZ_256);
33
34 if (!scu_base)
35 return -ENOMEM;
36
37 return 0;
38}
39
40static int amx3_common_init(void)
41{
42 gfx_pwrdm = pwrdm_lookup("gfx_pwrdm");
43 per_pwrdm = pwrdm_lookup("per_pwrdm");
44 mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
45
46 if ((!gfx_pwrdm) || (!per_pwrdm) || (!mpu_pwrdm))
47 return -ENODEV;
48
49 (void)clkdm_for_each(omap_pm_clkdms_setup, NULL);
50
51 /* CEFUSE domain can be turned off post bootup */
52 cefuse_pwrdm = pwrdm_lookup("cefuse_pwrdm");
53 if (cefuse_pwrdm)
54 omap_set_pwrdm_state(cefuse_pwrdm, PWRDM_POWER_OFF);
55 else
56 pr_err("PM: Failed to get cefuse_pwrdm\n");
57
58 return 0;
59}
60
61static int am33xx_suspend_init(void)
62{
63 int ret;
64
65 gfx_l4ls_clkdm = clkdm_lookup("gfx_l4ls_gfx_clkdm");
66
67 if (!gfx_l4ls_clkdm) {
68 pr_err("PM: Cannot lookup gfx_l4ls_clkdm clockdomains\n");
69 return -ENODEV;
70 }
71
72 ret = amx3_common_init();
73
74 return ret;
75}
76
77static int am43xx_suspend_init(void)
78{
79 int ret = 0;
80
81 ret = am43xx_map_scu();
82 if (ret) {
83 pr_err("PM: Could not ioremap SCU\n");
84 return ret;
85 }
86
87 ret = amx3_common_init();
88
89 return ret;
90}
91
92static void amx3_pre_suspend_common(void)
93{
94 omap_set_pwrdm_state(gfx_pwrdm, PWRDM_POWER_OFF);
95}
96
97static void amx3_post_suspend_common(void)
98{
99 int status;
100 /*
101 * Because gfx_pwrdm is the only one under MPU control,
102 * comment on transition status
103 */
104 status = pwrdm_read_pwrst(gfx_pwrdm);
105 if (status != PWRDM_POWER_OFF)
106 pr_err("PM: GFX domain did not transition: %x\n", status);
107}
108
109static int am33xx_suspend(unsigned int state, int (*fn)(unsigned long))
110{
111 int ret = 0;
112
113 amx3_pre_suspend_common();
114 ret = cpu_suspend(0, fn);
115 amx3_post_suspend_common();
116
117 /*
118 * BUG: GFX_L4LS clock domain needs to be woken up to
119 * ensure thet L4LS clock domain does not get stuck in
120 * transition. If that happens L3 module does not get
121 * disabled, thereby leading to PER power domain
122 * transition failing
123 */
124
125 clkdm_wakeup(gfx_l4ls_clkdm);
126 clkdm_sleep(gfx_l4ls_clkdm);
127
128 return ret;
129}
130
131static int am43xx_suspend(unsigned int state, int (*fn)(unsigned long))
132{
133 int ret = 0;
134
135 amx3_pre_suspend_common();
136 scu_power_mode(scu_base, SCU_PM_POWEROFF);
137 ret = cpu_suspend(0, fn);
138 scu_power_mode(scu_base, SCU_PM_NORMAL);
139 amx3_post_suspend_common();
140
141 return ret;
142}
143
144static struct am33xx_pm_sram_addr *amx3_get_sram_addrs(void)
145{
146 if (soc_is_am33xx())
147 return &am33xx_pm_sram;
148 else if (soc_is_am437x())
149 return &am43xx_pm_sram;
150 else
151 return NULL;
152}
153
154static struct am33xx_pm_platform_data am33xx_ops = {
155 .init = am33xx_suspend_init,
156 .soc_suspend = am33xx_suspend,
157 .get_sram_addrs = amx3_get_sram_addrs,
158};
159
160static struct am33xx_pm_platform_data am43xx_ops = {
161 .init = am43xx_suspend_init,
162 .soc_suspend = am43xx_suspend,
163 .get_sram_addrs = amx3_get_sram_addrs,
164};
165
166static struct am33xx_pm_platform_data *am33xx_pm_get_pdata(void)
167{
168 if (soc_is_am33xx())
169 return &am33xx_ops;
170 else if (soc_is_am437x())
171 return &am43xx_ops;
172 else
173 return NULL;
174}
175
176void __init amx3_common_pm_init(void)
177{
178 struct am33xx_pm_platform_data *pdata;
179 struct platform_device_info devinfo;
180
181 pdata = am33xx_pm_get_pdata();
182
183 memset(&devinfo, 0, sizeof(devinfo));
184 devinfo.name = "pm33xx";
185 devinfo.data = pdata;
186 devinfo.size_data = sizeof(*pdata);
187 devinfo.id = -1;
188 platform_device_register_full(&devinfo);
189}