Commit | Line | Data |
---|---|---|
c0407a96 PW |
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 | ||
24 | /* Interface documentation is in mach/omap-pm.h */ | |
ce491cf8 | 25 | #include <plat/omap-pm.h> |
c0407a96 | 26 | |
ce491cf8 | 27 | #include <plat/powerdomain.h> |
c0407a96 PW |
28 | |
29 | struct omap_opp *dsp_opps; | |
30 | struct omap_opp *mpu_opps; | |
31 | struct omap_opp *l3_opps; | |
32 | ||
33 | /* | |
34 | * Device-driver-originated constraints (via board-*.c files) | |
35 | */ | |
36 | ||
564889c1 | 37 | int omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t) |
c0407a96 PW |
38 | { |
39 | if (!dev || t < -1) { | |
564889c1 PW |
40 | WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); |
41 | return -EINVAL; | |
c0407a96 PW |
42 | }; |
43 | ||
44 | if (t == -1) | |
45 | pr_debug("OMAP PM: remove max MPU wakeup latency constraint: " | |
46 | "dev %s\n", dev_name(dev)); | |
47 | else | |
48 | pr_debug("OMAP PM: add max MPU wakeup latency constraint: " | |
49 | "dev %s, t = %ld usec\n", dev_name(dev), t); | |
50 | ||
51 | /* | |
52 | * For current Linux, this needs to map the MPU to a | |
53 | * powerdomain, then go through the list of current max lat | |
54 | * constraints on the MPU and find the smallest. If | |
55 | * the latency constraint has changed, the code should | |
56 | * recompute the state to enter for the next powerdomain | |
57 | * state. | |
58 | * | |
59 | * TI CDP code can call constraint_set here. | |
60 | */ | |
564889c1 PW |
61 | |
62 | return 0; | |
c0407a96 PW |
63 | } |
64 | ||
564889c1 | 65 | int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r) |
c0407a96 PW |
66 | { |
67 | if (!dev || (agent_id != OCP_INITIATOR_AGENT && | |
68 | agent_id != OCP_TARGET_AGENT)) { | |
564889c1 PW |
69 | WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); |
70 | return -EINVAL; | |
c0407a96 PW |
71 | }; |
72 | ||
73 | if (r == 0) | |
74 | pr_debug("OMAP PM: remove min bus tput constraint: " | |
75 | "dev %s for agent_id %d\n", dev_name(dev), agent_id); | |
76 | else | |
77 | pr_debug("OMAP PM: add min bus tput constraint: " | |
78 | "dev %s for agent_id %d: rate %ld KiB\n", | |
79 | dev_name(dev), agent_id, r); | |
80 | ||
81 | /* | |
82 | * This code should model the interconnect and compute the | |
83 | * required clock frequency, convert that to a VDD2 OPP ID, then | |
84 | * set the VDD2 OPP appropriately. | |
85 | * | |
86 | * TI CDP code can call constraint_set here on the VDD2 OPP. | |
87 | */ | |
564889c1 PW |
88 | |
89 | return 0; | |
c0407a96 PW |
90 | } |
91 | ||
564889c1 PW |
92 | int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev, |
93 | long t) | |
c0407a96 | 94 | { |
564889c1 PW |
95 | if (!req_dev || !dev || t < -1) { |
96 | WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); | |
97 | return -EINVAL; | |
c0407a96 PW |
98 | }; |
99 | ||
100 | if (t == -1) | |
101 | pr_debug("OMAP PM: remove max device latency constraint: " | |
102 | "dev %s\n", dev_name(dev)); | |
103 | else | |
104 | pr_debug("OMAP PM: add max device latency constraint: " | |
105 | "dev %s, t = %ld usec\n", dev_name(dev), t); | |
106 | ||
107 | /* | |
108 | * For current Linux, this needs to map the device to a | |
109 | * powerdomain, then go through the list of current max lat | |
110 | * constraints on that powerdomain and find the smallest. If | |
111 | * the latency constraint has changed, the code should | |
112 | * recompute the state to enter for the next powerdomain | |
113 | * state. Conceivably, this code should also determine | |
114 | * whether to actually disable the device clocks or not, | |
115 | * depending on how long it takes to re-enable the clocks. | |
116 | * | |
117 | * TI CDP code can call constraint_set here. | |
118 | */ | |
564889c1 PW |
119 | |
120 | return 0; | |
c0407a96 PW |
121 | } |
122 | ||
564889c1 | 123 | int omap_pm_set_max_sdma_lat(struct device *dev, long t) |
c0407a96 PW |
124 | { |
125 | if (!dev || t < -1) { | |
564889c1 PW |
126 | WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); |
127 | return -EINVAL; | |
c0407a96 PW |
128 | }; |
129 | ||
130 | if (t == -1) | |
131 | pr_debug("OMAP PM: remove max DMA latency constraint: " | |
132 | "dev %s\n", dev_name(dev)); | |
133 | else | |
134 | pr_debug("OMAP PM: add max DMA latency constraint: " | |
135 | "dev %s, t = %ld usec\n", dev_name(dev), t); | |
136 | ||
137 | /* | |
138 | * For current Linux PM QOS params, this code should scan the | |
139 | * list of maximum CPU and DMA latencies and select the | |
140 | * smallest, then set cpu_dma_latency pm_qos_param | |
141 | * accordingly. | |
142 | * | |
143 | * For future Linux PM QOS params, with separate CPU and DMA | |
144 | * latency params, this code should just set the dma_latency param. | |
145 | * | |
146 | * TI CDP code can call constraint_set here. | |
147 | */ | |
148 | ||
564889c1 | 149 | return 0; |
c0407a96 PW |
150 | } |
151 | ||
fb8ce14c PW |
152 | int omap_pm_set_min_clk_rate(struct device *dev, struct clk *c, long r) |
153 | { | |
154 | if (!dev || !c || r < 0) { | |
155 | WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); | |
156 | return -EINVAL; | |
157 | } | |
158 | ||
159 | if (r == 0) | |
160 | pr_debug("OMAP PM: remove min clk rate constraint: " | |
161 | "dev %s\n", dev_name(dev)); | |
162 | else | |
163 | pr_debug("OMAP PM: add min clk rate constraint: " | |
164 | "dev %s, rate = %ld Hz\n", dev_name(dev), r); | |
165 | ||
166 | /* | |
167 | * Code in a real implementation should keep track of these | |
168 | * constraints on the clock, and determine the highest minimum | |
169 | * clock rate. It should iterate over each OPP and determine | |
170 | * whether the OPP will result in a clock rate that would | |
171 | * satisfy this constraint (and any other PM constraint in effect | |
172 | * at that time). Once it finds the lowest-voltage OPP that | |
173 | * meets those conditions, it should switch to it, or return | |
174 | * an error if the code is not capable of doing so. | |
175 | */ | |
176 | ||
177 | return 0; | |
178 | } | |
c0407a96 PW |
179 | |
180 | /* | |
181 | * DSP Bridge-specific constraints | |
182 | */ | |
183 | ||
184 | const struct omap_opp *omap_pm_dsp_get_opp_table(void) | |
185 | { | |
186 | pr_debug("OMAP PM: DSP request for OPP table\n"); | |
187 | ||
188 | /* | |
189 | * Return DSP frequency table here: The final item in the | |
190 | * array should have .rate = .opp_id = 0. | |
191 | */ | |
192 | ||
193 | return NULL; | |
194 | } | |
195 | ||
196 | void omap_pm_dsp_set_min_opp(u8 opp_id) | |
197 | { | |
198 | if (opp_id == 0) { | |
199 | WARN_ON(1); | |
200 | return; | |
201 | } | |
202 | ||
203 | pr_debug("OMAP PM: DSP requests minimum VDD1 OPP to be %d\n", opp_id); | |
204 | ||
205 | /* | |
206 | * | |
207 | * For l-o dev tree, our VDD1 clk is keyed on OPP ID, so we | |
208 | * can just test to see which is higher, the CPU's desired OPP | |
209 | * ID or the DSP's desired OPP ID, and use whichever is | |
210 | * highest. | |
211 | * | |
212 | * In CDP12.14+, the VDD1 OPP custom clock that controls the DSP | |
213 | * rate is keyed on MPU speed, not the OPP ID. So we need to | |
214 | * map the OPP ID to the MPU speed for use with clk_set_rate() | |
215 | * if it is higher than the current OPP clock rate. | |
216 | * | |
217 | */ | |
218 | } | |
219 | ||
220 | ||
221 | u8 omap_pm_dsp_get_opp(void) | |
222 | { | |
223 | pr_debug("OMAP PM: DSP requests current DSP OPP ID\n"); | |
224 | ||
225 | /* | |
226 | * For l-o dev tree, call clk_get_rate() on VDD1 OPP clock | |
227 | * | |
228 | * CDP12.14+: | |
229 | * Call clk_get_rate() on the OPP custom clock, map that to an | |
230 | * OPP ID using the tables defined in board-*.c/chip-*.c files. | |
231 | */ | |
232 | ||
233 | return 0; | |
234 | } | |
235 | ||
236 | /* | |
237 | * CPUFreq-originated constraint | |
238 | * | |
239 | * In the future, this should be handled by custom OPP clocktype | |
240 | * functions. | |
241 | */ | |
242 | ||
243 | struct cpufreq_frequency_table **omap_pm_cpu_get_freq_table(void) | |
244 | { | |
245 | pr_debug("OMAP PM: CPUFreq request for frequency table\n"); | |
246 | ||
247 | /* | |
248 | * Return CPUFreq frequency table here: loop over | |
249 | * all VDD1 clkrates, pull out the mpu_ck frequencies, build | |
250 | * table | |
251 | */ | |
252 | ||
253 | return NULL; | |
254 | } | |
255 | ||
256 | void omap_pm_cpu_set_freq(unsigned long f) | |
257 | { | |
258 | if (f == 0) { | |
259 | WARN_ON(1); | |
260 | return; | |
261 | } | |
262 | ||
263 | pr_debug("OMAP PM: CPUFreq requests CPU frequency to be set to %lu\n", | |
264 | f); | |
265 | ||
266 | /* | |
267 | * For l-o dev tree, determine whether MPU freq or DSP OPP id | |
268 | * freq is higher. Find the OPP ID corresponding to the | |
269 | * higher frequency. Call clk_round_rate() and clk_set_rate() | |
270 | * on the OPP custom clock. | |
271 | * | |
272 | * CDP should just be able to set the VDD1 OPP clock rate here. | |
273 | */ | |
274 | } | |
275 | ||
276 | unsigned long omap_pm_cpu_get_freq(void) | |
277 | { | |
278 | pr_debug("OMAP PM: CPUFreq requests current CPU frequency\n"); | |
279 | ||
280 | /* | |
281 | * Call clk_get_rate() on the mpu_ck. | |
282 | */ | |
283 | ||
284 | return 0; | |
285 | } | |
286 | ||
287 | /* | |
288 | * Device context loss tracking | |
289 | */ | |
290 | ||
291 | int omap_pm_get_dev_context_loss_count(struct device *dev) | |
292 | { | |
293 | if (!dev) { | |
294 | WARN_ON(1); | |
295 | return -EINVAL; | |
296 | }; | |
297 | ||
298 | pr_debug("OMAP PM: returning context loss count for dev %s\n", | |
299 | dev_name(dev)); | |
300 | ||
301 | /* | |
302 | * Map the device to the powerdomain. Return the powerdomain | |
303 | * off counter. | |
304 | */ | |
305 | ||
306 | return 0; | |
307 | } | |
308 | ||
309 | ||
310 | /* Should be called before clk framework init */ | |
311 | int __init omap_pm_if_early_init(struct omap_opp *mpu_opp_table, | |
312 | struct omap_opp *dsp_opp_table, | |
313 | struct omap_opp *l3_opp_table) | |
314 | { | |
315 | mpu_opps = mpu_opp_table; | |
316 | dsp_opps = dsp_opp_table; | |
317 | l3_opps = l3_opp_table; | |
318 | return 0; | |
319 | } | |
320 | ||
321 | /* Must be called after clock framework is initialized */ | |
322 | int __init omap_pm_if_init(void) | |
323 | { | |
324 | return 0; | |
325 | } | |
326 | ||
327 | void omap_pm_if_exit(void) | |
328 | { | |
329 | /* Deallocate CPUFreq frequency table here */ | |
330 | } | |
331 |