diff options
Diffstat (limited to 'arch/arm/plat-omap/omap-pm-noop.c')
-rw-r--r-- | arch/arm/plat-omap/omap-pm-noop.c | 363 |
1 files changed, 363 insertions, 0 deletions
diff --git a/arch/arm/plat-omap/omap-pm-noop.c b/arch/arm/plat-omap/omap-pm-noop.c new file mode 100644 index 00000000000..b0471bb2d47 --- /dev/null +++ b/arch/arm/plat-omap/omap-pm-noop.c | |||
@@ -0,0 +1,363 @@ | |||
1 | /* | ||
2 | * omap-pm-noop.c - OMAP power management interface - dummy version | ||
3 | * | ||
4 | * This code implements the OMAP power management interface to | ||
5 | * drivers, CPUIdle, CPUFreq, and DSP Bridge. It is strictly for | ||
6 | * debug/demonstration use, as it does nothing but printk() whenever a | ||
7 | * function is called (when DEBUG is defined, below) | ||
8 | * | ||
9 | * Copyright (C) 2008-2009 Texas Instruments, Inc. | ||
10 | * Copyright (C) 2008-2009 Nokia Corporation | ||
11 | * Paul Walmsley | ||
12 | * | ||
13 | * Interface developed by (in alphabetical order): | ||
14 | * Karthik Dasu, Tony Lindgren, Rajendra Nayak, Sakari Poussa, Veeramanikandan | ||
15 | * Raju, Anand Sawant, Igor Stoppa, Paul Walmsley, Richard Woodruff | ||
16 | */ | ||
17 | |||
18 | #undef DEBUG | ||
19 | |||
20 | #include <linux/init.h> | ||
21 | #include <linux/cpufreq.h> | ||
22 | #include <linux/device.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | |||
25 | /* Interface documentation is in mach/omap-pm.h */ | ||
26 | #include <plat/omap-pm.h> | ||
27 | #include <plat/omap_device.h> | ||
28 | |||
29 | static bool off_mode_enabled; | ||
30 | static u32 dummy_context_loss_counter; | ||
31 | |||
32 | /* | ||
33 | * Device-driver-originated constraints (via board-*.c files) | ||
34 | */ | ||
35 | |||
36 | int omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t) | ||
37 | { | ||
38 | if (!dev || t < -1) { | ||
39 | WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); | ||
40 | return -EINVAL; | ||
41 | }; | ||
42 | |||
43 | if (t == -1) | ||
44 | pr_debug("OMAP PM: remove max MPU wakeup latency constraint: " | ||
45 | "dev %s\n", dev_name(dev)); | ||
46 | else | ||
47 | pr_debug("OMAP PM: add max MPU wakeup latency constraint: " | ||
48 | "dev %s, t = %ld usec\n", dev_name(dev), t); | ||
49 | |||
50 | /* | ||
51 | * For current Linux, this needs to map the MPU to a | ||
52 | * powerdomain, then go through the list of current max lat | ||
53 | * constraints on the MPU and find the smallest. If | ||
54 | * the latency constraint has changed, the code should | ||
55 | * recompute the state to enter for the next powerdomain | ||
56 | * state. | ||
57 | * | ||
58 | * TI CDP code can call constraint_set here. | ||
59 | */ | ||
60 | |||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r) | ||
65 | { | ||
66 | if (!dev || (agent_id != OCP_INITIATOR_AGENT && | ||
67 | agent_id != OCP_TARGET_AGENT)) { | ||
68 | WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); | ||
69 | return -EINVAL; | ||
70 | }; | ||
71 | |||
72 | if (r == 0) | ||
73 | pr_debug("OMAP PM: remove min bus tput constraint: " | ||
74 | "dev %s for agent_id %d\n", dev_name(dev), agent_id); | ||
75 | else | ||
76 | pr_debug("OMAP PM: add min bus tput constraint: " | ||
77 | "dev %s for agent_id %d: rate %ld KiB\n", | ||
78 | dev_name(dev), agent_id, r); | ||
79 | |||
80 | /* | ||
81 | * This code should model the interconnect and compute the | ||
82 | * required clock frequency, convert that to a VDD2 OPP ID, then | ||
83 | * set the VDD2 OPP appropriately. | ||
84 | * | ||
85 | * TI CDP code can call constraint_set here on the VDD2 OPP. | ||
86 | */ | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev, | ||
92 | long t) | ||
93 | { | ||
94 | if (!req_dev || !dev || t < -1) { | ||
95 | WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); | ||
96 | return -EINVAL; | ||
97 | }; | ||
98 | |||
99 | if (t == -1) | ||
100 | pr_debug("OMAP PM: remove max device latency constraint: " | ||
101 | "dev %s\n", dev_name(dev)); | ||
102 | else | ||
103 | pr_debug("OMAP PM: add max device latency constraint: " | ||
104 | "dev %s, t = %ld usec\n", dev_name(dev), t); | ||
105 | |||
106 | /* | ||
107 | * For current Linux, this needs to map the device to a | ||
108 | * powerdomain, then go through the list of current max lat | ||
109 | * constraints on that powerdomain and find the smallest. If | ||
110 | * the latency constraint has changed, the code should | ||
111 | * recompute the state to enter for the next powerdomain | ||
112 | * state. Conceivably, this code should also determine | ||
113 | * whether to actually disable the device clocks or not, | ||
114 | * depending on how long it takes to re-enable the clocks. | ||
115 | * | ||
116 | * TI CDP code can call constraint_set here. | ||
117 | */ | ||
118 | |||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | int omap_pm_set_max_sdma_lat(struct device *dev, long t) | ||
123 | { | ||
124 | if (!dev || t < -1) { | ||
125 | WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); | ||
126 | return -EINVAL; | ||
127 | }; | ||
128 | |||
129 | if (t == -1) | ||
130 | pr_debug("OMAP PM: remove max DMA latency constraint: " | ||
131 | "dev %s\n", dev_name(dev)); | ||
132 | else | ||
133 | pr_debug("OMAP PM: add max DMA latency constraint: " | ||
134 | "dev %s, t = %ld usec\n", dev_name(dev), t); | ||
135 | |||
136 | /* | ||
137 | * For current Linux PM QOS params, this code should scan the | ||
138 | * list of maximum CPU and DMA latencies and select the | ||
139 | * smallest, then set cpu_dma_latency pm_qos_param | ||
140 | * accordingly. | ||
141 | * | ||
142 | * For future Linux PM QOS params, with separate CPU and DMA | ||
143 | * latency params, this code should just set the dma_latency param. | ||
144 | * | ||
145 | * TI CDP code can call constraint_set here. | ||
146 | */ | ||
147 | |||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | int omap_pm_set_min_clk_rate(struct device *dev, struct clk *c, long r) | ||
152 | { | ||
153 | if (!dev || !c || r < 0) { | ||
154 | WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); | ||
155 | return -EINVAL; | ||
156 | } | ||
157 | |||
158 | if (r == 0) | ||
159 | pr_debug("OMAP PM: remove min clk rate constraint: " | ||
160 | "dev %s\n", dev_name(dev)); | ||
161 | else | ||
162 | pr_debug("OMAP PM: add min clk rate constraint: " | ||
163 | "dev %s, rate = %ld Hz\n", dev_name(dev), r); | ||
164 | |||
165 | /* | ||
166 | * Code in a real implementation should keep track of these | ||
167 | * constraints on the clock, and determine the highest minimum | ||
168 | * clock rate. It should iterate over each OPP and determine | ||
169 | * whether the OPP will result in a clock rate that would | ||
170 | * satisfy this constraint (and any other PM constraint in effect | ||
171 | * at that time). Once it finds the lowest-voltage OPP that | ||
172 | * meets those conditions, it should switch to it, or return | ||
173 | * an error if the code is not capable of doing so. | ||
174 | */ | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | /* | ||
180 | * DSP Bridge-specific constraints | ||
181 | */ | ||
182 | |||
183 | const struct omap_opp *omap_pm_dsp_get_opp_table(void) | ||
184 | { | ||
185 | pr_debug("OMAP PM: DSP request for OPP table\n"); | ||
186 | |||
187 | /* | ||
188 | * Return DSP frequency table here: The final item in the | ||
189 | * array should have .rate = .opp_id = 0. | ||
190 | */ | ||
191 | |||
192 | return NULL; | ||
193 | } | ||
194 | |||
195 | void omap_pm_dsp_set_min_opp(u8 opp_id) | ||
196 | { | ||
197 | if (opp_id == 0) { | ||
198 | WARN_ON(1); | ||
199 | return; | ||
200 | } | ||
201 | |||
202 | pr_debug("OMAP PM: DSP requests minimum VDD1 OPP to be %d\n", opp_id); | ||
203 | |||
204 | /* | ||
205 | * | ||
206 | * For l-o dev tree, our VDD1 clk is keyed on OPP ID, so we | ||
207 | * can just test to see which is higher, the CPU's desired OPP | ||
208 | * ID or the DSP's desired OPP ID, and use whichever is | ||
209 | * highest. | ||
210 | * | ||
211 | * In CDP12.14+, the VDD1 OPP custom clock that controls the DSP | ||
212 | * rate is keyed on MPU speed, not the OPP ID. So we need to | ||
213 | * map the OPP ID to the MPU speed for use with clk_set_rate() | ||
214 | * if it is higher than the current OPP clock rate. | ||
215 | * | ||
216 | */ | ||
217 | } | ||
218 | |||
219 | |||
220 | u8 omap_pm_dsp_get_opp(void) | ||
221 | { | ||
222 | pr_debug("OMAP PM: DSP requests current DSP OPP ID\n"); | ||
223 | |||
224 | /* | ||
225 | * For l-o dev tree, call clk_get_rate() on VDD1 OPP clock | ||
226 | * | ||
227 | * CDP12.14+: | ||
228 | * Call clk_get_rate() on the OPP custom clock, map that to an | ||
229 | * OPP ID using the tables defined in board-*.c/chip-*.c files. | ||
230 | */ | ||
231 | |||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | /* | ||
236 | * CPUFreq-originated constraint | ||
237 | * | ||
238 | * In the future, this should be handled by custom OPP clocktype | ||
239 | * functions. | ||
240 | */ | ||
241 | |||
242 | struct cpufreq_frequency_table **omap_pm_cpu_get_freq_table(void) | ||
243 | { | ||
244 | pr_debug("OMAP PM: CPUFreq request for frequency table\n"); | ||
245 | |||
246 | /* | ||
247 | * Return CPUFreq frequency table here: loop over | ||
248 | * all VDD1 clkrates, pull out the mpu_ck frequencies, build | ||
249 | * table | ||
250 | */ | ||
251 | |||
252 | return NULL; | ||
253 | } | ||
254 | |||
255 | void omap_pm_cpu_set_freq(unsigned long f) | ||
256 | { | ||
257 | if (f == 0) { | ||
258 | WARN_ON(1); | ||
259 | return; | ||
260 | } | ||
261 | |||
262 | pr_debug("OMAP PM: CPUFreq requests CPU frequency to be set to %lu\n", | ||
263 | f); | ||
264 | |||
265 | /* | ||
266 | * For l-o dev tree, determine whether MPU freq or DSP OPP id | ||
267 | * freq is higher. Find the OPP ID corresponding to the | ||
268 | * higher frequency. Call clk_round_rate() and clk_set_rate() | ||
269 | * on the OPP custom clock. | ||
270 | * | ||
271 | * CDP should just be able to set the VDD1 OPP clock rate here. | ||
272 | */ | ||
273 | } | ||
274 | |||
275 | unsigned long omap_pm_cpu_get_freq(void) | ||
276 | { | ||
277 | pr_debug("OMAP PM: CPUFreq requests current CPU frequency\n"); | ||
278 | |||
279 | /* | ||
280 | * Call clk_get_rate() on the mpu_ck. | ||
281 | */ | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | /** | ||
287 | * omap_pm_enable_off_mode - notify OMAP PM that off-mode is enabled | ||
288 | * | ||
289 | * Intended for use only by OMAP PM core code to notify this layer | ||
290 | * that off mode has been enabled. | ||
291 | */ | ||
292 | void omap_pm_enable_off_mode(void) | ||
293 | { | ||
294 | off_mode_enabled = true; | ||
295 | } | ||
296 | |||
297 | /** | ||
298 | * omap_pm_disable_off_mode - notify OMAP PM that off-mode is disabled | ||
299 | * | ||
300 | * Intended for use only by OMAP PM core code to notify this layer | ||
301 | * that off mode has been disabled. | ||
302 | */ | ||
303 | void omap_pm_disable_off_mode(void) | ||
304 | { | ||
305 | off_mode_enabled = false; | ||
306 | } | ||
307 | |||
308 | /* | ||
309 | * Device context loss tracking | ||
310 | */ | ||
311 | |||
312 | #ifdef CONFIG_ARCH_OMAP2PLUS | ||
313 | |||
314 | u32 omap_pm_get_dev_context_loss_count(struct device *dev) | ||
315 | { | ||
316 | struct platform_device *pdev = to_platform_device(dev); | ||
317 | u32 count; | ||
318 | |||
319 | if (WARN_ON(!dev)) | ||
320 | return 0; | ||
321 | |||
322 | if (dev->parent == &omap_device_parent) { | ||
323 | count = omap_device_get_context_loss_count(pdev); | ||
324 | } else { | ||
325 | WARN_ONCE(off_mode_enabled, "omap_pm: using dummy context loss counter; device %s should be converted to omap_device", | ||
326 | dev_name(dev)); | ||
327 | if (off_mode_enabled) | ||
328 | dummy_context_loss_counter++; | ||
329 | count = dummy_context_loss_counter; | ||
330 | } | ||
331 | |||
332 | pr_debug("OMAP PM: context loss count for dev %s = %d\n", | ||
333 | dev_name(dev), count); | ||
334 | |||
335 | return count; | ||
336 | } | ||
337 | |||
338 | #else | ||
339 | |||
340 | u32 omap_pm_get_dev_context_loss_count(struct device *dev) | ||
341 | { | ||
342 | return dummy_context_loss_counter; | ||
343 | } | ||
344 | |||
345 | #endif | ||
346 | |||
347 | /* Should be called before clk framework init */ | ||
348 | int __init omap_pm_if_early_init(void) | ||
349 | { | ||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | /* Must be called after clock framework is initialized */ | ||
354 | int __init omap_pm_if_init(void) | ||
355 | { | ||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | void omap_pm_if_exit(void) | ||
360 | { | ||
361 | /* Deallocate CPUFreq frequency table here */ | ||
362 | } | ||
363 | |||