Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
omap-pm-noop.c
Go to the documentation of this file.
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 int dummy_context_loss_counter;
31 
32 /*
33  * Device-driver-originated constraints (via board-*.c files)
34  */
35 
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: dev %s\n",
45  dev_name(dev));
46  else
47  pr_debug("OMAP PM: add max MPU wakeup latency constraint: dev %s, t = %ld usec\n",
48  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: dev %s for agent_id %d\n",
74  dev_name(dev), agent_id);
75  else
76  pr_debug("OMAP PM: add min bus tput constraint: dev %s for agent_id %d: rate %ld KiB\n",
77  dev_name(dev), agent_id, r);
78 
79  /*
80  * This code should model the interconnect and compute the
81  * required clock frequency, convert that to a VDD2 OPP ID, then
82  * set the VDD2 OPP appropriately.
83  *
84  * TI CDP code can call constraint_set here on the VDD2 OPP.
85  */
86 
87  return 0;
88 }
89 
90 int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev,
91  long t)
92 {
93  if (!req_dev || !dev || t < -1) {
94  WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
95  return -EINVAL;
96  }
97 
98  if (t == -1)
99  pr_debug("OMAP PM: remove max device latency constraint: dev %s\n",
100  dev_name(dev));
101  else
102  pr_debug("OMAP PM: add max device latency constraint: dev %s, t = %ld usec\n",
103  dev_name(dev), t);
104 
105  /*
106  * For current Linux, this needs to map the device to a
107  * powerdomain, then go through the list of current max lat
108  * constraints on that powerdomain and find the smallest. If
109  * the latency constraint has changed, the code should
110  * recompute the state to enter for the next powerdomain
111  * state. Conceivably, this code should also determine
112  * whether to actually disable the device clocks or not,
113  * depending on how long it takes to re-enable the clocks.
114  *
115  * TI CDP code can call constraint_set here.
116  */
117 
118  return 0;
119 }
120 
122 {
123  if (!dev || t < -1) {
124  WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
125  return -EINVAL;
126  }
127 
128  if (t == -1)
129  pr_debug("OMAP PM: remove max DMA latency constraint: dev %s\n",
130  dev_name(dev));
131  else
132  pr_debug("OMAP PM: add max DMA latency constraint: dev %s, t = %ld usec\n",
133  dev_name(dev), t);
134 
135  /*
136  * For current Linux PM QOS params, this code should scan the
137  * list of maximum CPU and DMA latencies and select the
138  * smallest, then set cpu_dma_latency pm_qos_param
139  * accordingly.
140  *
141  * For future Linux PM QOS params, with separate CPU and DMA
142  * latency params, this code should just set the dma_latency param.
143  *
144  * TI CDP code can call constraint_set here.
145  */
146 
147  return 0;
148 }
149 
150 int omap_pm_set_min_clk_rate(struct device *dev, struct clk *c, long r)
151 {
152  if (!dev || !c || r < 0) {
153  WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
154  return -EINVAL;
155  }
156 
157  if (r == 0)
158  pr_debug("OMAP PM: remove min clk rate constraint: dev %s\n",
159  dev_name(dev));
160  else
161  pr_debug("OMAP PM: add min clk rate constraint: dev %s, rate = %ld Hz\n",
162  dev_name(dev), r);
163 
164  /*
165  * Code in a real implementation should keep track of these
166  * constraints on the clock, and determine the highest minimum
167  * clock rate. It should iterate over each OPP and determine
168  * whether the OPP will result in a clock rate that would
169  * satisfy this constraint (and any other PM constraint in effect
170  * at that time). Once it finds the lowest-voltage OPP that
171  * meets those conditions, it should switch to it, or return
172  * an error if the code is not capable of doing so.
173  */
174 
175  return 0;
176 }
177 
178 /*
179  * DSP Bridge-specific constraints
180  */
181 
182 const struct omap_opp *omap_pm_dsp_get_opp_table(void)
183 {
184  pr_debug("OMAP PM: DSP request for OPP table\n");
185 
186  /*
187  * Return DSP frequency table here: The final item in the
188  * array should have .rate = .opp_id = 0.
189  */
190 
191  return NULL;
192 }
193 
195 {
196  if (opp_id == 0) {
197  WARN_ON(1);
198  return;
199  }
200 
201  pr_debug("OMAP PM: DSP requests minimum VDD1 OPP to be %d\n", opp_id);
202 
203  /*
204  *
205  * For l-o dev tree, our VDD1 clk is keyed on OPP ID, so we
206  * can just test to see which is higher, the CPU's desired OPP
207  * ID or the DSP's desired OPP ID, and use whichever is
208  * highest.
209  *
210  * In CDP12.14+, the VDD1 OPP custom clock that controls the DSP
211  * rate is keyed on MPU speed, not the OPP ID. So we need to
212  * map the OPP ID to the MPU speed for use with clk_set_rate()
213  * if it is higher than the current OPP clock rate.
214  *
215  */
216 }
217 
218 
220 {
221  pr_debug("OMAP PM: DSP requests current DSP OPP ID\n");
222 
223  /*
224  * For l-o dev tree, call clk_get_rate() on VDD1 OPP clock
225  *
226  * CDP12.14+:
227  * Call clk_get_rate() on the OPP custom clock, map that to an
228  * OPP ID using the tables defined in board-*.c/chip-*.c files.
229  */
230 
231  return 0;
232 }
233 
234 /*
235  * CPUFreq-originated constraint
236  *
237  * In the future, this should be handled by custom OPP clocktype
238  * functions.
239  */
240 
242 {
243  pr_debug("OMAP PM: CPUFreq request for frequency table\n");
244 
245  /*
246  * Return CPUFreq frequency table here: loop over
247  * all VDD1 clkrates, pull out the mpu_ck frequencies, build
248  * table
249  */
250 
251  return NULL;
252 }
253 
254 void omap_pm_cpu_set_freq(unsigned long f)
255 {
256  if (f == 0) {
257  WARN_ON(1);
258  return;
259  }
260 
261  pr_debug("OMAP PM: CPUFreq requests CPU frequency to be set to %lu\n",
262  f);
263 
264  /*
265  * For l-o dev tree, determine whether MPU freq or DSP OPP id
266  * freq is higher. Find the OPP ID corresponding to the
267  * higher frequency. Call clk_round_rate() and clk_set_rate()
268  * on the OPP custom clock.
269  *
270  * CDP should just be able to set the VDD1 OPP clock rate here.
271  */
272 }
273 
274 unsigned long omap_pm_cpu_get_freq(void)
275 {
276  pr_debug("OMAP PM: CPUFreq requests current CPU frequency\n");
277 
278  /*
279  * Call clk_get_rate() on the mpu_ck.
280  */
281 
282  return 0;
283 }
284 
292 {
293  off_mode_enabled = true;
294 }
295 
303 {
304  off_mode_enabled = false;
305 }
306 
307 /*
308  * Device context loss tracking
309  */
310 
311 #ifdef CONFIG_ARCH_OMAP2PLUS
312 
314 {
315  struct platform_device *pdev = to_platform_device(dev);
316  int count;
317 
318  if (WARN_ON(!dev))
319  return -ENODEV;
320 
321  if (dev->pm_domain == &omap_device_pm_domain) {
323  } else {
324  WARN_ONCE(off_mode_enabled, "omap_pm: using dummy context loss counter; device %s should be converted to omap_device",
325  dev_name(dev));
326 
327  count = dummy_context_loss_counter;
328 
329  if (off_mode_enabled) {
330  count++;
331  /*
332  * Context loss count has to be a non-negative value.
333  * Clear the sign bit to get a value range from 0 to
334  * INT_MAX.
335  */
336  count &= INT_MAX;
337  dummy_context_loss_counter = count;
338  }
339  }
340 
341  pr_debug("OMAP PM: context loss count for dev %s = %d\n",
342  dev_name(dev), count);
343 
344  return count;
345 }
346 
347 #else
348 
350 {
351  return dummy_context_loss_counter;
352 }
353 
354 #endif
355 
356 /* Should be called before clk framework init */
358 {
359  return 0;
360 }
361 
362 /* Must be called after clock framework is initialized */
364 {
365  return 0;
366 }
367 
368 void omap_pm_if_exit(void)
369 {
370  /* Deallocate CPUFreq frequency table here */
371 }
372