diff options
Diffstat (limited to 'arch/arm/mach-omap2/pm.c')
-rw-r--r-- | arch/arm/mach-omap2/pm.c | 200 |
1 files changed, 193 insertions, 7 deletions
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index 68f9f2e95891..49486f522dca 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c | |||
@@ -13,16 +13,23 @@ | |||
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/io.h> | 14 | #include <linux/io.h> |
15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/opp.h> | ||
16 | 17 | ||
17 | #include <plat/omap-pm.h> | 18 | #include <plat/omap-pm.h> |
18 | #include <plat/omap_device.h> | 19 | #include <plat/omap_device.h> |
19 | #include <plat/common.h> | 20 | #include <plat/common.h> |
20 | 21 | ||
22 | #include "voltage.h" | ||
23 | #include "powerdomain.h" | ||
24 | #include "clockdomain.h" | ||
25 | #include "pm.h" | ||
26 | |||
21 | static struct omap_device_pm_latency *pm_lats; | 27 | static struct omap_device_pm_latency *pm_lats; |
22 | 28 | ||
23 | static struct device *mpu_dev; | 29 | static struct device *mpu_dev; |
24 | static struct device *dsp_dev; | 30 | static struct device *iva_dev; |
25 | static struct device *l3_dev; | 31 | static struct device *l3_dev; |
32 | static struct device *dsp_dev; | ||
26 | 33 | ||
27 | struct device *omap2_get_mpuss_device(void) | 34 | struct device *omap2_get_mpuss_device(void) |
28 | { | 35 | { |
@@ -30,10 +37,10 @@ struct device *omap2_get_mpuss_device(void) | |||
30 | return mpu_dev; | 37 | return mpu_dev; |
31 | } | 38 | } |
32 | 39 | ||
33 | struct device *omap2_get_dsp_device(void) | 40 | struct device *omap2_get_iva_device(void) |
34 | { | 41 | { |
35 | WARN_ON_ONCE(!dsp_dev); | 42 | WARN_ON_ONCE(!iva_dev); |
36 | return dsp_dev; | 43 | return iva_dev; |
37 | } | 44 | } |
38 | 45 | ||
39 | struct device *omap2_get_l3_device(void) | 46 | struct device *omap2_get_l3_device(void) |
@@ -42,6 +49,13 @@ struct device *omap2_get_l3_device(void) | |||
42 | return l3_dev; | 49 | return l3_dev; |
43 | } | 50 | } |
44 | 51 | ||
52 | struct device *omap4_get_dsp_device(void) | ||
53 | { | ||
54 | WARN_ON_ONCE(!dsp_dev); | ||
55 | return dsp_dev; | ||
56 | } | ||
57 | EXPORT_SYMBOL(omap4_get_dsp_device); | ||
58 | |||
45 | /* static int _init_omap_device(struct omap_hwmod *oh, void *user) */ | 59 | /* static int _init_omap_device(struct omap_hwmod *oh, void *user) */ |
46 | static int _init_omap_device(char *name, struct device **new_dev) | 60 | static int _init_omap_device(char *name, struct device **new_dev) |
47 | { | 61 | { |
@@ -69,8 +83,161 @@ static int _init_omap_device(char *name, struct device **new_dev) | |||
69 | static void omap2_init_processor_devices(void) | 83 | static void omap2_init_processor_devices(void) |
70 | { | 84 | { |
71 | _init_omap_device("mpu", &mpu_dev); | 85 | _init_omap_device("mpu", &mpu_dev); |
72 | _init_omap_device("iva", &dsp_dev); | 86 | if (omap3_has_iva()) |
73 | _init_omap_device("l3_main", &l3_dev); | 87 | _init_omap_device("iva", &iva_dev); |
88 | |||
89 | if (cpu_is_omap44xx()) { | ||
90 | _init_omap_device("l3_main_1", &l3_dev); | ||
91 | _init_omap_device("dsp", &dsp_dev); | ||
92 | _init_omap_device("iva", &iva_dev); | ||
93 | } else { | ||
94 | _init_omap_device("l3_main", &l3_dev); | ||
95 | } | ||
96 | } | ||
97 | |||
98 | /* Types of sleep_switch used in omap_set_pwrdm_state */ | ||
99 | #define FORCEWAKEUP_SWITCH 0 | ||
100 | #define LOWPOWERSTATE_SWITCH 1 | ||
101 | |||
102 | /* | ||
103 | * This sets pwrdm state (other than mpu & core. Currently only ON & | ||
104 | * RET are supported. | ||
105 | */ | ||
106 | int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) | ||
107 | { | ||
108 | u32 cur_state; | ||
109 | int sleep_switch = 0; | ||
110 | int ret = 0; | ||
111 | |||
112 | if (pwrdm == NULL || IS_ERR(pwrdm)) | ||
113 | return -EINVAL; | ||
114 | |||
115 | while (!(pwrdm->pwrsts & (1 << state))) { | ||
116 | if (state == PWRDM_POWER_OFF) | ||
117 | return ret; | ||
118 | state--; | ||
119 | } | ||
120 | |||
121 | cur_state = pwrdm_read_next_pwrst(pwrdm); | ||
122 | if (cur_state == state) | ||
123 | return ret; | ||
124 | |||
125 | if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) { | ||
126 | if ((pwrdm_read_pwrst(pwrdm) > state) && | ||
127 | (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) { | ||
128 | sleep_switch = LOWPOWERSTATE_SWITCH; | ||
129 | } else { | ||
130 | clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); | ||
131 | pwrdm_wait_transition(pwrdm); | ||
132 | sleep_switch = FORCEWAKEUP_SWITCH; | ||
133 | } | ||
134 | } | ||
135 | |||
136 | ret = pwrdm_set_next_pwrst(pwrdm, state); | ||
137 | if (ret) { | ||
138 | printk(KERN_ERR "Unable to set state of powerdomain: %s\n", | ||
139 | pwrdm->name); | ||
140 | goto err; | ||
141 | } | ||
142 | |||
143 | switch (sleep_switch) { | ||
144 | case FORCEWAKEUP_SWITCH: | ||
145 | if (pwrdm->pwrdm_clkdms[0]->flags & CLKDM_CAN_ENABLE_AUTO) | ||
146 | clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); | ||
147 | else | ||
148 | clkdm_sleep(pwrdm->pwrdm_clkdms[0]); | ||
149 | break; | ||
150 | case LOWPOWERSTATE_SWITCH: | ||
151 | pwrdm_set_lowpwrstchange(pwrdm); | ||
152 | break; | ||
153 | default: | ||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | pwrdm_wait_transition(pwrdm); | ||
158 | pwrdm_state_switch(pwrdm); | ||
159 | err: | ||
160 | return ret; | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * This API is to be called during init to put the various voltage | ||
165 | * domains to the voltage as per the opp table. Typically we boot up | ||
166 | * at the nominal voltage. So this function finds out the rate of | ||
167 | * the clock associated with the voltage domain, finds out the correct | ||
168 | * opp entry and puts the voltage domain to the voltage specifies | ||
169 | * in the opp entry | ||
170 | */ | ||
171 | static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name, | ||
172 | struct device *dev) | ||
173 | { | ||
174 | struct voltagedomain *voltdm; | ||
175 | struct clk *clk; | ||
176 | struct opp *opp; | ||
177 | unsigned long freq, bootup_volt; | ||
178 | |||
179 | if (!vdd_name || !clk_name || !dev) { | ||
180 | printk(KERN_ERR "%s: Invalid parameters!\n", __func__); | ||
181 | goto exit; | ||
182 | } | ||
183 | |||
184 | voltdm = omap_voltage_domain_lookup(vdd_name); | ||
185 | if (IS_ERR(voltdm)) { | ||
186 | printk(KERN_ERR "%s: Unable to get vdd pointer for vdd_%s\n", | ||
187 | __func__, vdd_name); | ||
188 | goto exit; | ||
189 | } | ||
190 | |||
191 | clk = clk_get(NULL, clk_name); | ||
192 | if (IS_ERR(clk)) { | ||
193 | printk(KERN_ERR "%s: unable to get clk %s\n", | ||
194 | __func__, clk_name); | ||
195 | goto exit; | ||
196 | } | ||
197 | |||
198 | freq = clk->rate; | ||
199 | clk_put(clk); | ||
200 | |||
201 | opp = opp_find_freq_ceil(dev, &freq); | ||
202 | if (IS_ERR(opp)) { | ||
203 | printk(KERN_ERR "%s: unable to find boot up OPP for vdd_%s\n", | ||
204 | __func__, vdd_name); | ||
205 | goto exit; | ||
206 | } | ||
207 | |||
208 | bootup_volt = opp_get_voltage(opp); | ||
209 | if (!bootup_volt) { | ||
210 | printk(KERN_ERR "%s: unable to find voltage corresponding" | ||
211 | "to the bootup OPP for vdd_%s\n", __func__, vdd_name); | ||
212 | goto exit; | ||
213 | } | ||
214 | |||
215 | omap_voltage_scale_vdd(voltdm, bootup_volt); | ||
216 | return 0; | ||
217 | |||
218 | exit: | ||
219 | printk(KERN_ERR "%s: Unable to put vdd_%s to its init voltage\n\n", | ||
220 | __func__, vdd_name); | ||
221 | return -EINVAL; | ||
222 | } | ||
223 | |||
224 | static void __init omap3_init_voltages(void) | ||
225 | { | ||
226 | if (!cpu_is_omap34xx()) | ||
227 | return; | ||
228 | |||
229 | omap2_set_init_voltage("mpu", "dpll1_ck", mpu_dev); | ||
230 | omap2_set_init_voltage("core", "l3_ick", l3_dev); | ||
231 | } | ||
232 | |||
233 | static void __init omap4_init_voltages(void) | ||
234 | { | ||
235 | if (!cpu_is_omap44xx()) | ||
236 | return; | ||
237 | |||
238 | omap2_set_init_voltage("mpu", "dpll_mpu_ck", mpu_dev); | ||
239 | omap2_set_init_voltage("core", "l3_div_ck", l3_dev); | ||
240 | omap2_set_init_voltage("iva", "dpll_iva_m5x2_ck", iva_dev); | ||
74 | } | 241 | } |
75 | 242 | ||
76 | static int __init omap2_common_pm_init(void) | 243 | static int __init omap2_common_pm_init(void) |
@@ -80,5 +247,24 @@ static int __init omap2_common_pm_init(void) | |||
80 | 247 | ||
81 | return 0; | 248 | return 0; |
82 | } | 249 | } |
83 | device_initcall(omap2_common_pm_init); | 250 | postcore_initcall(omap2_common_pm_init); |
84 | 251 | ||
252 | static int __init omap2_common_pm_late_init(void) | ||
253 | { | ||
254 | /* Init the OMAP TWL parameters */ | ||
255 | omap3_twl_init(); | ||
256 | omap4_twl_init(); | ||
257 | |||
258 | /* Init the voltage layer */ | ||
259 | omap_voltage_late_init(); | ||
260 | |||
261 | /* Initialize the voltages */ | ||
262 | omap3_init_voltages(); | ||
263 | omap4_init_voltages(); | ||
264 | |||
265 | /* Smartreflex device init */ | ||
266 | omap_devinit_smartreflex(); | ||
267 | |||
268 | return 0; | ||
269 | } | ||
270 | late_initcall(omap2_common_pm_late_init); | ||