diff options
author | Miguel Vadillo <vadillo@ti.com> | 2010-09-09 11:12:34 -0400 |
---|---|---|
committer | Paolo Pisati <paolo.pisati@canonical.com> | 2012-08-17 04:19:08 -0400 |
commit | 2b09254c67d989214783096b140ff10c6dea0825 (patch) | |
tree | 717f38f1241f4027765577a7f0a1786d3b21f2f3 | |
parent | 4481003c2cf1d7d7ccf16b08900289f86007b804 (diff) |
SYSLINK:IPU-PM-add ipu pm to syslink tree
Add ipu pm to syslink tree
Signed-off-by: Miguel Vadillo <vadillo@ti.com>
Signed-off-by: Juan Gutierrez <jgutierrez@ti.com>
Signed-off-by: Paul Hunt <hunt@ti.com>
Signed-off-by: Fernando Guzman Lugo <x0095840@ti.com>
Signed-off-by: Hari Kanigeri <h-kanigeri2@ti.com>
Signed-off-by: Angela Stegmaier <angelabaker@ti.com>
-rw-r--r-- | drivers/dsp/syslink/ipu_pm/ipu_pm.c | 3490 | ||||
-rw-r--r-- | drivers/dsp/syslink/ipu_pm/ipu_pm.h | 467 |
2 files changed, 3957 insertions, 0 deletions
diff --git a/drivers/dsp/syslink/ipu_pm/ipu_pm.c b/drivers/dsp/syslink/ipu_pm/ipu_pm.c new file mode 100644 index 00000000000..30986f252c8 --- /dev/null +++ b/drivers/dsp/syslink/ipu_pm/ipu_pm.c | |||
@@ -0,0 +1,3490 @@ | |||
1 | /* | ||
2 | * ipu_pm.c | ||
3 | * | ||
4 | * IPU Power Management support functions for TI OMAP processors. | ||
5 | * | ||
6 | * Copyright (C) 2009-2010 Texas Instruments, Inc. | ||
7 | * | ||
8 | * This package is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
13 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
14 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
15 | */ | ||
16 | |||
17 | #include <generated/autoconf.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/cdev.h> | ||
22 | #include <linux/device.h> | ||
23 | #include <linux/mod_devicetable.h> | ||
24 | #include <linux/fs.h> | ||
25 | #include <linux/mm.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/vmalloc.h> | ||
29 | #include <linux/uaccess.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <syslink/notify.h> | ||
32 | #include <syslink/notify_driver.h> | ||
33 | #include <syslink/notifydefs.h> | ||
34 | #include <syslink/notify_driverdefs.h> | ||
35 | #include <syslink/notify_ducatidriver.h> | ||
36 | |||
37 | /* Power Management headers */ | ||
38 | #include <plat/omap_hwmod.h> | ||
39 | #include <plat/omap_device.h> | ||
40 | #include <plat/dma.h> | ||
41 | #include <plat/dmtimer.h> | ||
42 | #include <plat/clock.h> | ||
43 | #include <plat/i2c.h> | ||
44 | #include <plat/io.h> | ||
45 | #include <plat/iommu.h> | ||
46 | #include <plat/mailbox.h> | ||
47 | #include <plat/remoteproc.h> | ||
48 | #include <plat/omap-pm.h> | ||
49 | #include <linux/i2c.h> | ||
50 | #include <linux/gpio.h> | ||
51 | #include <linux/semaphore.h> | ||
52 | #include <linux/jiffies.h> | ||
53 | #include <linux/clk.h> | ||
54 | #include <linux/regulator/consumer.h> | ||
55 | #include <linux/regulator/driver.h> | ||
56 | #include <linux/regulator/machine.h> | ||
57 | #include <linux/i2c/twl.h> | ||
58 | |||
59 | /* Module headers */ | ||
60 | #include "ipu_pm.h" | ||
61 | |||
62 | /** ============================================================================ | ||
63 | * Macros and types | ||
64 | * ============================================================================ | ||
65 | */ | ||
66 | #define A9 3 | ||
67 | #define SYS_M3 2 | ||
68 | #define APP_M3 1 | ||
69 | #define TESLA 0 | ||
70 | |||
71 | #define proc_supported(proc_id) (proc_id == SYS_M3 || proc_id == APP_M3) | ||
72 | |||
73 | #define LINE_ID 0 | ||
74 | #define NUM_SELF_PROC 2 | ||
75 | #define IPU_KFIFO_SIZE 16 | ||
76 | #define PM_VERSION 0x00020000 | ||
77 | |||
78 | #define SYSM3_IDLE_FLAG_PHY_ADDR 0x9E0502D8 | ||
79 | #define APPM3_IDLE_FLAG_PHY_ADDR 0x9E0502DC | ||
80 | |||
81 | #define NUM_IDLE_CORES ((__raw_readl(appm3Idle) << 1) + \ | ||
82 | (__raw_readl(sysm3Idle))) | ||
83 | |||
84 | /** ============================================================================ | ||
85 | * Forward declarations of internal functions | ||
86 | * ============================================================================ | ||
87 | */ | ||
88 | |||
89 | /* Request a resource on behalf of an IPU client */ | ||
90 | static inline int ipu_pm_req_res(u32 res_type, u32 proc_id, u32 rcb_num); | ||
91 | |||
92 | /* Release a resource on behalf of an IPU client */ | ||
93 | static inline int ipu_pm_rel_res(u32 res_type, u32 proc_id, u32 rcb_num); | ||
94 | |||
95 | /* Request a sdma channels on behalf of an IPU client */ | ||
96 | static inline int ipu_pm_get_sdma_chan(int proc_id, u32 rcb_num); | ||
97 | |||
98 | /* Request a gptimer on behalf of an IPU client */ | ||
99 | static inline int ipu_pm_get_gptimer(int proc_id, u32 rcb_num); | ||
100 | |||
101 | /* Request an i2c bus on behalf of an IPU client */ | ||
102 | static inline int ipu_pm_get_i2c_bus(int proc_id, u32 rcb_num); | ||
103 | |||
104 | /* Request a gpio on behalf of an IPU client */ | ||
105 | static inline int ipu_pm_get_gpio(int proc_id, u32 rcb_num); | ||
106 | |||
107 | /* Request a regulator on behalf of an IPU client */ | ||
108 | static inline int ipu_pm_get_regulator(int proc_id, u32 rcb_num); | ||
109 | |||
110 | /* Request an Aux clk on behalf of an IPU client */ | ||
111 | static inline int ipu_pm_get_aux_clk(int proc_id, u32 rcb_num); | ||
112 | |||
113 | /* Request sys m3 on behalf of an IPU client */ | ||
114 | static inline int ipu_pm_get_sys_m3(int proc_id, u32 rcb_num); | ||
115 | |||
116 | /* Request app m3 on behalf of an IPU client */ | ||
117 | static inline int ipu_pm_get_app_m3(int proc_id, u32 rcb_num); | ||
118 | |||
119 | /* Request L3 Bus on behalf of an IPU client */ | ||
120 | static inline int ipu_pm_get_l3_bus(int proc_id, u32 rcb_num); | ||
121 | |||
122 | /* Request IVA HD on behalf of an IPU client */ | ||
123 | static inline int ipu_pm_get_iva_hd(int proc_id, u32 rcb_num); | ||
124 | |||
125 | /* Request FDIF on behalf of an IPU client */ | ||
126 | static inline int ipu_pm_get_fdif(int proc_id, u32 rcb_num); | ||
127 | |||
128 | /* Request MPU on behalf of an IPU client */ | ||
129 | static inline int ipu_pm_get_mpu(int proc_id, u32 rcb_num); | ||
130 | |||
131 | /* Request IPU on behalf of an IPU client */ | ||
132 | static inline int ipu_pm_get_ipu(int proc_id, u32 rcb_num); | ||
133 | |||
134 | /* Request IVA SEQ0 on behalf of an IPU client */ | ||
135 | static inline int ipu_pm_get_ivaseq0(int proc_id, u32 rcb_num); | ||
136 | |||
137 | /* Request IVA SEQ1 on behalf of an IPU client */ | ||
138 | static inline int ipu_pm_get_ivaseq1(int proc_id, u32 rcb_num); | ||
139 | |||
140 | /* Request ISS on behalf of an IPU client */ | ||
141 | static inline int ipu_pm_get_iss(int proc_id, u32 rcb_num); | ||
142 | |||
143 | /* Release a sdma on behalf of an IPU client */ | ||
144 | static inline int ipu_pm_rel_sdma_chan(int proc_id, u32 rcb_num); | ||
145 | |||
146 | /* Release a gptimer on behalf of an IPU client */ | ||
147 | static inline int ipu_pm_rel_gptimer(int proc_id, u32 rcb_num); | ||
148 | |||
149 | /* Release an i2c buses on behalf of an IPU client */ | ||
150 | static inline int ipu_pm_rel_i2c_bus(int proc_id, u32 rcb_num); | ||
151 | |||
152 | /* Release a gpio on behalf of an IPU client */ | ||
153 | static inline int ipu_pm_rel_gpio(int proc_id, u32 rcb_num); | ||
154 | |||
155 | /* Release a regulator on behalf of an IPU client */ | ||
156 | static inline int ipu_pm_rel_regulator(int proc_id, u32 rcb_num); | ||
157 | |||
158 | /* Release an Aux clk on behalf of an IPU client */ | ||
159 | static inline int ipu_pm_rel_aux_clk(int proc_id, u32 rcb_num); | ||
160 | |||
161 | /* Release sys m3 on behalf of an IPU client */ | ||
162 | static inline int ipu_pm_rel_sys_m3(int proc_id, u32 rcb_num); | ||
163 | |||
164 | /* Release app m3 on behalf of an IPU client */ | ||
165 | static inline int ipu_pm_rel_app_m3(int proc_id, u32 rcb_num); | ||
166 | |||
167 | /* Release L3 Bus on behalf of an IPU client */ | ||
168 | static inline int ipu_pm_rel_l3_bus(int proc_id, u32 rcb_num); | ||
169 | |||
170 | /* Release IVA HD on behalf of an IPU client */ | ||
171 | static inline int ipu_pm_rel_iva_hd(int proc_id, u32 rcb_num); | ||
172 | |||
173 | /* Release FDIF on behalf of an IPU client */ | ||
174 | static inline int ipu_pm_rel_fdif(int proc_id, u32 rcb_num); | ||
175 | |||
176 | /* Release MPU on behalf of an IPU client */ | ||
177 | static inline int ipu_pm_rel_mpu(int proc_id, u32 rcb_num); | ||
178 | |||
179 | /* Release IPU on behalf of an IPU client */ | ||
180 | static inline int ipu_pm_rel_ipu(int proc_id, u32 rcb_num); | ||
181 | |||
182 | /* Release IVA SEQ0 on behalf of an IPU client */ | ||
183 | static inline int ipu_pm_rel_ivaseq0(int proc_id, u32 rcb_num); | ||
184 | |||
185 | /* Release IVA SEQ1 on behalf of an IPU client */ | ||
186 | static inline int ipu_pm_rel_ivaseq1(int proc_id, u32 rcb_num); | ||
187 | |||
188 | /* Release ISS on behalf of an IPU client */ | ||
189 | static inline int ipu_pm_rel_iss(int proc_id, u32 rcb_num); | ||
190 | |||
191 | /* Request a FDIF constraint on behalf of an IPU client */ | ||
192 | static inline int ipu_pm_req_cstr_fdif(int proc_id, u32 rcb_num); | ||
193 | |||
194 | /* Request a IPU constraint on behalf of an IPU client */ | ||
195 | static inline int ipu_pm_req_cstr_ipu(int proc_id, u32 rcb_num); | ||
196 | |||
197 | /* Request a L3 Bus constraint on behalf of an IPU client */ | ||
198 | static inline int ipu_pm_req_cstr_l3_bus(int proc_id, u32 rcb_num); | ||
199 | |||
200 | /* Request an IVA HD constraint on behalf of an IPU client */ | ||
201 | static inline int ipu_pm_req_cstr_iva_hd(int proc_id, u32 rcb_num); | ||
202 | |||
203 | /* Request an ISS constraint on behalf of an IPU client */ | ||
204 | static inline int ipu_pm_req_cstr_iss(int proc_id, u32 rcb_num); | ||
205 | |||
206 | /* Request an MPU constraint on behalf of an IPU client */ | ||
207 | static inline int ipu_pm_req_cstr_mpu(int proc_id, u32 rcb_num); | ||
208 | |||
209 | /* Release a FDFI constraint on behalf of an IPU client */ | ||
210 | static inline int ipu_pm_rel_cstr_fdif(int proc_id, u32 rcb_num); | ||
211 | |||
212 | /* Release a IPU constraint on behalf of an IPU client */ | ||
213 | static inline int ipu_pm_rel_cstr_ipu(int proc_id, u32 rcb_num); | ||
214 | |||
215 | /* Release a L3 Bus constraint on behalf of an IPU client */ | ||
216 | static inline int ipu_pm_rel_cstr_l3_bus(int proc_id, u32 rcb_num); | ||
217 | |||
218 | /* Release an IVA HD constraint on behalf of an IPU client */ | ||
219 | static inline int ipu_pm_rel_cstr_iva_hd(int proc_id, u32 rcb_num); | ||
220 | |||
221 | /* Release an ISS constraint on behalf of an IPU client */ | ||
222 | static inline int ipu_pm_rel_cstr_iss(int proc_id, u32 rcb_num); | ||
223 | |||
224 | /* Release an MPU constraint on behalf of an IPU client */ | ||
225 | static inline int ipu_pm_rel_cstr_mpu(int proc_id, u32 rcb_num); | ||
226 | |||
227 | /** ============================================================================ | ||
228 | * Globals | ||
229 | * ============================================================================ | ||
230 | */ | ||
231 | |||
232 | /* Usage Masks */ | ||
233 | static u32 GPTIMER_USE_MASK = 0xFFFF; | ||
234 | static u32 I2C_USE_MASK = 0xFFFF; | ||
235 | static u32 AUX_CLK_USE_MASK = 0xFFFF; | ||
236 | |||
237 | /* Previous voltage value of secondary camera regulator */ | ||
238 | static u32 cam2_prev_volt; | ||
239 | |||
240 | static struct ipu_pm_object *pm_handle_appm3; | ||
241 | static struct ipu_pm_object *pm_handle_sysm3; | ||
242 | static struct workqueue_struct *ipu_wq; | ||
243 | static struct pm_qos_request_list *pm_qos_handle; | ||
244 | static struct omap_rproc *sys_rproc; | ||
245 | static struct omap_rproc *app_rproc; | ||
246 | static struct omap_mbox *ducati_mbox; | ||
247 | static struct iommu *ducati_iommu; | ||
248 | static bool first_time = 1; | ||
249 | static struct omap_dm_timer *pm_gpt; | ||
250 | |||
251 | /* Ducati Interrupt Capable Gptimers */ | ||
252 | static int ipu_timer_list[NUM_IPU_TIMERS] = { | ||
253 | GP_TIMER_4, | ||
254 | GP_TIMER_9, | ||
255 | GP_TIMER_11}; | ||
256 | |||
257 | /* I2C spinlock assignment mapping table */ | ||
258 | static int i2c_spinlock_list[I2C_BUS_MAX + 1] = { | ||
259 | I2C_SL_INVAL, | ||
260 | I2C_1_SL, | ||
261 | I2C_2_SL, | ||
262 | I2C_3_SL, | ||
263 | I2C_4_SL}; | ||
264 | |||
265 | static char *ipu_regulator_name[REGULATOR_MAX] = { | ||
266 | "cam2pwr"}; | ||
267 | |||
268 | static struct ipu_pm_module_object ipu_pm_state = { | ||
269 | .def_cfg.reserved = 1, | ||
270 | .gate_handle = NULL | ||
271 | } ; | ||
272 | |||
273 | static struct ipu_pm_params pm_params = { | ||
274 | .pm_fdif_counter = 0, | ||
275 | .pm_ipu_counter = 0, | ||
276 | .pm_sys_m3_counter = 0, | ||
277 | .pm_app_m3_counter = 0, | ||
278 | .pm_iss_counter = 0, | ||
279 | .pm_iva_hd_counter = 0, | ||
280 | .pm_ivaseq0_counter = 0, | ||
281 | .pm_ivaseq1_counter = 0, | ||
282 | .pm_l3_bus_counter = 0, | ||
283 | .pm_mpu_counter = 0, | ||
284 | .pm_sdmachan_counter = 0, | ||
285 | .pm_gptimer_counter = 0, | ||
286 | .pm_gpio_counter = 0, | ||
287 | .pm_i2c_bus_counter = 0, | ||
288 | .pm_regulator_counter = 0, | ||
289 | .pm_aux_clk_counter = 0, | ||
290 | .timeout = 10000, | ||
291 | .shared_addr = NULL, | ||
292 | .pm_num_events = NUMBER_PM_EVENTS, | ||
293 | .pm_resource_event = PM_RESOURCE, | ||
294 | .pm_notification_event = PM_NOTIFICATION, | ||
295 | .proc_id = A9, | ||
296 | .remote_proc_id = -1, | ||
297 | .line_id = 0 | ||
298 | } ; | ||
299 | |||
300 | static void __iomem *sysm3Idle; | ||
301 | static void __iomem *appm3Idle; | ||
302 | |||
303 | /* | ||
304 | Request a resource on behalf of an IPU client | ||
305 | * | ||
306 | */ | ||
307 | static inline int ipu_pm_req_res(u32 res_type, u32 proc_id, u32 rcb_num) | ||
308 | { | ||
309 | int retval = PM_SUCCESS; | ||
310 | |||
311 | switch (res_type) { | ||
312 | case SDMA: | ||
313 | retval = ipu_pm_get_sdma_chan(proc_id, rcb_num); | ||
314 | break; | ||
315 | case GP_TIMER: | ||
316 | retval = ipu_pm_get_gptimer(proc_id, rcb_num); | ||
317 | break; | ||
318 | case GP_IO: | ||
319 | retval = ipu_pm_get_gpio(proc_id, rcb_num); | ||
320 | break; | ||
321 | case I2C: | ||
322 | retval = ipu_pm_get_i2c_bus(proc_id, rcb_num); | ||
323 | break; | ||
324 | case REGULATOR: | ||
325 | retval = ipu_pm_get_regulator(proc_id, rcb_num); | ||
326 | break; | ||
327 | case AUX_CLK: | ||
328 | retval = ipu_pm_get_aux_clk(proc_id, rcb_num); | ||
329 | break; | ||
330 | case SYSM3: | ||
331 | retval = ipu_pm_get_sys_m3(proc_id, rcb_num); | ||
332 | break; | ||
333 | case APPM3: | ||
334 | retval = ipu_pm_get_app_m3(proc_id, rcb_num); | ||
335 | break; | ||
336 | case L3_BUS: | ||
337 | retval = ipu_pm_get_l3_bus(proc_id, rcb_num); | ||
338 | break; | ||
339 | case IVA_HD: | ||
340 | retval = ipu_pm_get_iva_hd(proc_id, rcb_num); | ||
341 | break; | ||
342 | case IVASEQ0: | ||
343 | retval = ipu_pm_get_ivaseq0(proc_id, rcb_num); | ||
344 | break; | ||
345 | case IVASEQ1: | ||
346 | retval = ipu_pm_get_ivaseq1(proc_id, rcb_num); | ||
347 | break; | ||
348 | case ISS: | ||
349 | retval = ipu_pm_get_iss(proc_id, rcb_num); | ||
350 | break; | ||
351 | case FDIF: | ||
352 | retval = ipu_pm_get_fdif(proc_id, rcb_num); | ||
353 | break; | ||
354 | case MPU: | ||
355 | retval = ipu_pm_get_mpu(proc_id, rcb_num); | ||
356 | break; | ||
357 | case IPU: | ||
358 | retval = ipu_pm_get_ipu(proc_id, rcb_num); | ||
359 | break; | ||
360 | default: | ||
361 | pr_err("Unsupported resource\n"); | ||
362 | retval = PM_UNSUPPORTED; | ||
363 | } | ||
364 | |||
365 | return retval; | ||
366 | } | ||
367 | |||
368 | /* | ||
369 | Release a resource on behalf of an IPU client | ||
370 | * | ||
371 | */ | ||
372 | static inline int ipu_pm_rel_res(u32 res_type, u32 proc_id, u32 rcb_num) | ||
373 | { | ||
374 | int retval = PM_SUCCESS; | ||
375 | |||
376 | switch (res_type) { | ||
377 | case SDMA: | ||
378 | retval = ipu_pm_rel_sdma_chan(proc_id, rcb_num); | ||
379 | break; | ||
380 | case GP_TIMER: | ||
381 | retval = ipu_pm_rel_gptimer(proc_id, rcb_num); | ||
382 | break; | ||
383 | case GP_IO: | ||
384 | retval = ipu_pm_rel_gpio(proc_id, rcb_num); | ||
385 | break; | ||
386 | case I2C: | ||
387 | retval = ipu_pm_rel_i2c_bus(proc_id, rcb_num); | ||
388 | break; | ||
389 | case REGULATOR: | ||
390 | retval = ipu_pm_rel_regulator(proc_id, rcb_num); | ||
391 | break; | ||
392 | case AUX_CLK: | ||
393 | retval = ipu_pm_rel_aux_clk(proc_id, rcb_num); | ||
394 | break; | ||
395 | case SYSM3: | ||
396 | retval = ipu_pm_rel_sys_m3(proc_id, rcb_num); | ||
397 | break; | ||
398 | case APPM3: | ||
399 | retval = ipu_pm_rel_app_m3(proc_id, rcb_num); | ||
400 | break; | ||
401 | case L3_BUS: | ||
402 | retval = ipu_pm_rel_l3_bus(proc_id, rcb_num); | ||
403 | break; | ||
404 | case IVA_HD: | ||
405 | retval = ipu_pm_rel_iva_hd(proc_id, rcb_num); | ||
406 | break; | ||
407 | case IVASEQ0: | ||
408 | retval = ipu_pm_rel_ivaseq0(proc_id, rcb_num); | ||
409 | break; | ||
410 | case IVASEQ1: | ||
411 | retval = ipu_pm_rel_ivaseq1(proc_id, rcb_num); | ||
412 | break; | ||
413 | case ISS: | ||
414 | retval = ipu_pm_rel_iss(proc_id, rcb_num); | ||
415 | break; | ||
416 | case FDIF: | ||
417 | retval = ipu_pm_rel_fdif(proc_id, rcb_num); | ||
418 | break; | ||
419 | case MPU: | ||
420 | retval = ipu_pm_rel_mpu(proc_id, rcb_num); | ||
421 | break; | ||
422 | case IPU: | ||
423 | retval = ipu_pm_rel_ipu(proc_id, rcb_num); | ||
424 | break; | ||
425 | default: | ||
426 | pr_err("Unsupported resource\n"); | ||
427 | retval = PM_UNSUPPORTED; | ||
428 | } | ||
429 | |||
430 | return retval; | ||
431 | } | ||
432 | |||
433 | /* | ||
434 | Request a resource constraint on behalf of an IPU client | ||
435 | * | ||
436 | */ | ||
437 | static inline int ipu_pm_req_cstr(u32 res_type, u32 proc_id, u32 rcb_num) | ||
438 | { | ||
439 | int retval = PM_SUCCESS; | ||
440 | |||
441 | switch (res_type) { | ||
442 | case FDIF: | ||
443 | retval = ipu_pm_req_cstr_fdif(proc_id, rcb_num); | ||
444 | break; | ||
445 | case IPU: | ||
446 | retval = ipu_pm_req_cstr_ipu(proc_id, rcb_num); | ||
447 | break; | ||
448 | case L3_BUS: | ||
449 | retval = ipu_pm_req_cstr_l3_bus(proc_id, rcb_num); | ||
450 | break; | ||
451 | case IVA_HD: | ||
452 | retval = ipu_pm_req_cstr_iva_hd(proc_id, rcb_num); | ||
453 | break; | ||
454 | case ISS: | ||
455 | retval = ipu_pm_req_cstr_iss(proc_id, rcb_num); | ||
456 | break; | ||
457 | case MPU: | ||
458 | retval = ipu_pm_req_cstr_mpu(proc_id, rcb_num); | ||
459 | break; | ||
460 | default: | ||
461 | pr_err("Resource does not support constraints\n"); | ||
462 | retval = PM_UNSUPPORTED; | ||
463 | } | ||
464 | |||
465 | return retval; | ||
466 | } | ||
467 | |||
468 | /* | ||
469 | Release a resource constraint on behalf of an IPU client | ||
470 | * | ||
471 | */ | ||
472 | static inline int ipu_pm_rel_cstr(u32 res_type, u32 proc_id, u32 rcb_num) | ||
473 | { | ||
474 | int retval = PM_SUCCESS; | ||
475 | |||
476 | switch (res_type) { | ||
477 | case FDIF: | ||
478 | retval = ipu_pm_rel_cstr_fdif(proc_id, rcb_num); | ||
479 | break; | ||
480 | case IPU: | ||
481 | retval = ipu_pm_rel_cstr_ipu(proc_id, rcb_num); | ||
482 | break; | ||
483 | case L3_BUS: | ||
484 | retval = ipu_pm_rel_cstr_l3_bus(proc_id, rcb_num); | ||
485 | break; | ||
486 | case IVA_HD: | ||
487 | retval = ipu_pm_rel_cstr_iva_hd(proc_id, rcb_num); | ||
488 | break; | ||
489 | case ISS: | ||
490 | retval = ipu_pm_rel_cstr_iss(proc_id, rcb_num); | ||
491 | break; | ||
492 | case MPU: | ||
493 | retval = ipu_pm_rel_cstr_mpu(proc_id, rcb_num); | ||
494 | break; | ||
495 | default: | ||
496 | pr_err("Resource does not support constraints\n"); | ||
497 | retval = PM_UNSUPPORTED; | ||
498 | } | ||
499 | |||
500 | return retval; | ||
501 | } | ||
502 | |||
503 | /* | ||
504 | Work Function to req/rel a resource | ||
505 | * | ||
506 | */ | ||
507 | static void ipu_pm_work(struct work_struct *work) | ||
508 | { | ||
509 | struct ipu_pm_object *handle = | ||
510 | container_of(work, struct ipu_pm_object, work); | ||
511 | struct rcb_block *rcb_p; | ||
512 | struct ipu_pm_msg im; | ||
513 | struct ipu_pm_params *params = handle->params; | ||
514 | union message_slicer pm_msg; | ||
515 | int action_type; | ||
516 | int res_type; | ||
517 | int rcb_num; | ||
518 | int retval = PM_SUCCESS; | ||
519 | |||
520 | while (kfifo_len(&handle->fifo) >= sizeof(im)) { | ||
521 | spin_lock_irq(&handle->lock); | ||
522 | kfifo_out(&handle->fifo, &im, sizeof(im)); | ||
523 | spin_unlock_irq(&handle->lock); | ||
524 | |||
525 | /* Get the payload */ | ||
526 | pm_msg.whole = im.pm_msg; | ||
527 | /* Get the rcb_num */ | ||
528 | rcb_num = pm_msg.fields.rcb_num; | ||
529 | /* Get pointer to the proper RCB */ | ||
530 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
531 | |||
532 | /* Get the type of resource and the actions required */ | ||
533 | action_type = rcb_p->msg_type; | ||
534 | res_type = rcb_p->sub_type; | ||
535 | switch (action_type) { | ||
536 | case PM_REQUEST_RESOURCE: | ||
537 | retval = ipu_pm_req_res(res_type, im.proc_id, rcb_num); | ||
538 | if (retval != PM_SUCCESS) | ||
539 | pm_msg.fields.msg_type = PM_FAIL; | ||
540 | break; | ||
541 | case PM_RELEASE_RESOURCE: | ||
542 | retval = ipu_pm_rel_res(res_type, im.proc_id, rcb_num); | ||
543 | if (retval != PM_SUCCESS) | ||
544 | pm_msg.fields.msg_type = PM_FAIL; | ||
545 | break; | ||
546 | case PM_REQUEST_CONSTRAINTS: | ||
547 | retval = ipu_pm_req_cstr(res_type, im.proc_id, rcb_num); | ||
548 | if (retval != PM_SUCCESS) | ||
549 | pm_msg.fields.msg_type = PM_FAIL; | ||
550 | break; | ||
551 | case PM_RELEASE_CONSTRAINTS: | ||
552 | retval = ipu_pm_rel_cstr(res_type, im.proc_id, rcb_num); | ||
553 | if (retval != PM_SUCCESS) | ||
554 | pm_msg.fields.msg_type = PM_FAIL; | ||
555 | break; | ||
556 | default: | ||
557 | pm_msg.fields.msg_type = PM_FAIL; | ||
558 | retval = PM_UNSUPPORTED; | ||
559 | break; | ||
560 | } | ||
561 | |||
562 | /* Update the payload with the reply msg */ | ||
563 | pm_msg.fields.reply_flag = true; | ||
564 | pm_msg.fields.parm = retval; | ||
565 | |||
566 | /* Restore the payload and send to caller*/ | ||
567 | im.pm_msg = pm_msg.whole; | ||
568 | |||
569 | /* Send the ACK to Remote Proc*/ | ||
570 | retval = notify_send_event( | ||
571 | params->remote_proc_id, | ||
572 | params->line_id, | ||
573 | params->pm_resource_event | \ | ||
574 | (NOTIFY_SYSTEMKEY << 16), | ||
575 | im.pm_msg, | ||
576 | true); | ||
577 | if (retval < 0) | ||
578 | pr_err("Error sending notify event\n"); | ||
579 | } | ||
580 | } | ||
581 | |||
582 | void ipu_pm_callback(u16 proc_id, u16 line_id, u32 event_id, | ||
583 | uint *arg, u32 payload) | ||
584 | { | ||
585 | struct ipu_pm_object *handle; | ||
586 | struct ipu_pm_msg im; | ||
587 | |||
588 | /*get the handle to proper ipu pm object */ | ||
589 | handle = ipu_pm_get_handle(proc_id); | ||
590 | |||
591 | im.proc_id = proc_id; | ||
592 | im.pm_msg = payload; | ||
593 | |||
594 | spin_lock_irq(&handle->lock); | ||
595 | if (kfifo_avail(&handle->fifo) >= sizeof(im)) { | ||
596 | kfifo_in(&handle->fifo, (unsigned char *)&im, sizeof(im)); | ||
597 | queue_work(ipu_wq, &handle->work); | ||
598 | } | ||
599 | spin_unlock_irq(&handle->lock); | ||
600 | } | ||
601 | EXPORT_SYMBOL(ipu_pm_callback); | ||
602 | |||
603 | |||
604 | /* | ||
605 | Function for PM notifications Callback | ||
606 | * | ||
607 | */ | ||
608 | void ipu_pm_notify_callback(u16 proc_id, u16 line_id, u32 event_id, | ||
609 | uint *arg, u32 payload) | ||
610 | { | ||
611 | /** | ||
612 | * Post semaphore based in eventType (payload); | ||
613 | * IPU has alreay finished the process for the | ||
614 | * notification | ||
615 | */ | ||
616 | /* Get the payload */ | ||
617 | struct ipu_pm_object *handle; | ||
618 | union message_slicer pm_msg; | ||
619 | struct ipu_pm_params *params; | ||
620 | int retval; | ||
621 | |||
622 | /* get the handle to proper ipu pm object */ | ||
623 | handle = ipu_pm_get_handle(proc_id); | ||
624 | if (WARN_ON(unlikely(handle == NULL))) | ||
625 | return; | ||
626 | params = handle->params; | ||
627 | if (WARN_ON(unlikely(params == NULL))) | ||
628 | return; | ||
629 | |||
630 | pm_msg.whole = payload; | ||
631 | if (pm_msg.fields.msg_type == PM_NOTIFY_HIBERNATE) { | ||
632 | /* Remote proc requested hibernate */ | ||
633 | /* Remote Proc is ready to hibernate */ | ||
634 | retval = ipu_pm_save_ctx(proc_id); | ||
635 | if (retval) | ||
636 | pr_info("Unable to stop proc %d\n", proc_id); | ||
637 | } else { | ||
638 | switch (pm_msg.fields.msg_subtype) { | ||
639 | case PM_SUSPEND: | ||
640 | handle->pm_event[PM_SUSPEND].pm_msg = payload; | ||
641 | up(&handle->pm_event[PM_SUSPEND].sem_handle); | ||
642 | break; | ||
643 | case PM_RESUME: | ||
644 | handle->pm_event[PM_RESUME].pm_msg = payload; | ||
645 | up(&handle->pm_event[PM_RESUME].sem_handle); | ||
646 | break; | ||
647 | case PM_HIBERNATE: | ||
648 | handle->pm_event[PM_HIBERNATE].pm_msg = payload; | ||
649 | up(&handle->pm_event[PM_HIBERNATE].sem_handle); | ||
650 | break; | ||
651 | case PM_PID_DEATH: | ||
652 | handle->pm_event[PM_PID_DEATH].pm_msg = payload; | ||
653 | up(&handle->pm_event[PM_PID_DEATH].sem_handle); | ||
654 | break; | ||
655 | } | ||
656 | } | ||
657 | } | ||
658 | EXPORT_SYMBOL(ipu_pm_notify_callback); | ||
659 | |||
660 | /* | ||
661 | Function for send PM Notifications | ||
662 | * | ||
663 | */ | ||
664 | int ipu_pm_notifications(enum pm_event_type event_type, void *data) | ||
665 | { | ||
666 | /** | ||
667 | * Function called by linux driver | ||
668 | * Recieves evenType: Suspend, Resume, others... | ||
669 | * Send event to Ducati | ||
670 | * Pend semaphore based in event_type (payload) | ||
671 | * Return ACK to caller | ||
672 | */ | ||
673 | |||
674 | struct ipu_pm_object *handle; | ||
675 | struct ipu_pm_params *params; | ||
676 | union message_slicer pm_msg; | ||
677 | int retval; | ||
678 | int pm_ack = 0; | ||
679 | int i; | ||
680 | int proc_id; | ||
681 | |||
682 | /*get the handle to proper ipu pm object */ | ||
683 | for (i = 0; i < NUM_SELF_PROC; i++) { | ||
684 | proc_id = i + 1; | ||
685 | handle = ipu_pm_get_handle(proc_id); | ||
686 | if (handle == NULL) | ||
687 | continue; | ||
688 | params = handle->params; | ||
689 | if (params == NULL) | ||
690 | continue; | ||
691 | switch (event_type) { | ||
692 | case PM_SUSPEND: | ||
693 | pm_msg.fields.msg_type = PM_NOTIFICATIONS; | ||
694 | pm_msg.fields.msg_subtype = PM_SUSPEND; | ||
695 | pm_msg.fields.parm = PM_SUCCESS; | ||
696 | /* put general purpose message in share memory */ | ||
697 | handle->rcb_table->gp_msg = (unsigned)data; | ||
698 | /* send the request to IPU*/ | ||
699 | retval = notify_send_event( | ||
700 | params->remote_proc_id, | ||
701 | params->line_id, | ||
702 | params->pm_notification_event | \ | ||
703 | (NOTIFY_SYSTEMKEY << 16), | ||
704 | (unsigned int)pm_msg.whole, | ||
705 | true); | ||
706 | if (retval < 0) | ||
707 | goto error_send; | ||
708 | /* wait until event from IPU (ipu_pm_notify_callback)*/ | ||
709 | retval = down_timeout | ||
710 | (&handle->pm_event[PM_SUSPEND] | ||
711 | .sem_handle, | ||
712 | msecs_to_jiffies(params->timeout)); | ||
713 | pm_msg.whole = handle->pm_event[PM_SUSPEND].pm_msg; | ||
714 | if (WARN_ON((retval < 0) || | ||
715 | (pm_msg.fields.parm != PM_SUCCESS))) | ||
716 | goto error; | ||
717 | break; | ||
718 | case PM_RESUME: | ||
719 | pm_msg.fields.msg_type = PM_NOTIFICATIONS; | ||
720 | pm_msg.fields.msg_subtype = PM_RESUME; | ||
721 | pm_msg.fields.parm = PM_SUCCESS; | ||
722 | /* put general purpose message in share memory */ | ||
723 | handle->rcb_table->gp_msg = (unsigned)data; | ||
724 | /* send the request to IPU*/ | ||
725 | retval = notify_send_event( | ||
726 | params->remote_proc_id, | ||
727 | params->line_id, | ||
728 | params->pm_notification_event | \ | ||
729 | (NOTIFY_SYSTEMKEY << 16), | ||
730 | (unsigned int)pm_msg.whole, | ||
731 | true); | ||
732 | if (retval < 0) | ||
733 | goto error_send; | ||
734 | /* wait until event from IPU (ipu_pm_notify_callback)*/ | ||
735 | retval = down_timeout | ||
736 | (&handle->pm_event[PM_RESUME] | ||
737 | .sem_handle, | ||
738 | msecs_to_jiffies(params->timeout)); | ||
739 | pm_msg.whole = handle->pm_event[PM_RESUME].pm_msg; | ||
740 | if (WARN_ON((retval < 0) || | ||
741 | (pm_msg.fields.parm != PM_SUCCESS))) | ||
742 | goto error; | ||
743 | break; | ||
744 | case PM_HIBERNATE: | ||
745 | pm_msg.fields.msg_type = PM_NOTIFICATIONS; | ||
746 | pm_msg.fields.msg_subtype = PM_HIBERNATE; | ||
747 | pm_msg.fields.parm = PM_SUCCESS; | ||
748 | /* put general purpose message in share memory */ | ||
749 | handle->rcb_table->gp_msg = (unsigned)data; | ||
750 | /* send the request to IPU*/ | ||
751 | retval = notify_send_event( | ||
752 | params->remote_proc_id, | ||
753 | params->line_id, | ||
754 | params->pm_notification_event | \ | ||
755 | (NOTIFY_SYSTEMKEY << 16), | ||
756 | (unsigned int)pm_msg.whole, | ||
757 | true); | ||
758 | if (retval < 0) | ||
759 | goto error_send; | ||
760 | /* wait until event from IPU (ipu_pm_notify_callback)*/ | ||
761 | retval = down_timeout | ||
762 | (&handle->pm_event[PM_HIBERNATE] | ||
763 | .sem_handle, | ||
764 | msecs_to_jiffies(params->timeout)); | ||
765 | pm_msg.whole = handle->pm_event[PM_HIBERNATE].pm_msg; | ||
766 | if (WARN_ON((retval < 0) || | ||
767 | (pm_msg.fields.parm != PM_SUCCESS))) | ||
768 | goto error; | ||
769 | else { | ||
770 | /*Remote Proc is ready to hibernate*/ | ||
771 | pm_ack = ipu_pm_save_ctx(proc_id); | ||
772 | } | ||
773 | break; | ||
774 | case PM_PID_DEATH: | ||
775 | pm_msg.fields.msg_type = PM_NOTIFICATIONS; | ||
776 | pm_msg.fields.msg_subtype = PM_PID_DEATH; | ||
777 | pm_msg.fields.parm = PM_SUCCESS; | ||
778 | /* put general purpose message in share memory */ | ||
779 | handle->rcb_table->gp_msg = (unsigned)data; | ||
780 | /* send the request to IPU*/ | ||
781 | retval = notify_send_event( | ||
782 | params->remote_proc_id, | ||
783 | params->line_id, | ||
784 | params->pm_notification_event | \ | ||
785 | (NOTIFY_SYSTEMKEY << 16), | ||
786 | (unsigned int)pm_msg.whole, | ||
787 | true); | ||
788 | if (retval < 0) | ||
789 | goto error_send; | ||
790 | /* wait until event from IPU (ipu_pm_notify_callback)*/ | ||
791 | retval = down_timeout | ||
792 | (&handle->pm_event[PM_PID_DEATH] | ||
793 | .sem_handle, | ||
794 | msecs_to_jiffies(params->timeout)); | ||
795 | pm_msg.whole = handle->pm_event[PM_PID_DEATH].pm_msg; | ||
796 | if (WARN_ON((retval < 0) || | ||
797 | (pm_msg.fields.parm != PM_SUCCESS))) | ||
798 | goto error; | ||
799 | break; | ||
800 | } | ||
801 | } | ||
802 | return pm_ack; | ||
803 | |||
804 | error_send: | ||
805 | pr_err("Error notify_send event\n"); | ||
806 | error: | ||
807 | pr_err("Error sending Notification events\n"); | ||
808 | return -EBUSY; | ||
809 | } | ||
810 | EXPORT_SYMBOL(ipu_pm_notifications); | ||
811 | |||
812 | /* | ||
813 | Request a sdma channels on behalf of an IPU client | ||
814 | * | ||
815 | */ | ||
816 | static inline int ipu_pm_get_sdma_chan(int proc_id, u32 rcb_num) | ||
817 | { | ||
818 | struct ipu_pm_object *handle; | ||
819 | struct ipu_pm_params *params; | ||
820 | struct rcb_block *rcb_p; | ||
821 | int pm_sdmachan_num; | ||
822 | int pm_sdmachan_dummy; | ||
823 | int ch; | ||
824 | int ch_aux; | ||
825 | int retval; | ||
826 | |||
827 | /* get the handle to proper ipu pm object */ | ||
828 | handle = ipu_pm_get_handle(proc_id); | ||
829 | if (WARN_ON(unlikely(handle == NULL))) | ||
830 | return PM_NOT_INSTANTIATED; | ||
831 | |||
832 | params = handle->params; | ||
833 | if (WARN_ON(unlikely(params == NULL))) | ||
834 | return PM_NOT_INSTANTIATED; | ||
835 | |||
836 | /* Get pointer to the proper RCB */ | ||
837 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
838 | return PM_INVAL_RCB_NUM; | ||
839 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
840 | /* Get number of channels from RCB */ | ||
841 | pm_sdmachan_num = rcb_p->num_chan; | ||
842 | if (WARN_ON((pm_sdmachan_num <= 0) || | ||
843 | (pm_sdmachan_num > SDMA_CHANNELS_MAX))) | ||
844 | return PM_INVAL_NUM_CHANNELS; | ||
845 | |||
846 | /* Request resource using PRCM API */ | ||
847 | for (ch = 0; ch < pm_sdmachan_num; ch++) { | ||
848 | retval = omap_request_dma(proc_id, | ||
849 | "ducati-ss", | ||
850 | NULL, | ||
851 | NULL, | ||
852 | &pm_sdmachan_dummy); | ||
853 | if (retval == 0) { | ||
854 | params->pm_sdmachan_counter++; | ||
855 | rcb_p->channels[ch] = (unsigned char)pm_sdmachan_dummy; | ||
856 | } else | ||
857 | goto clean_sdma; | ||
858 | } | ||
859 | return PM_SUCCESS; | ||
860 | clean_sdma: | ||
861 | /*failure, need to free the chanels*/ | ||
862 | for (ch_aux = 0; ch_aux < ch; ch_aux++) { | ||
863 | pm_sdmachan_dummy = (int)rcb_p->channels[ch_aux]; | ||
864 | omap_free_dma(pm_sdmachan_dummy); | ||
865 | params->pm_sdmachan_counter--; | ||
866 | } | ||
867 | return PM_INSUFFICIENT_CHANNELS; | ||
868 | } | ||
869 | |||
870 | /* | ||
871 | Request a gptimer on behalf of an IPU client | ||
872 | * | ||
873 | */ | ||
874 | static inline int ipu_pm_get_gptimer(int proc_id, u32 rcb_num) | ||
875 | { | ||
876 | struct ipu_pm_object *handle; | ||
877 | struct ipu_pm_params *params; | ||
878 | struct rcb_block *rcb_p; | ||
879 | struct omap_dm_timer *p_gpt = NULL; | ||
880 | int pm_gp_num; | ||
881 | |||
882 | /* get the handle to proper ipu pm object */ | ||
883 | handle = ipu_pm_get_handle(proc_id); | ||
884 | if (WARN_ON(unlikely(handle == NULL))) | ||
885 | return PM_NOT_INSTANTIATED; | ||
886 | |||
887 | params = handle->params; | ||
888 | if (WARN_ON(unlikely(params == NULL))) | ||
889 | return PM_NOT_INSTANTIATED; | ||
890 | |||
891 | /* Get pointer to the proper RCB */ | ||
892 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
893 | return PM_INVAL_RCB_NUM; | ||
894 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
895 | /* Request resource using PRCM API */ | ||
896 | for (pm_gp_num = 0; pm_gp_num < NUM_IPU_TIMERS; pm_gp_num++) { | ||
897 | if (GPTIMER_USE_MASK & (1 << ipu_timer_list[pm_gp_num])) { | ||
898 | p_gpt = omap_dm_timer_request_specific | ||
899 | (ipu_timer_list[pm_gp_num]); | ||
900 | } else | ||
901 | continue; | ||
902 | if (p_gpt != NULL) { | ||
903 | /* Clear the bit in the usage mask */ | ||
904 | GPTIMER_USE_MASK &= ~(1 << ipu_timer_list[pm_gp_num]); | ||
905 | break; | ||
906 | } | ||
907 | } | ||
908 | if (p_gpt == NULL) | ||
909 | return PM_NO_GPTIMER; | ||
910 | else { | ||
911 | /* Store the gptimer number and base address */ | ||
912 | rcb_p->fill9 = ipu_timer_list[pm_gp_num]; | ||
913 | rcb_p->mod_base_addr = (unsigned)p_gpt; | ||
914 | params->pm_gptimer_counter++; | ||
915 | return PM_SUCCESS; | ||
916 | } | ||
917 | } | ||
918 | |||
919 | /* | ||
920 | Request an i2c bus on behalf of an IPU client | ||
921 | * | ||
922 | */ | ||
923 | static inline int ipu_pm_get_i2c_bus(int proc_id, u32 rcb_num) | ||
924 | { | ||
925 | struct ipu_pm_object *handle; | ||
926 | struct ipu_pm_params *params; | ||
927 | struct rcb_block *rcb_p; | ||
928 | struct clk *p_i2c_clk; | ||
929 | int i2c_clk_status; | ||
930 | char i2c_name[I2C_NAME_SIZE]; | ||
931 | int pm_i2c_bus_num; | ||
932 | |||
933 | /* get the handle to proper ipu pm object */ | ||
934 | handle = ipu_pm_get_handle(proc_id); | ||
935 | if (WARN_ON(unlikely(handle == NULL))) | ||
936 | return PM_NOT_INSTANTIATED; | ||
937 | |||
938 | params = handle->params; | ||
939 | if (WARN_ON(unlikely(params == NULL))) | ||
940 | return PM_NOT_INSTANTIATED; | ||
941 | |||
942 | /* Get pointer to the proper RCB */ | ||
943 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
944 | return PM_INVAL_RCB_NUM; | ||
945 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
946 | |||
947 | pm_i2c_bus_num = rcb_p->fill9; | ||
948 | if (WARN_ON((pm_i2c_bus_num < I2C_BUS_MIN) || | ||
949 | (pm_i2c_bus_num > I2C_BUS_MAX))) | ||
950 | return PM_INVAL_NUM_I2C; | ||
951 | |||
952 | if (I2C_USE_MASK & (1 << pm_i2c_bus_num)) { | ||
953 | /* building the name for i2c_clk */ | ||
954 | sprintf(i2c_name, "i2c%d_fck", pm_i2c_bus_num); | ||
955 | |||
956 | /* Request resource using PRCM API */ | ||
957 | p_i2c_clk = omap_clk_get_by_name(i2c_name); | ||
958 | if (p_i2c_clk == NULL) | ||
959 | return PM_NO_I2C; | ||
960 | i2c_clk_status = clk_enable(p_i2c_clk); | ||
961 | if (i2c_clk_status != 0) | ||
962 | return PM_NO_I2C; | ||
963 | /* Clear the bit in the usage mask */ | ||
964 | I2C_USE_MASK &= ~(1 << pm_i2c_bus_num); | ||
965 | rcb_p->mod_base_addr = (unsigned)p_i2c_clk; | ||
966 | /* Get the HW spinlock and store it in the RCB */ | ||
967 | rcb_p->data[0] = i2c_spinlock_list[pm_i2c_bus_num]; | ||
968 | params->pm_i2c_bus_counter++; | ||
969 | |||
970 | return PM_SUCCESS; | ||
971 | } else | ||
972 | return PM_NO_I2C; | ||
973 | } | ||
974 | |||
975 | /* | ||
976 | Request a gpio on behalf of an IPU client | ||
977 | * | ||
978 | */ | ||
979 | static inline int ipu_pm_get_gpio(int proc_id, u32 rcb_num) | ||
980 | { | ||
981 | struct ipu_pm_object *handle; | ||
982 | struct ipu_pm_params *params; | ||
983 | struct rcb_block *rcb_p; | ||
984 | int pm_gpio_num; | ||
985 | int retval; | ||
986 | |||
987 | /* get the handle to proper ipu pm object */ | ||
988 | handle = ipu_pm_get_handle(proc_id); | ||
989 | if (WARN_ON(unlikely(handle == NULL))) | ||
990 | return PM_NOT_INSTANTIATED; | ||
991 | |||
992 | params = handle->params; | ||
993 | if (WARN_ON(unlikely(params == NULL))) | ||
994 | return PM_NOT_INSTANTIATED; | ||
995 | |||
996 | /* Get pointer to the proper RCB */ | ||
997 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
998 | return PM_INVAL_RCB_NUM; | ||
999 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1000 | |||
1001 | pm_gpio_num = rcb_p->fill9; | ||
1002 | retval = gpio_request(pm_gpio_num , "ducati-ss"); | ||
1003 | if (retval != 0) | ||
1004 | return PM_NO_GPIO; | ||
1005 | params->pm_gpio_counter++; | ||
1006 | |||
1007 | return PM_SUCCESS; | ||
1008 | } | ||
1009 | |||
1010 | /* | ||
1011 | Request a regulator on behalf of an IPU client | ||
1012 | * | ||
1013 | */ | ||
1014 | static inline int ipu_pm_get_regulator(int proc_id, u32 rcb_num) | ||
1015 | { | ||
1016 | struct ipu_pm_object *handle; | ||
1017 | struct ipu_pm_params *params; | ||
1018 | struct rcb_block *rcb_p; | ||
1019 | struct regulator *p_regulator = NULL; | ||
1020 | char *regulator_name; | ||
1021 | int pm_regulator_num; | ||
1022 | int retval = 0; | ||
1023 | |||
1024 | /* get the handle to proper ipu pm object */ | ||
1025 | handle = ipu_pm_get_handle(proc_id); | ||
1026 | if (WARN_ON(unlikely(handle == NULL))) | ||
1027 | return PM_NOT_INSTANTIATED; | ||
1028 | |||
1029 | params = handle->params; | ||
1030 | if (WARN_ON(unlikely(params == NULL))) | ||
1031 | return PM_NOT_INSTANTIATED; | ||
1032 | |||
1033 | /* Get pointer to the proper RCB */ | ||
1034 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1035 | return PM_INVAL_RCB_NUM; | ||
1036 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1037 | |||
1038 | pm_regulator_num = rcb_p->fill9; | ||
1039 | if (WARN_ON((pm_regulator_num < REGULATOR_MIN) || | ||
1040 | (pm_regulator_num > REGULATOR_MAX))) | ||
1041 | return PM_INVAL_REGULATOR; | ||
1042 | |||
1043 | /* | ||
1044 | FIXME:Only providing 1 regulator, if more are provided | ||
1045 | * this check is not valid. | ||
1046 | */ | ||
1047 | if (WARN_ON(params->pm_regulator_counter > 0)) | ||
1048 | return PM_INVAL_REGULATOR; | ||
1049 | |||
1050 | /* Search the name of regulator based on the id and request it */ | ||
1051 | regulator_name = ipu_regulator_name[pm_regulator_num - 1]; | ||
1052 | p_regulator = regulator_get(NULL, regulator_name); | ||
1053 | if (p_regulator == NULL) | ||
1054 | return PM_NO_REGULATOR; | ||
1055 | |||
1056 | /* Get and store the regulator default voltage */ | ||
1057 | cam2_prev_volt = regulator_get_voltage(p_regulator); | ||
1058 | |||
1059 | /* Set the regulator voltage min = data[0]; max = data[1]*/ | ||
1060 | retval = regulator_set_voltage(p_regulator, rcb_p->data[0], | ||
1061 | rcb_p->data[1]); | ||
1062 | if (retval) | ||
1063 | return PM_INVAL_REGULATOR; | ||
1064 | |||
1065 | /* Store the regulator handle in the RCB */ | ||
1066 | rcb_p->mod_base_addr = (unsigned)p_regulator; | ||
1067 | params->pm_regulator_counter++; | ||
1068 | |||
1069 | return PM_SUCCESS; | ||
1070 | } | ||
1071 | |||
1072 | /* | ||
1073 | Request an Aux clk on behalf of an IPU client | ||
1074 | * | ||
1075 | */ | ||
1076 | static inline int ipu_pm_get_aux_clk(int proc_id, u32 rcb_num) | ||
1077 | { | ||
1078 | struct ipu_pm_object *handle; | ||
1079 | struct ipu_pm_params *params; | ||
1080 | struct rcb_block *rcb_p; | ||
1081 | u32 tmp = 0; | ||
1082 | int pm_aux_clk_num; | ||
1083 | |||
1084 | /* get the handle to proper ipu pm object */ | ||
1085 | handle = ipu_pm_get_handle(proc_id); | ||
1086 | if (WARN_ON(unlikely(handle == NULL))) | ||
1087 | return PM_NOT_INSTANTIATED; | ||
1088 | |||
1089 | params = handle->params; | ||
1090 | if (WARN_ON(unlikely(params == NULL))) | ||
1091 | return PM_NOT_INSTANTIATED; | ||
1092 | |||
1093 | /* Get pointer to the proper RCB */ | ||
1094 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1095 | return PM_INVAL_RCB_NUM; | ||
1096 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1097 | |||
1098 | pm_aux_clk_num = rcb_p->fill9; | ||
1099 | |||
1100 | if (WARN_ON((pm_aux_clk_num < AUX_CLK_MIN) || | ||
1101 | (pm_aux_clk_num > AUX_CLK_MAX))) | ||
1102 | return PM_INVAL_AUX_CLK; | ||
1103 | |||
1104 | if (AUX_CLK_USE_MASK & (1 << pm_aux_clk_num)) { | ||
1105 | /* Build the value to write */ | ||
1106 | MASK_SET_FIELD(tmp, AUX_CLK_ENABLE, 0x1); | ||
1107 | MASK_SET_FIELD(tmp, AUX_CLK_SRCSELECT, 0x2); | ||
1108 | |||
1109 | /* Clear the bit in the usage mask */ | ||
1110 | AUX_CLK_USE_MASK &= ~(1 << pm_aux_clk_num); | ||
1111 | |||
1112 | /* Enabling aux clock */ | ||
1113 | __raw_writel(tmp, AUX_CLK_REG(pm_aux_clk_num)); | ||
1114 | |||
1115 | /* Store the aux clk addres in the RCB */ | ||
1116 | rcb_p->mod_base_addr = | ||
1117 | (unsigned __force)AUX_CLK_REG(pm_aux_clk_num); | ||
1118 | params->pm_aux_clk_counter++; | ||
1119 | } else | ||
1120 | return PM_NO_AUX_CLK; | ||
1121 | |||
1122 | return PM_SUCCESS; | ||
1123 | } | ||
1124 | |||
1125 | /* | ||
1126 | Request sys m3 on behalf of an IPU client | ||
1127 | * | ||
1128 | */ | ||
1129 | static inline int ipu_pm_get_sys_m3(int proc_id, u32 rcb_num) | ||
1130 | { | ||
1131 | struct ipu_pm_object *handle; | ||
1132 | struct ipu_pm_params *params; | ||
1133 | struct rcb_block *rcb_p; | ||
1134 | |||
1135 | /* get the handle to proper ipu pm object */ | ||
1136 | handle = ipu_pm_get_handle(proc_id); | ||
1137 | if (WARN_ON(unlikely(handle == NULL))) | ||
1138 | return PM_NOT_INSTANTIATED; | ||
1139 | |||
1140 | params = handle->params; | ||
1141 | if (WARN_ON(unlikely(params == NULL))) | ||
1142 | return PM_NOT_INSTANTIATED; | ||
1143 | |||
1144 | /* Get pointer to the proper RCB */ | ||
1145 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1146 | return PM_INVAL_RCB_NUM; | ||
1147 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1148 | |||
1149 | if (params->pm_sys_m3_counter) | ||
1150 | return PM_UNSUPPORTED; | ||
1151 | |||
1152 | pr_info("Request SYS M3\n"); | ||
1153 | |||
1154 | params->pm_sys_m3_counter++; | ||
1155 | |||
1156 | return PM_SUCCESS; | ||
1157 | } | ||
1158 | |||
1159 | /* | ||
1160 | Request app m3 on behalf of an IPU client | ||
1161 | * | ||
1162 | */ | ||
1163 | static inline int ipu_pm_get_app_m3(int proc_id, u32 rcb_num) | ||
1164 | { | ||
1165 | struct ipu_pm_object *handle; | ||
1166 | struct ipu_pm_params *params; | ||
1167 | struct rcb_block *rcb_p; | ||
1168 | |||
1169 | /* get the handle to proper ipu pm object */ | ||
1170 | handle = ipu_pm_get_handle(proc_id); | ||
1171 | if (WARN_ON(unlikely(handle == NULL))) | ||
1172 | return PM_NOT_INSTANTIATED; | ||
1173 | |||
1174 | params = handle->params; | ||
1175 | if (WARN_ON(unlikely(params == NULL))) | ||
1176 | return PM_NOT_INSTANTIATED; | ||
1177 | |||
1178 | /* Get pointer to the proper RCB */ | ||
1179 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1180 | return PM_INVAL_RCB_NUM; | ||
1181 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1182 | |||
1183 | if (params->pm_app_m3_counter) | ||
1184 | return PM_UNSUPPORTED; | ||
1185 | |||
1186 | pr_info("Request APP M3\n"); | ||
1187 | |||
1188 | params->pm_app_m3_counter++; | ||
1189 | |||
1190 | return PM_SUCCESS; | ||
1191 | } | ||
1192 | |||
1193 | /* | ||
1194 | Request L3 Bus on behalf of an IPU client | ||
1195 | * | ||
1196 | */ | ||
1197 | static inline int ipu_pm_get_l3_bus(int proc_id, u32 rcb_num) | ||
1198 | { | ||
1199 | struct ipu_pm_object *handle; | ||
1200 | struct ipu_pm_params *params; | ||
1201 | struct rcb_block *rcb_p; | ||
1202 | |||
1203 | /* get the handle to proper ipu pm object */ | ||
1204 | handle = ipu_pm_get_handle(proc_id); | ||
1205 | if (WARN_ON(unlikely(handle == NULL))) | ||
1206 | return PM_NOT_INSTANTIATED; | ||
1207 | |||
1208 | params = handle->params; | ||
1209 | if (WARN_ON(unlikely(params == NULL))) | ||
1210 | return PM_NOT_INSTANTIATED; | ||
1211 | |||
1212 | /* Get pointer to the proper RCB */ | ||
1213 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1214 | return PM_INVAL_RCB_NUM; | ||
1215 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1216 | |||
1217 | if (params->pm_l3_bus_counter) | ||
1218 | return PM_UNSUPPORTED; | ||
1219 | |||
1220 | pr_info("Request L3 BUS\n"); | ||
1221 | |||
1222 | params->pm_l3_bus_counter++; | ||
1223 | |||
1224 | return PM_SUCCESS; | ||
1225 | } | ||
1226 | |||
1227 | /* | ||
1228 | Request IVA HD on behalf of an IPU client | ||
1229 | * | ||
1230 | */ | ||
1231 | static inline int ipu_pm_get_iva_hd(int proc_id, u32 rcb_num) | ||
1232 | { | ||
1233 | struct ipu_pm_object *handle; | ||
1234 | struct ipu_pm_params *params; | ||
1235 | struct rcb_block *rcb_p; | ||
1236 | int retval; | ||
1237 | |||
1238 | /* get the handle to proper ipu pm object */ | ||
1239 | handle = ipu_pm_get_handle(proc_id); | ||
1240 | if (WARN_ON(unlikely(handle == NULL))) | ||
1241 | return PM_NOT_INSTANTIATED; | ||
1242 | |||
1243 | params = handle->params; | ||
1244 | if (WARN_ON(unlikely(params == NULL))) | ||
1245 | return PM_NOT_INSTANTIATED; | ||
1246 | |||
1247 | /* Get pointer to the proper RCB */ | ||
1248 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1249 | return PM_INVAL_RCB_NUM; | ||
1250 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1251 | |||
1252 | if (params->pm_iva_hd_counter) | ||
1253 | return PM_UNSUPPORTED; | ||
1254 | |||
1255 | pr_info("Request IVA_HD\n"); | ||
1256 | retval = omap_pm_set_max_mpu_wakeup_lat(&pm_qos_handle, | ||
1257 | IPU_PM_MM_MPU_LAT_CONSTRAINT); | ||
1258 | if (retval) | ||
1259 | return PM_UNSUPPORTED; | ||
1260 | |||
1261 | params->pm_iva_hd_counter++; | ||
1262 | |||
1263 | return PM_SUCCESS; | ||
1264 | } | ||
1265 | |||
1266 | /* | ||
1267 | Request FDIF on behalf of an IPU client | ||
1268 | * | ||
1269 | */ | ||
1270 | static inline int ipu_pm_get_fdif(int proc_id, u32 rcb_num) | ||
1271 | { | ||
1272 | struct ipu_pm_object *handle; | ||
1273 | struct ipu_pm_params *params; | ||
1274 | struct rcb_block *rcb_p; | ||
1275 | int retval; | ||
1276 | |||
1277 | /* get the handle to proper ipu pm object */ | ||
1278 | handle = ipu_pm_get_handle(proc_id); | ||
1279 | if (WARN_ON(unlikely(handle == NULL))) | ||
1280 | return PM_NOT_INSTANTIATED; | ||
1281 | |||
1282 | params = handle->params; | ||
1283 | if (WARN_ON(unlikely(params == NULL))) | ||
1284 | return PM_NOT_INSTANTIATED; | ||
1285 | |||
1286 | /* Get pointer to the proper RCB */ | ||
1287 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1288 | return PM_INVAL_RCB_NUM; | ||
1289 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1290 | |||
1291 | pr_info("Request FDIF\n"); | ||
1292 | if (params->pm_fdif_counter) | ||
1293 | return PM_UNSUPPORTED; | ||
1294 | |||
1295 | retval = ipu_pm_module_start(rcb_p->sub_type); | ||
1296 | printk(KERN_ERR "@@@@ cop_module_start( ) %s @@@@\n", | ||
1297 | retval ? "Failed" : "Successful"); | ||
1298 | params->pm_fdif_counter++; | ||
1299 | |||
1300 | return PM_SUCCESS; | ||
1301 | } | ||
1302 | |||
1303 | /* | ||
1304 | Request MPU on behalf of an IPU client | ||
1305 | * | ||
1306 | */ | ||
1307 | static inline int ipu_pm_get_mpu(int proc_id, u32 rcb_num) | ||
1308 | { | ||
1309 | struct ipu_pm_object *handle; | ||
1310 | struct ipu_pm_params *params; | ||
1311 | struct rcb_block *rcb_p; | ||
1312 | int retval; | ||
1313 | |||
1314 | /* get the handle to proper ipu pm object */ | ||
1315 | handle = ipu_pm_get_handle(proc_id); | ||
1316 | if (WARN_ON(unlikely(handle == NULL))) | ||
1317 | return PM_NOT_INSTANTIATED; | ||
1318 | |||
1319 | params = handle->params; | ||
1320 | if (WARN_ON(unlikely(params == NULL))) | ||
1321 | return PM_NOT_INSTANTIATED; | ||
1322 | |||
1323 | /* Get pointer to the proper RCB */ | ||
1324 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1325 | return PM_INVAL_RCB_NUM; | ||
1326 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1327 | |||
1328 | pr_info("Request MPU\n"); | ||
1329 | if (params->pm_mpu_counter) | ||
1330 | return PM_UNSUPPORTED; | ||
1331 | |||
1332 | retval = ipu_pm_module_start(rcb_p->sub_type); | ||
1333 | printk(KERN_ERR "@@@@ cop_module_start( ) %s @@@@\n", | ||
1334 | retval ? "Failed" : "Successful"); | ||
1335 | params->pm_mpu_counter++; | ||
1336 | |||
1337 | return PM_SUCCESS; | ||
1338 | } | ||
1339 | |||
1340 | /* | ||
1341 | Request IPU on behalf of an IPU client | ||
1342 | * | ||
1343 | */ | ||
1344 | static inline int ipu_pm_get_ipu(int proc_id, u32 rcb_num) | ||
1345 | { | ||
1346 | struct ipu_pm_object *handle; | ||
1347 | struct ipu_pm_params *params; | ||
1348 | struct rcb_block *rcb_p; | ||
1349 | int retval; | ||
1350 | |||
1351 | /* get the handle to proper ipu pm object */ | ||
1352 | handle = ipu_pm_get_handle(proc_id); | ||
1353 | if (WARN_ON(unlikely(handle == NULL))) | ||
1354 | return PM_NOT_INSTANTIATED; | ||
1355 | |||
1356 | params = handle->params; | ||
1357 | if (WARN_ON(unlikely(params == NULL))) | ||
1358 | return PM_NOT_INSTANTIATED; | ||
1359 | |||
1360 | /* Get pointer to the proper RCB */ | ||
1361 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1362 | return PM_INVAL_RCB_NUM; | ||
1363 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1364 | |||
1365 | pr_info("Request IPU\n"); | ||
1366 | if (params->pm_ipu_counter) | ||
1367 | return PM_UNSUPPORTED; | ||
1368 | |||
1369 | retval = ipu_pm_module_start(rcb_p->sub_type); | ||
1370 | printk(KERN_ERR "@@@@ cop_module_start( ) %s @@@@\n", | ||
1371 | retval ? "Failed" : "Successful"); | ||
1372 | params->pm_ipu_counter++; | ||
1373 | |||
1374 | return PM_SUCCESS; | ||
1375 | } | ||
1376 | |||
1377 | |||
1378 | |||
1379 | /* | ||
1380 | Request IVA SEQ0 on behalf of an IPU client | ||
1381 | * | ||
1382 | */ | ||
1383 | static inline int ipu_pm_get_ivaseq0(int proc_id, u32 rcb_num) | ||
1384 | { | ||
1385 | struct ipu_pm_object *handle; | ||
1386 | struct ipu_pm_params *params; | ||
1387 | struct rcb_block *rcb_p; | ||
1388 | int retval; | ||
1389 | |||
1390 | /* get the handle to proper ipu pm object */ | ||
1391 | handle = ipu_pm_get_handle(proc_id); | ||
1392 | if (WARN_ON(unlikely(handle == NULL))) | ||
1393 | return PM_NOT_INSTANTIATED; | ||
1394 | |||
1395 | params = handle->params; | ||
1396 | if (WARN_ON(unlikely(params == NULL))) | ||
1397 | return PM_NOT_INSTANTIATED; | ||
1398 | |||
1399 | /* Get pointer to the proper RCB */ | ||
1400 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1401 | return PM_INVAL_RCB_NUM; | ||
1402 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1403 | |||
1404 | pr_info("Request IVASEQ0\n"); | ||
1405 | if (params->pm_ivaseq0_counter) | ||
1406 | return PM_UNSUPPORTED; | ||
1407 | |||
1408 | retval = ipu_pm_module_start(rcb_p->sub_type); | ||
1409 | printk(KERN_ERR "@@@@ cop_module_start( ) %s @@@@\n", | ||
1410 | retval ? "Failed" : "Successful"); | ||
1411 | params->pm_ivaseq0_counter++; | ||
1412 | |||
1413 | return PM_SUCCESS; | ||
1414 | } | ||
1415 | |||
1416 | /* | ||
1417 | Request IVA SEQ1 on behalf of an IPU client | ||
1418 | * | ||
1419 | */ | ||
1420 | static inline int ipu_pm_get_ivaseq1(int proc_id, u32 rcb_num) | ||
1421 | { | ||
1422 | struct ipu_pm_object *handle; | ||
1423 | struct ipu_pm_params *params; | ||
1424 | struct rcb_block *rcb_p; | ||
1425 | int retval; | ||
1426 | |||
1427 | /* get the handle to proper ipu pm object */ | ||
1428 | handle = ipu_pm_get_handle(proc_id); | ||
1429 | if (WARN_ON(unlikely(handle == NULL))) | ||
1430 | return PM_NOT_INSTANTIATED; | ||
1431 | |||
1432 | params = handle->params; | ||
1433 | if (WARN_ON(unlikely(params == NULL))) | ||
1434 | return PM_NOT_INSTANTIATED; | ||
1435 | |||
1436 | /* Get pointer to the proper RCB */ | ||
1437 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1438 | return PM_INVAL_RCB_NUM; | ||
1439 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1440 | |||
1441 | pr_info("Request IVASEQ1\n"); | ||
1442 | if (params->pm_ivaseq1_counter) | ||
1443 | return PM_UNSUPPORTED; | ||
1444 | |||
1445 | retval = ipu_pm_module_start(rcb_p->sub_type); | ||
1446 | printk(KERN_ERR "@@@@ cop_module_start( ) %s @@@@\n", | ||
1447 | retval ? "Failed" : "Successful"); | ||
1448 | params->pm_ivaseq1_counter++; | ||
1449 | |||
1450 | return PM_SUCCESS; | ||
1451 | } | ||
1452 | |||
1453 | /* | ||
1454 | Request ISS on behalf of an IPU client | ||
1455 | * | ||
1456 | */ | ||
1457 | static inline int ipu_pm_get_iss(int proc_id, u32 rcb_num) | ||
1458 | { | ||
1459 | struct ipu_pm_object *handle; | ||
1460 | struct ipu_pm_params *params; | ||
1461 | struct rcb_block *rcb_p; | ||
1462 | int retval; | ||
1463 | |||
1464 | /* get the handle to proper ipu pm object */ | ||
1465 | handle = ipu_pm_get_handle(proc_id); | ||
1466 | if (WARN_ON(unlikely(handle == NULL))) | ||
1467 | return PM_NOT_INSTANTIATED; | ||
1468 | |||
1469 | params = handle->params; | ||
1470 | if (WARN_ON(unlikely(params == NULL))) | ||
1471 | return PM_NOT_INSTANTIATED; | ||
1472 | |||
1473 | /* Get pointer to the proper RCB */ | ||
1474 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1475 | return PM_INVAL_RCB_NUM; | ||
1476 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1477 | |||
1478 | if (params->pm_iss_counter) | ||
1479 | return PM_UNSUPPORTED; | ||
1480 | |||
1481 | pr_info("Request ISS\n"); | ||
1482 | retval = omap_pm_set_max_mpu_wakeup_lat(&pm_qos_handle, | ||
1483 | IPU_PM_MM_MPU_LAT_CONSTRAINT); | ||
1484 | if (retval) | ||
1485 | return PM_UNSUPPORTED; | ||
1486 | |||
1487 | params->pm_iss_counter++; | ||
1488 | |||
1489 | return PM_SUCCESS; | ||
1490 | } | ||
1491 | |||
1492 | /* | ||
1493 | Release a sdma on behalf of an IPU client | ||
1494 | * | ||
1495 | */ | ||
1496 | static inline int ipu_pm_rel_sdma_chan(int proc_id, u32 rcb_num) | ||
1497 | { | ||
1498 | struct ipu_pm_object *handle; | ||
1499 | struct ipu_pm_params *params; | ||
1500 | struct rcb_block *rcb_p; | ||
1501 | int pm_sdmachan_num; | ||
1502 | int pm_sdmachan_dummy; | ||
1503 | int ch; | ||
1504 | |||
1505 | /* get the handle to proper ipu pm object */ | ||
1506 | handle = ipu_pm_get_handle(proc_id); | ||
1507 | if (WARN_ON(unlikely(handle == NULL))) | ||
1508 | return PM_NOT_INSTANTIATED; | ||
1509 | |||
1510 | params = handle->params; | ||
1511 | if (WARN_ON(unlikely(params == NULL))) | ||
1512 | return PM_NOT_INSTANTIATED; | ||
1513 | |||
1514 | /* Get pointer to the proper RCB */ | ||
1515 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1516 | return PM_INVAL_RCB_NUM; | ||
1517 | |||
1518 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1519 | |||
1520 | /* Release resource using PRCM API */ | ||
1521 | pm_sdmachan_num = rcb_p->num_chan; | ||
1522 | for (ch = 0; ch < pm_sdmachan_num; ch++) { | ||
1523 | pm_sdmachan_dummy = (int)rcb_p->channels[ch]; | ||
1524 | omap_free_dma(pm_sdmachan_dummy); | ||
1525 | params->pm_sdmachan_counter--; | ||
1526 | } | ||
1527 | return PM_SUCCESS; | ||
1528 | } | ||
1529 | |||
1530 | /* | ||
1531 | Release a gptimer on behalf of an IPU client | ||
1532 | * | ||
1533 | */ | ||
1534 | static inline int ipu_pm_rel_gptimer(int proc_id, u32 rcb_num) | ||
1535 | { | ||
1536 | struct ipu_pm_object *handle; | ||
1537 | struct ipu_pm_params *params; | ||
1538 | struct rcb_block *rcb_p; | ||
1539 | struct omap_dm_timer *p_gpt; | ||
1540 | int pm_gptimer_num; | ||
1541 | |||
1542 | /* get the handle to proper ipu pm object */ | ||
1543 | handle = ipu_pm_get_handle(proc_id); | ||
1544 | if (WARN_ON(unlikely(handle == NULL))) | ||
1545 | return PM_NOT_INSTANTIATED; | ||
1546 | |||
1547 | params = handle->params; | ||
1548 | if (WARN_ON(unlikely(params == NULL))) | ||
1549 | return PM_NOT_INSTANTIATED; | ||
1550 | |||
1551 | /* Get pointer to the proper RCB */ | ||
1552 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1553 | return PM_INVAL_RCB_NUM; | ||
1554 | |||
1555 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1556 | |||
1557 | p_gpt = (struct omap_dm_timer *)rcb_p->mod_base_addr; | ||
1558 | pm_gptimer_num = rcb_p->fill9; | ||
1559 | |||
1560 | /* Check the usage mask */ | ||
1561 | if (GPTIMER_USE_MASK & (1 << pm_gptimer_num)) | ||
1562 | return PM_NO_GPTIMER; | ||
1563 | |||
1564 | /* Set the usage mask for reuse */ | ||
1565 | GPTIMER_USE_MASK |= (1 << pm_gptimer_num); | ||
1566 | |||
1567 | /* Release resource using PRCM API */ | ||
1568 | if (p_gpt != NULL) | ||
1569 | omap_dm_timer_free(p_gpt); | ||
1570 | rcb_p->mod_base_addr = 0; | ||
1571 | params->pm_gptimer_counter--; | ||
1572 | return PM_SUCCESS; | ||
1573 | } | ||
1574 | |||
1575 | /* | ||
1576 | Release an i2c buses on behalf of an IPU client | ||
1577 | * | ||
1578 | */ | ||
1579 | static inline int ipu_pm_rel_i2c_bus(int proc_id, u32 rcb_num) | ||
1580 | { | ||
1581 | struct ipu_pm_object *handle; | ||
1582 | struct ipu_pm_params *params; | ||
1583 | struct rcb_block *rcb_p; | ||
1584 | struct clk *p_i2c_clk; | ||
1585 | int pm_i2c_bus_num; | ||
1586 | |||
1587 | /* get the handle to proper ipu pm object */ | ||
1588 | handle = ipu_pm_get_handle(proc_id); | ||
1589 | if (WARN_ON(unlikely(handle == NULL))) | ||
1590 | return PM_NOT_INSTANTIATED; | ||
1591 | |||
1592 | params = handle->params; | ||
1593 | if (WARN_ON(unlikely(params == NULL))) | ||
1594 | return PM_NOT_INSTANTIATED;; | ||
1595 | |||
1596 | /* Get pointer to the proper RCB */ | ||
1597 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1598 | return PM_INVAL_RCB_NUM; | ||
1599 | |||
1600 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1601 | pm_i2c_bus_num = rcb_p->fill9; | ||
1602 | p_i2c_clk = (struct clk *)rcb_p->mod_base_addr; | ||
1603 | |||
1604 | /* Check the usage mask */ | ||
1605 | if (I2C_USE_MASK & (1 << pm_i2c_bus_num)) | ||
1606 | return PM_NO_I2C; | ||
1607 | |||
1608 | /* Release resource using PRCM API */ | ||
1609 | clk_disable(p_i2c_clk); | ||
1610 | rcb_p->mod_base_addr = 0; | ||
1611 | |||
1612 | /* Set the usage mask for reuse */ | ||
1613 | I2C_USE_MASK |= (1 << pm_i2c_bus_num); | ||
1614 | |||
1615 | params->pm_i2c_bus_counter--; | ||
1616 | |||
1617 | return PM_SUCCESS; | ||
1618 | } | ||
1619 | |||
1620 | /* | ||
1621 | Release a gpio on behalf of an IPU client | ||
1622 | * | ||
1623 | */ | ||
1624 | static inline int ipu_pm_rel_gpio(int proc_id, u32 rcb_num) | ||
1625 | { | ||
1626 | struct ipu_pm_object *handle; | ||
1627 | struct ipu_pm_params *params; | ||
1628 | struct rcb_block *rcb_p; | ||
1629 | int pm_gpio_num; | ||
1630 | |||
1631 | /* get the handle to proper ipu pm object */ | ||
1632 | handle = ipu_pm_get_handle(proc_id); | ||
1633 | if (WARN_ON(unlikely(handle == NULL))) | ||
1634 | return PM_NOT_INSTANTIATED; | ||
1635 | |||
1636 | params = handle->params; | ||
1637 | if (WARN_ON(unlikely(params == NULL))) | ||
1638 | return PM_NOT_INSTANTIATED; | ||
1639 | |||
1640 | /* Get pointer to the proper RCB */ | ||
1641 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1642 | return PM_INVAL_RCB_NUM; | ||
1643 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1644 | |||
1645 | pm_gpio_num = rcb_p->fill9; | ||
1646 | gpio_free(pm_gpio_num); | ||
1647 | params->pm_gpio_counter--; | ||
1648 | |||
1649 | return PM_SUCCESS; | ||
1650 | } | ||
1651 | |||
1652 | /* | ||
1653 | Release a regulator on behalf of an IPU client | ||
1654 | * | ||
1655 | */ | ||
1656 | static inline int ipu_pm_rel_regulator(int proc_id, u32 rcb_num) | ||
1657 | { | ||
1658 | struct ipu_pm_object *handle; | ||
1659 | struct ipu_pm_params *params; | ||
1660 | struct rcb_block *rcb_p; | ||
1661 | struct regulator *p_regulator = NULL; | ||
1662 | int retval = 0; | ||
1663 | |||
1664 | /* get the handle to proper ipu pm object */ | ||
1665 | handle = ipu_pm_get_handle(proc_id); | ||
1666 | if (WARN_ON(unlikely(handle == NULL))) | ||
1667 | return PM_NOT_INSTANTIATED; | ||
1668 | |||
1669 | params = handle->params; | ||
1670 | if (WARN_ON(unlikely(params == NULL))) | ||
1671 | return PM_NOT_INSTANTIATED; | ||
1672 | |||
1673 | /* Get pointer to the proper RCB */ | ||
1674 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1675 | return PM_INVAL_RCB_NUM; | ||
1676 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1677 | /* Get the regulator */ | ||
1678 | p_regulator = (struct regulator *)rcb_p->mod_base_addr; | ||
1679 | |||
1680 | /* Restart the voltage to the default value */ | ||
1681 | retval = regulator_set_voltage(p_regulator, cam2_prev_volt, | ||
1682 | cam2_prev_volt); | ||
1683 | if (retval) | ||
1684 | return PM_INVAL_REGULATOR; | ||
1685 | |||
1686 | /* Release resource using PRCM API */ | ||
1687 | regulator_put(p_regulator); | ||
1688 | |||
1689 | rcb_p->mod_base_addr = 0; | ||
1690 | params->pm_regulator_counter--; | ||
1691 | |||
1692 | return PM_SUCCESS; | ||
1693 | } | ||
1694 | |||
1695 | /* | ||
1696 | Release an Aux clk on behalf of an IPU client | ||
1697 | * | ||
1698 | */ | ||
1699 | static inline int ipu_pm_rel_aux_clk(int proc_id, u32 rcb_num) | ||
1700 | { | ||
1701 | struct ipu_pm_object *handle; | ||
1702 | struct ipu_pm_params *params; | ||
1703 | struct rcb_block *rcb_p; | ||
1704 | u32 tmp = 0; | ||
1705 | int pm_aux_clk_num; | ||
1706 | |||
1707 | /* get the handle to proper ipu pm object */ | ||
1708 | handle = ipu_pm_get_handle(proc_id); | ||
1709 | if (WARN_ON(unlikely(handle == NULL))) | ||
1710 | return PM_NOT_INSTANTIATED; | ||
1711 | |||
1712 | params = handle->params; | ||
1713 | if (WARN_ON(unlikely(params == NULL))) | ||
1714 | return PM_NOT_INSTANTIATED; | ||
1715 | |||
1716 | /* Get pointer to the proper RCB */ | ||
1717 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1718 | return PM_INVAL_RCB_NUM; | ||
1719 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1720 | |||
1721 | pm_aux_clk_num = rcb_p->fill9; | ||
1722 | |||
1723 | /* Check the usage mask */ | ||
1724 | if (AUX_CLK_USE_MASK & (1 << pm_aux_clk_num)) | ||
1725 | return PM_NO_AUX_CLK; | ||
1726 | |||
1727 | /* Build the value to write */ | ||
1728 | MASK_SET_FIELD(tmp, AUX_CLK_ENABLE, 0x0); | ||
1729 | MASK_SET_FIELD(tmp, AUX_CLK_SRCSELECT, 0x0); | ||
1730 | |||
1731 | /* Disabling aux clock */ | ||
1732 | __raw_writel(tmp, AUX_CLK_REG(pm_aux_clk_num)); | ||
1733 | |||
1734 | /* Set the usage mask for reuse */ | ||
1735 | AUX_CLK_USE_MASK |= (1 << pm_aux_clk_num); | ||
1736 | |||
1737 | rcb_p->mod_base_addr = 0; | ||
1738 | params->pm_aux_clk_counter--; | ||
1739 | |||
1740 | return PM_SUCCESS; | ||
1741 | } | ||
1742 | |||
1743 | /* | ||
1744 | Release sys m3 on behalf of an IPU client | ||
1745 | * | ||
1746 | */ | ||
1747 | static inline int ipu_pm_rel_sys_m3(int proc_id, u32 rcb_num) | ||
1748 | { | ||
1749 | struct ipu_pm_object *handle; | ||
1750 | struct ipu_pm_params *params; | ||
1751 | struct rcb_block *rcb_p; | ||
1752 | |||
1753 | /* get the handle to proper ipu pm object */ | ||
1754 | handle = ipu_pm_get_handle(proc_id); | ||
1755 | if (WARN_ON(unlikely(handle == NULL))) | ||
1756 | return PM_NOT_INSTANTIATED; | ||
1757 | |||
1758 | params = handle->params; | ||
1759 | if (WARN_ON(unlikely(params == NULL))) | ||
1760 | return PM_NOT_INSTANTIATED; | ||
1761 | |||
1762 | /* Get pointer to the proper RCB */ | ||
1763 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1764 | return PM_INVAL_RCB_NUM; | ||
1765 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1766 | |||
1767 | pr_info("Release SYS M3\n"); | ||
1768 | |||
1769 | if (!params->pm_sys_m3_counter) | ||
1770 | goto error; | ||
1771 | params->pm_sys_m3_counter--; | ||
1772 | |||
1773 | return PM_SUCCESS; | ||
1774 | error: | ||
1775 | return PM_UNSUPPORTED; | ||
1776 | } | ||
1777 | |||
1778 | /* | ||
1779 | Release app m3 on behalf of an IPU client | ||
1780 | * | ||
1781 | */ | ||
1782 | static inline int ipu_pm_rel_app_m3(int proc_id, u32 rcb_num) | ||
1783 | { | ||
1784 | struct ipu_pm_object *handle; | ||
1785 | struct ipu_pm_params *params; | ||
1786 | struct rcb_block *rcb_p; | ||
1787 | |||
1788 | /* get the handle to proper ipu pm object */ | ||
1789 | handle = ipu_pm_get_handle(proc_id); | ||
1790 | if (WARN_ON(unlikely(handle == NULL))) | ||
1791 | return PM_NOT_INSTANTIATED; | ||
1792 | |||
1793 | params = handle->params; | ||
1794 | if (WARN_ON(unlikely(params == NULL))) | ||
1795 | return PM_NOT_INSTANTIATED; | ||
1796 | |||
1797 | /* Get pointer to the proper RCB */ | ||
1798 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1799 | return PM_INVAL_RCB_NUM; | ||
1800 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1801 | |||
1802 | pr_info("Release APP M3\n"); | ||
1803 | |||
1804 | if (!params->pm_app_m3_counter) | ||
1805 | goto error; | ||
1806 | params->pm_app_m3_counter--; | ||
1807 | |||
1808 | return PM_SUCCESS; | ||
1809 | error: | ||
1810 | return PM_UNSUPPORTED; | ||
1811 | } | ||
1812 | |||
1813 | /* | ||
1814 | Release L3 Bus on behalf of an IPU client | ||
1815 | * | ||
1816 | */ | ||
1817 | static inline int ipu_pm_rel_l3_bus(int proc_id, u32 rcb_num) | ||
1818 | { | ||
1819 | struct ipu_pm_object *handle; | ||
1820 | struct ipu_pm_params *params; | ||
1821 | struct rcb_block *rcb_p; | ||
1822 | |||
1823 | /* get the handle to proper ipu pm object */ | ||
1824 | handle = ipu_pm_get_handle(proc_id); | ||
1825 | if (WARN_ON(unlikely(handle == NULL))) | ||
1826 | return PM_NOT_INSTANTIATED; | ||
1827 | |||
1828 | params = handle->params; | ||
1829 | if (WARN_ON(unlikely(params == NULL))) | ||
1830 | return PM_NOT_INSTANTIATED; | ||
1831 | |||
1832 | /* Get pointer to the proper RCB */ | ||
1833 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1834 | return PM_INVAL_RCB_NUM; | ||
1835 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1836 | |||
1837 | pr_info("Release L3 BUS\n"); | ||
1838 | |||
1839 | if (!params->pm_l3_bus_counter) | ||
1840 | goto error; | ||
1841 | params->pm_l3_bus_counter--; | ||
1842 | |||
1843 | return PM_SUCCESS; | ||
1844 | error: | ||
1845 | return PM_UNSUPPORTED; | ||
1846 | } | ||
1847 | |||
1848 | /* | ||
1849 | Release FDIF on behalf of an IPU client | ||
1850 | * | ||
1851 | */ | ||
1852 | static inline int ipu_pm_rel_fdif(int proc_id, u32 rcb_num) | ||
1853 | { | ||
1854 | struct ipu_pm_object *handle; | ||
1855 | struct ipu_pm_params *params; | ||
1856 | struct rcb_block *rcb_p; | ||
1857 | int retval; | ||
1858 | |||
1859 | /* get the handle to proper ipu pm object */ | ||
1860 | handle = ipu_pm_get_handle(proc_id); | ||
1861 | if (WARN_ON(unlikely(handle == NULL))) | ||
1862 | return PM_NOT_INSTANTIATED; | ||
1863 | |||
1864 | params = handle->params; | ||
1865 | if (WARN_ON(unlikely(params == NULL))) | ||
1866 | return PM_NOT_INSTANTIATED; | ||
1867 | |||
1868 | /* Get pointer to the proper RCB */ | ||
1869 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1870 | return PM_INVAL_RCB_NUM; | ||
1871 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1872 | |||
1873 | pr_info("Release FDIF\n"); | ||
1874 | |||
1875 | if (!params->pm_fdif_counter) | ||
1876 | goto error; | ||
1877 | |||
1878 | retval = ipu_pm_module_stop(rcb_p->sub_type); | ||
1879 | printk(KERN_ERR "@@@@ cop_module_stop( ) %s @@@@\n", | ||
1880 | retval ? "Failed" : "Successful"); | ||
1881 | params->pm_fdif_counter--; | ||
1882 | |||
1883 | return PM_SUCCESS; | ||
1884 | error: | ||
1885 | return PM_UNSUPPORTED; | ||
1886 | } | ||
1887 | |||
1888 | /* | ||
1889 | Release MPU on behalf of an IPU client | ||
1890 | * | ||
1891 | */ | ||
1892 | static inline int ipu_pm_rel_mpu(int proc_id, u32 rcb_num) | ||
1893 | { | ||
1894 | struct ipu_pm_object *handle; | ||
1895 | struct ipu_pm_params *params; | ||
1896 | struct rcb_block *rcb_p; | ||
1897 | int retval; | ||
1898 | |||
1899 | /* get the handle to proper ipu pm object */ | ||
1900 | handle = ipu_pm_get_handle(proc_id); | ||
1901 | if (WARN_ON(unlikely(handle == NULL))) | ||
1902 | return PM_NOT_INSTANTIATED; | ||
1903 | |||
1904 | params = handle->params; | ||
1905 | if (WARN_ON(unlikely(params == NULL))) | ||
1906 | return PM_NOT_INSTANTIATED; | ||
1907 | |||
1908 | /* Get pointer to the proper RCB */ | ||
1909 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1910 | return PM_INVAL_RCB_NUM; | ||
1911 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1912 | |||
1913 | pr_info("Release MPU\n"); | ||
1914 | |||
1915 | if (!params->pm_mpu_counter) | ||
1916 | goto error; | ||
1917 | |||
1918 | retval = ipu_pm_module_stop(rcb_p->sub_type); | ||
1919 | printk(KERN_ERR "@@@@ cop_module_stop( ) %s @@@@\n", | ||
1920 | retval ? "Failed" : "Successful"); | ||
1921 | params->pm_mpu_counter--; | ||
1922 | |||
1923 | return PM_SUCCESS; | ||
1924 | error: | ||
1925 | return PM_UNSUPPORTED; | ||
1926 | } | ||
1927 | |||
1928 | /* | ||
1929 | Release IPU on behalf of an IPU client | ||
1930 | * | ||
1931 | */ | ||
1932 | static inline int ipu_pm_rel_ipu(int proc_id, u32 rcb_num) | ||
1933 | { | ||
1934 | struct ipu_pm_object *handle; | ||
1935 | struct ipu_pm_params *params; | ||
1936 | struct rcb_block *rcb_p; | ||
1937 | int retval; | ||
1938 | |||
1939 | /* get the handle to proper ipu pm object */ | ||
1940 | handle = ipu_pm_get_handle(proc_id); | ||
1941 | if (WARN_ON(unlikely(handle == NULL))) | ||
1942 | return PM_NOT_INSTANTIATED; | ||
1943 | |||
1944 | params = handle->params; | ||
1945 | if (WARN_ON(unlikely(params == NULL))) | ||
1946 | return PM_NOT_INSTANTIATED; | ||
1947 | |||
1948 | /* Get pointer to the proper RCB */ | ||
1949 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1950 | return PM_INVAL_RCB_NUM; | ||
1951 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1952 | |||
1953 | pr_info("Release IPU\n"); | ||
1954 | |||
1955 | if (!params->pm_ipu_counter) | ||
1956 | goto error; | ||
1957 | |||
1958 | retval = ipu_pm_module_stop(rcb_p->sub_type); | ||
1959 | printk(KERN_ERR "@@@@ cop_module_stop( ) %s @@@@\n", | ||
1960 | retval ? "Failed" : "Successful"); | ||
1961 | params->pm_ipu_counter--; | ||
1962 | |||
1963 | return PM_SUCCESS; | ||
1964 | error: | ||
1965 | return PM_UNSUPPORTED; | ||
1966 | } | ||
1967 | |||
1968 | /* | ||
1969 | Release IVA HD on behalf of an IPU client | ||
1970 | * | ||
1971 | */ | ||
1972 | static inline int ipu_pm_rel_iva_hd(int proc_id, u32 rcb_num) | ||
1973 | { | ||
1974 | struct ipu_pm_object *handle; | ||
1975 | struct ipu_pm_params *params; | ||
1976 | struct rcb_block *rcb_p; | ||
1977 | int retval; | ||
1978 | |||
1979 | /* get the handle to proper ipu pm object */ | ||
1980 | handle = ipu_pm_get_handle(proc_id); | ||
1981 | if (WARN_ON(unlikely(handle == NULL))) | ||
1982 | return PM_NOT_INSTANTIATED; | ||
1983 | |||
1984 | params = handle->params; | ||
1985 | if (WARN_ON(unlikely(params == NULL))) | ||
1986 | return PM_NOT_INSTANTIATED; | ||
1987 | |||
1988 | /* Get pointer to the proper RCB */ | ||
1989 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
1990 | return PM_INVAL_RCB_NUM; | ||
1991 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
1992 | |||
1993 | pr_info("Release IVA_HD\n"); | ||
1994 | |||
1995 | if (!params->pm_iva_hd_counter) | ||
1996 | goto error; | ||
1997 | |||
1998 | params->pm_iva_hd_counter--; | ||
1999 | |||
2000 | if (params->pm_iva_hd_counter == 0 && params->pm_iss_counter == 0) { | ||
2001 | retval = omap_pm_set_max_mpu_wakeup_lat(&pm_qos_handle, | ||
2002 | IPU_PM_NO_MPU_LAT_CONSTRAINT); | ||
2003 | if (retval) | ||
2004 | goto error; | ||
2005 | } | ||
2006 | |||
2007 | return PM_SUCCESS; | ||
2008 | error: | ||
2009 | return PM_UNSUPPORTED; | ||
2010 | } | ||
2011 | |||
2012 | /* | ||
2013 | Release IVA SEQ0 on behalf of an IPU client | ||
2014 | * | ||
2015 | */ | ||
2016 | static inline int ipu_pm_rel_ivaseq0(int proc_id, u32 rcb_num) | ||
2017 | { | ||
2018 | struct ipu_pm_object *handle; | ||
2019 | struct ipu_pm_params *params; | ||
2020 | struct rcb_block *rcb_p; | ||
2021 | int retval; | ||
2022 | |||
2023 | /* get the handle to proper ipu pm object */ | ||
2024 | handle = ipu_pm_get_handle(proc_id); | ||
2025 | if (WARN_ON(unlikely(handle == NULL))) | ||
2026 | return PM_NOT_INSTANTIATED; | ||
2027 | |||
2028 | params = handle->params; | ||
2029 | if (WARN_ON(unlikely(params == NULL))) | ||
2030 | return PM_NOT_INSTANTIATED; | ||
2031 | |||
2032 | /* Get pointer to the proper RCB */ | ||
2033 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
2034 | return PM_INVAL_RCB_NUM; | ||
2035 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
2036 | |||
2037 | pr_info("Release IVASEQ0\n"); | ||
2038 | |||
2039 | if (!params->pm_ivaseq0_counter) | ||
2040 | goto error; | ||
2041 | |||
2042 | retval = ipu_pm_module_stop(rcb_p->sub_type); | ||
2043 | printk(KERN_ERR "@@@@ cop_module_stop( ) %s @@@@\n", | ||
2044 | retval ? "Failed" : "Successful"); | ||
2045 | params->pm_ivaseq0_counter--; | ||
2046 | |||
2047 | return PM_SUCCESS; | ||
2048 | error: | ||
2049 | return PM_UNSUPPORTED; | ||
2050 | } | ||
2051 | |||
2052 | /* | ||
2053 | Release IVA SEQ1 on behalf of an IPU client | ||
2054 | * | ||
2055 | */ | ||
2056 | static inline int ipu_pm_rel_ivaseq1(int proc_id, u32 rcb_num) | ||
2057 | { | ||
2058 | struct ipu_pm_object *handle; | ||
2059 | struct ipu_pm_params *params; | ||
2060 | struct rcb_block *rcb_p; | ||
2061 | int retval; | ||
2062 | |||
2063 | /* get the handle to proper ipu pm object */ | ||
2064 | handle = ipu_pm_get_handle(proc_id); | ||
2065 | if (WARN_ON(unlikely(handle == NULL))) | ||
2066 | return PM_NOT_INSTANTIATED; | ||
2067 | |||
2068 | params = handle->params; | ||
2069 | if (WARN_ON(unlikely(params == NULL))) | ||
2070 | return PM_NOT_INSTANTIATED; | ||
2071 | |||
2072 | /* Get pointer to the proper RCB */ | ||
2073 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
2074 | return PM_INVAL_RCB_NUM; | ||
2075 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
2076 | |||
2077 | pr_info("Release IVASEQ1\n"); | ||
2078 | |||
2079 | if (!params->pm_ivaseq1_counter) | ||
2080 | goto error; | ||
2081 | |||
2082 | retval = ipu_pm_module_stop(rcb_p->sub_type); | ||
2083 | printk(KERN_ERR "@@@@ cop_module_stop( ) %s @@@@\n", | ||
2084 | retval ? "Failed" : "Successful"); | ||
2085 | params->pm_ivaseq1_counter--; | ||
2086 | |||
2087 | return PM_SUCCESS; | ||
2088 | error: | ||
2089 | return PM_UNSUPPORTED; | ||
2090 | } | ||
2091 | |||
2092 | /* | ||
2093 | Release ISS on behalf of an IPU client | ||
2094 | * | ||
2095 | */ | ||
2096 | static inline int ipu_pm_rel_iss(int proc_id, u32 rcb_num) | ||
2097 | { | ||
2098 | struct ipu_pm_object *handle; | ||
2099 | struct ipu_pm_params *params; | ||
2100 | struct rcb_block *rcb_p; | ||
2101 | int retval; | ||
2102 | |||
2103 | /* get the handle to proper ipu pm object */ | ||
2104 | handle = ipu_pm_get_handle(proc_id); | ||
2105 | if (WARN_ON(unlikely(handle == NULL))) | ||
2106 | return PM_NOT_INSTANTIATED; | ||
2107 | |||
2108 | params = handle->params; | ||
2109 | if (WARN_ON(unlikely(params == NULL))) | ||
2110 | return PM_NOT_INSTANTIATED; | ||
2111 | |||
2112 | /* Get pointer to the proper RCB */ | ||
2113 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
2114 | return PM_INVAL_RCB_NUM; | ||
2115 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
2116 | |||
2117 | pr_info("Release ISS\n"); | ||
2118 | |||
2119 | if (!params->pm_iss_counter) | ||
2120 | goto error; | ||
2121 | |||
2122 | params->pm_iss_counter--; | ||
2123 | |||
2124 | if (params->pm_iva_hd_counter == 0 && params->pm_iss_counter == 0) { | ||
2125 | retval = omap_pm_set_max_mpu_wakeup_lat(&pm_qos_handle, | ||
2126 | IPU_PM_NO_MPU_LAT_CONSTRAINT); | ||
2127 | if (retval) | ||
2128 | goto error; | ||
2129 | } | ||
2130 | |||
2131 | return PM_SUCCESS; | ||
2132 | error: | ||
2133 | return PM_UNSUPPORTED; | ||
2134 | } | ||
2135 | |||
2136 | /* | ||
2137 | Request a FDIF constraint on behalf of an IPU client | ||
2138 | * | ||
2139 | */ | ||
2140 | static inline int ipu_pm_req_cstr_fdif(int proc_id, u32 rcb_num) | ||
2141 | { | ||
2142 | struct ipu_pm_object *handle; | ||
2143 | struct ipu_pm_params *params; | ||
2144 | struct rcb_block *rcb_p; | ||
2145 | int perf; | ||
2146 | int lat; | ||
2147 | int bw; | ||
2148 | u32 cstr_flags; | ||
2149 | |||
2150 | /* get the handle to proper ipu pm object */ | ||
2151 | handle = ipu_pm_get_handle(proc_id); | ||
2152 | if (WARN_ON(unlikely(handle == NULL))) | ||
2153 | return PM_NOT_INSTANTIATED; | ||
2154 | |||
2155 | params = handle->params; | ||
2156 | if (WARN_ON(unlikely(params == NULL))) | ||
2157 | return PM_NOT_INSTANTIATED; | ||
2158 | |||
2159 | /* Get pointer to the proper RCB */ | ||
2160 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
2161 | return PM_INVAL_RCB_NUM; | ||
2162 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
2163 | |||
2164 | /* Get the configurable constraints */ | ||
2165 | cstr_flags = rcb_p->data[0]; | ||
2166 | |||
2167 | /* TODO: call the baseport APIs */ | ||
2168 | if (cstr_flags & PM_CSTR_PERF_MASK) { | ||
2169 | perf = rcb_p->data[1]; | ||
2170 | pr_info("Request perfomance Cstr FDIF:%d\n", perf); | ||
2171 | } | ||
2172 | |||
2173 | if (cstr_flags & PM_CSTR_LAT_MASK) { | ||
2174 | lat = rcb_p->data[2]; | ||
2175 | pr_info("Request latency Cstr FDIF:%d\n", lat); | ||
2176 | } | ||
2177 | |||
2178 | if (cstr_flags & PM_CSTR_BW_MASK) { | ||
2179 | bw = rcb_p->data[3]; | ||
2180 | pr_info("Request bandwidth Cstr FDIF:%d\n", bw); | ||
2181 | } | ||
2182 | |||
2183 | return PM_SUCCESS; | ||
2184 | } | ||
2185 | |||
2186 | /* | ||
2187 | Request a IPU constraint on behalf of an IPU client | ||
2188 | * | ||
2189 | */ | ||
2190 | static inline int ipu_pm_req_cstr_ipu(int proc_id, u32 rcb_num) | ||
2191 | { | ||
2192 | struct ipu_pm_object *handle; | ||
2193 | struct ipu_pm_params *params; | ||
2194 | struct rcb_block *rcb_p; | ||
2195 | int perf; | ||
2196 | int lat; | ||
2197 | int bw; | ||
2198 | u32 cstr_flags; | ||
2199 | |||
2200 | /* get the handle to proper ipu pm object */ | ||
2201 | handle = ipu_pm_get_handle(proc_id); | ||
2202 | if (WARN_ON(unlikely(handle == NULL))) | ||
2203 | return PM_NOT_INSTANTIATED; | ||
2204 | |||
2205 | params = handle->params; | ||
2206 | if (WARN_ON(unlikely(params == NULL))) | ||
2207 | return PM_NOT_INSTANTIATED; | ||
2208 | |||
2209 | /* Get pointer to the proper RCB */ | ||
2210 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
2211 | return PM_INVAL_RCB_NUM; | ||
2212 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
2213 | |||
2214 | /* Get the configurable constraints */ | ||
2215 | cstr_flags = rcb_p->data[0]; | ||
2216 | |||
2217 | /* TODO: call the baseport APIs */ | ||
2218 | if (cstr_flags & PM_CSTR_PERF_MASK) { | ||
2219 | perf = rcb_p->data[1]; | ||
2220 | pr_info("Request perfomance Cstr IPU:%d\n", perf); | ||
2221 | } | ||
2222 | |||
2223 | if (cstr_flags & PM_CSTR_LAT_MASK) { | ||
2224 | lat = rcb_p->data[2]; | ||
2225 | pr_info("Request latency Cstr IPU:%d\n", lat); | ||
2226 | } | ||
2227 | |||
2228 | if (cstr_flags & PM_CSTR_BW_MASK) { | ||
2229 | bw = rcb_p->data[3]; | ||
2230 | pr_info("Request bandwidth Cstr IPU:%d\n", bw); | ||
2231 | } | ||
2232 | |||
2233 | return PM_SUCCESS; | ||
2234 | } | ||
2235 | |||
2236 | /* | ||
2237 | Request a L3 Bus constraint on behalf of an IPU client | ||
2238 | * | ||
2239 | */ | ||
2240 | static inline int ipu_pm_req_cstr_l3_bus(int proc_id, u32 rcb_num) | ||
2241 | { | ||
2242 | struct ipu_pm_object *handle; | ||
2243 | struct ipu_pm_params *params; | ||
2244 | struct rcb_block *rcb_p; | ||
2245 | int perf; | ||
2246 | int lat; | ||
2247 | int bw; | ||
2248 | u32 cstr_flags; | ||
2249 | |||
2250 | /* get the handle to proper ipu pm object */ | ||
2251 | handle = ipu_pm_get_handle(proc_id); | ||
2252 | if (WARN_ON(unlikely(handle == NULL))) | ||
2253 | return PM_NOT_INSTANTIATED; | ||
2254 | |||
2255 | params = handle->params; | ||
2256 | if (WARN_ON(unlikely(params == NULL))) | ||
2257 | return PM_NOT_INSTANTIATED; | ||
2258 | |||
2259 | /* Get pointer to the proper RCB */ | ||
2260 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
2261 | return PM_INVAL_RCB_NUM; | ||
2262 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
2263 | |||
2264 | /* Get the configurable constraints */ | ||
2265 | cstr_flags = rcb_p->data[0]; | ||
2266 | |||
2267 | /* TODO: call the baseport APIs */ | ||
2268 | if (cstr_flags & PM_CSTR_PERF_MASK) { | ||
2269 | perf = rcb_p->data[1]; | ||
2270 | pr_info("Request perfomance Cstr L3 Bus:%d\n", perf); | ||
2271 | } | ||
2272 | |||
2273 | if (cstr_flags & PM_CSTR_LAT_MASK) { | ||
2274 | lat = rcb_p->data[2]; | ||
2275 | pr_info("Request latency Cstr L3 Bus:%d\n", lat); | ||
2276 | } | ||
2277 | |||
2278 | if (cstr_flags & PM_CSTR_BW_MASK) { | ||
2279 | bw = rcb_p->data[3]; | ||
2280 | pr_info("Request bandwidth Cstr L3 Bus:%d\n", bw); | ||
2281 | } | ||
2282 | |||
2283 | return PM_SUCCESS; | ||
2284 | } | ||
2285 | |||
2286 | /* | ||
2287 | Request an IVA HD constraint on behalf of an IPU client | ||
2288 | * | ||
2289 | */ | ||
2290 | static inline int ipu_pm_req_cstr_iva_hd(int proc_id, u32 rcb_num) | ||
2291 | { | ||
2292 | struct ipu_pm_object *handle; | ||
2293 | struct ipu_pm_params *params; | ||
2294 | struct rcb_block *rcb_p; | ||
2295 | int perf; | ||
2296 | int lat; | ||
2297 | int bw; | ||
2298 | u32 cstr_flags; | ||
2299 | |||
2300 | /* get the handle to proper ipu pm object */ | ||
2301 | handle = ipu_pm_get_handle(proc_id); | ||
2302 | if (WARN_ON(unlikely(handle == NULL))) | ||
2303 | return PM_NOT_INSTANTIATED; | ||
2304 | |||
2305 | params = handle->params; | ||
2306 | if (WARN_ON(unlikely(params == NULL))) | ||
2307 | return PM_NOT_INSTANTIATED; | ||
2308 | |||
2309 | /* Get pointer to the proper RCB */ | ||
2310 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
2311 | return PM_INVAL_RCB_NUM; | ||
2312 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
2313 | |||
2314 | /* Get the configurable constraints */ | ||
2315 | cstr_flags = rcb_p->data[0]; | ||
2316 | |||
2317 | /* TODO: call the baseport APIs */ | ||
2318 | if (cstr_flags & PM_CSTR_PERF_MASK) { | ||
2319 | perf = rcb_p->data[1]; | ||
2320 | pr_info("Request perfomance Cstr IVA HD:%d\n", perf); | ||
2321 | } | ||
2322 | |||
2323 | if (cstr_flags & PM_CSTR_LAT_MASK) { | ||
2324 | lat = rcb_p->data[2]; | ||
2325 | pr_info("Request latency Cstr IVA HD:%d\n", lat); | ||
2326 | } | ||
2327 | |||
2328 | if (cstr_flags & PM_CSTR_BW_MASK) { | ||
2329 | bw = rcb_p->data[3]; | ||
2330 | pr_info("Request bandwidth Cstr IVA HD:%d\n", bw); | ||
2331 | } | ||
2332 | |||
2333 | return PM_SUCCESS; | ||
2334 | } | ||
2335 | |||
2336 | /* | ||
2337 | Request an ISS constraint on behalf of an IPU client | ||
2338 | * | ||
2339 | */ | ||
2340 | static inline int ipu_pm_req_cstr_iss(int proc_id, u32 rcb_num) | ||
2341 | { | ||
2342 | struct ipu_pm_object *handle; | ||
2343 | struct ipu_pm_params *params; | ||
2344 | struct rcb_block *rcb_p; | ||
2345 | int perf; | ||
2346 | int lat; | ||
2347 | int bw; | ||
2348 | u32 cstr_flags; | ||
2349 | |||
2350 | /* get the handle to proper ipu pm object */ | ||
2351 | handle = ipu_pm_get_handle(proc_id); | ||
2352 | if (WARN_ON(unlikely(handle == NULL))) | ||
2353 | return PM_NOT_INSTANTIATED; | ||
2354 | |||
2355 | params = handle->params; | ||
2356 | if (WARN_ON(unlikely(params == NULL))) | ||
2357 | return PM_NOT_INSTANTIATED; | ||
2358 | |||
2359 | /* Get pointer to the proper RCB */ | ||
2360 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
2361 | return PM_INVAL_RCB_NUM; | ||
2362 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
2363 | |||
2364 | /* Get the configurable constraints */ | ||
2365 | cstr_flags = rcb_p->data[0]; | ||
2366 | |||
2367 | /* TODO: call the baseport APIs */ | ||
2368 | if (cstr_flags & PM_CSTR_PERF_MASK) { | ||
2369 | perf = rcb_p->data[1]; | ||
2370 | pr_info("Request perfomance Cstr ISS:%d\n", perf); | ||
2371 | } | ||
2372 | |||
2373 | if (cstr_flags & PM_CSTR_LAT_MASK) { | ||
2374 | lat = rcb_p->data[2]; | ||
2375 | pr_info("Request latency Cstr ISS:%d\n", lat); | ||
2376 | } | ||
2377 | |||
2378 | if (cstr_flags & PM_CSTR_BW_MASK) { | ||
2379 | bw = rcb_p->data[3]; | ||
2380 | pr_info("Request bandwidth Cstr ISS:%d\n", bw); | ||
2381 | } | ||
2382 | |||
2383 | return PM_SUCCESS; | ||
2384 | } | ||
2385 | |||
2386 | /* | ||
2387 | Request an MPU constraint on behalf of an IPU client | ||
2388 | * | ||
2389 | */ | ||
2390 | static inline int ipu_pm_req_cstr_mpu(int proc_id, u32 rcb_num) | ||
2391 | { | ||
2392 | struct ipu_pm_object *handle; | ||
2393 | struct ipu_pm_params *params; | ||
2394 | struct rcb_block *rcb_p; | ||
2395 | int perf; | ||
2396 | int lat; | ||
2397 | int bw; | ||
2398 | u32 cstr_flags; | ||
2399 | |||
2400 | /* get the handle to proper ipu pm object */ | ||
2401 | handle = ipu_pm_get_handle(proc_id); | ||
2402 | if (WARN_ON(unlikely(handle == NULL))) | ||
2403 | return PM_NOT_INSTANTIATED; | ||
2404 | |||
2405 | params = handle->params; | ||
2406 | if (WARN_ON(unlikely(params == NULL))) | ||
2407 | return PM_NOT_INSTANTIATED; | ||
2408 | |||
2409 | /* Get pointer to the proper RCB */ | ||
2410 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
2411 | return PM_INVAL_RCB_NUM; | ||
2412 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
2413 | |||
2414 | /* Get the configurable constraints */ | ||
2415 | cstr_flags = rcb_p->data[0]; | ||
2416 | |||
2417 | /* TODO: call the baseport APIs */ | ||
2418 | if (cstr_flags & PM_CSTR_PERF_MASK) { | ||
2419 | perf = rcb_p->data[1]; | ||
2420 | pr_info("Request perfomance Cstr MPU:%d\n", perf); | ||
2421 | } | ||
2422 | |||
2423 | if (cstr_flags & PM_CSTR_LAT_MASK) { | ||
2424 | lat = rcb_p->data[2]; | ||
2425 | pr_info("Request latency Cstr MPU:%d\n", lat); | ||
2426 | } | ||
2427 | |||
2428 | if (cstr_flags & PM_CSTR_BW_MASK) { | ||
2429 | bw = rcb_p->data[3]; | ||
2430 | pr_info("Request bandwidth Cstr MPU:%d\n", bw); | ||
2431 | } | ||
2432 | |||
2433 | return PM_SUCCESS; | ||
2434 | } | ||
2435 | |||
2436 | |||
2437 | /* | ||
2438 | Release a FDIF constraint on behalf of an IPU client | ||
2439 | * | ||
2440 | */ | ||
2441 | static inline int ipu_pm_rel_cstr_fdif(int proc_id, u32 rcb_num) | ||
2442 | { | ||
2443 | struct ipu_pm_object *handle; | ||
2444 | struct ipu_pm_params *params; | ||
2445 | struct rcb_block *rcb_p; | ||
2446 | int perf; | ||
2447 | int lat; | ||
2448 | int bw; | ||
2449 | u32 cstr_flags; | ||
2450 | |||
2451 | /* get the handle to proper ipu pm object */ | ||
2452 | handle = ipu_pm_get_handle(proc_id); | ||
2453 | if (WARN_ON(unlikely(handle == NULL))) | ||
2454 | return PM_NOT_INSTANTIATED; | ||
2455 | |||
2456 | params = handle->params; | ||
2457 | if (WARN_ON(unlikely(params == NULL))) | ||
2458 | return PM_NOT_INSTANTIATED; | ||
2459 | |||
2460 | /* Get pointer to the proper RCB */ | ||
2461 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
2462 | return PM_INVAL_RCB_NUM; | ||
2463 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
2464 | |||
2465 | /* Get the configurable constraints */ | ||
2466 | cstr_flags = rcb_p->data[0]; | ||
2467 | |||
2468 | /* TODO: call the baseport APIs */ | ||
2469 | if (cstr_flags & PM_CSTR_PERF_MASK) { | ||
2470 | perf = rcb_p->data[1]; | ||
2471 | pr_info("Release perfomance Cstr FDIF:%d\n", perf); | ||
2472 | } | ||
2473 | |||
2474 | if (cstr_flags & PM_CSTR_LAT_MASK) { | ||
2475 | lat = rcb_p->data[2]; | ||
2476 | pr_info("Release latency Cstr FDIF:%d\n", lat); | ||
2477 | } | ||
2478 | |||
2479 | if (cstr_flags & PM_CSTR_BW_MASK) { | ||
2480 | bw = rcb_p->data[3]; | ||
2481 | pr_info("Release bandwidth Cstr FDIF:%d\n", bw); | ||
2482 | } | ||
2483 | |||
2484 | return PM_SUCCESS; | ||
2485 | } | ||
2486 | |||
2487 | /* | ||
2488 | Release a IPU constraint on behalf of an IPU client | ||
2489 | * | ||
2490 | */ | ||
2491 | static inline int ipu_pm_rel_cstr_ipu(int proc_id, u32 rcb_num) | ||
2492 | { | ||
2493 | struct ipu_pm_object *handle; | ||
2494 | struct ipu_pm_params *params; | ||
2495 | struct rcb_block *rcb_p; | ||
2496 | int perf; | ||
2497 | int lat; | ||
2498 | int bw; | ||
2499 | u32 cstr_flags; | ||
2500 | |||
2501 | /* get the handle to proper ipu pm object */ | ||
2502 | handle = ipu_pm_get_handle(proc_id); | ||
2503 | if (WARN_ON(unlikely(handle == NULL))) | ||
2504 | return PM_NOT_INSTANTIATED; | ||
2505 | |||
2506 | params = handle->params; | ||
2507 | if (WARN_ON(unlikely(params == NULL))) | ||
2508 | return PM_NOT_INSTANTIATED; | ||
2509 | |||
2510 | /* Get pointer to the proper RCB */ | ||
2511 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
2512 | return PM_INVAL_RCB_NUM; | ||
2513 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
2514 | |||
2515 | /* Get the configurable constraints */ | ||
2516 | cstr_flags = rcb_p->data[0]; | ||
2517 | |||
2518 | /* TODO: call the baseport APIs */ | ||
2519 | if (cstr_flags & PM_CSTR_PERF_MASK) { | ||
2520 | perf = rcb_p->data[1]; | ||
2521 | pr_info("Release perfomance Cstr IPU:%d\n", perf); | ||
2522 | } | ||
2523 | |||
2524 | if (cstr_flags & PM_CSTR_LAT_MASK) { | ||
2525 | lat = rcb_p->data[2]; | ||
2526 | pr_info("Release latency Cstr IPU:%d\n", lat); | ||
2527 | } | ||
2528 | |||
2529 | if (cstr_flags & PM_CSTR_BW_MASK) { | ||
2530 | bw = rcb_p->data[3]; | ||
2531 | pr_info("Release bandwidth Cstr IPU:%d\n", bw); | ||
2532 | } | ||
2533 | |||
2534 | return PM_SUCCESS; | ||
2535 | } | ||
2536 | |||
2537 | /* | ||
2538 | Release a L3 Bus constraint on behalf of an IPU client | ||
2539 | * | ||
2540 | */ | ||
2541 | static inline int ipu_pm_rel_cstr_l3_bus(int proc_id, u32 rcb_num) | ||
2542 | { | ||
2543 | struct ipu_pm_object *handle; | ||
2544 | struct ipu_pm_params *params; | ||
2545 | struct rcb_block *rcb_p; | ||
2546 | int perf; | ||
2547 | int lat; | ||
2548 | int bw; | ||
2549 | u32 cstr_flags; | ||
2550 | |||
2551 | /* get the handle to proper ipu pm object */ | ||
2552 | handle = ipu_pm_get_handle(proc_id); | ||
2553 | if (WARN_ON(unlikely(handle == NULL))) | ||
2554 | return PM_NOT_INSTANTIATED; | ||
2555 | |||
2556 | params = handle->params; | ||
2557 | if (WARN_ON(unlikely(params == NULL))) | ||
2558 | return PM_NOT_INSTANTIATED; | ||
2559 | |||
2560 | /* Get pointer to the proper RCB */ | ||
2561 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
2562 | return PM_INVAL_RCB_NUM; | ||
2563 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
2564 | |||
2565 | /* Get the configurable constraints */ | ||
2566 | cstr_flags = rcb_p->data[0]; | ||
2567 | |||
2568 | /* TODO: call the baseport APIs */ | ||
2569 | if (cstr_flags & PM_CSTR_PERF_MASK) { | ||
2570 | perf = rcb_p->data[1]; | ||
2571 | pr_info("Release perfomance Cstr L3 Bus:%d\n", perf); | ||
2572 | } | ||
2573 | |||
2574 | if (cstr_flags & PM_CSTR_LAT_MASK) { | ||
2575 | lat = rcb_p->data[2]; | ||
2576 | pr_info("Release latency Cstr L3 Bus:%d\n", lat); | ||
2577 | } | ||
2578 | |||
2579 | if (cstr_flags & PM_CSTR_BW_MASK) { | ||
2580 | bw = rcb_p->data[3]; | ||
2581 | pr_info("Release bandwidth Cstr L3 Bus:%d\n", bw); | ||
2582 | } | ||
2583 | |||
2584 | return PM_SUCCESS; | ||
2585 | } | ||
2586 | |||
2587 | /* | ||
2588 | Release an IVA HD constraint on behalf of an IPU client | ||
2589 | * | ||
2590 | */ | ||
2591 | static inline int ipu_pm_rel_cstr_iva_hd(int proc_id, u32 rcb_num) | ||
2592 | { | ||
2593 | struct ipu_pm_object *handle; | ||
2594 | struct ipu_pm_params *params; | ||
2595 | struct rcb_block *rcb_p; | ||
2596 | int perf; | ||
2597 | int lat; | ||
2598 | int bw; | ||
2599 | u32 cstr_flags; | ||
2600 | |||
2601 | /* get the handle to proper ipu pm object */ | ||
2602 | handle = ipu_pm_get_handle(proc_id); | ||
2603 | if (WARN_ON(unlikely(handle == NULL))) | ||
2604 | return PM_NOT_INSTANTIATED; | ||
2605 | |||
2606 | params = handle->params; | ||
2607 | if (WARN_ON(unlikely(params == NULL))) | ||
2608 | return PM_NOT_INSTANTIATED; | ||
2609 | |||
2610 | /* Get pointer to the proper RCB */ | ||
2611 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
2612 | return PM_INVAL_RCB_NUM; | ||
2613 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
2614 | |||
2615 | /* Get the configurable constraints */ | ||
2616 | cstr_flags = rcb_p->data[0]; | ||
2617 | |||
2618 | /* TODO: call the baseport APIs */ | ||
2619 | if (cstr_flags & PM_CSTR_PERF_MASK) { | ||
2620 | perf = rcb_p->data[1]; | ||
2621 | pr_info("Release perfomance Cstr IVA HD:%d\n", perf); | ||
2622 | } | ||
2623 | |||
2624 | if (cstr_flags & PM_CSTR_LAT_MASK) { | ||
2625 | lat = rcb_p->data[2]; | ||
2626 | pr_info("Release latency Cstr IVA HD:%d\n", lat); | ||
2627 | } | ||
2628 | |||
2629 | if (cstr_flags & PM_CSTR_BW_MASK) { | ||
2630 | bw = rcb_p->data[3]; | ||
2631 | pr_info("Release bandwidth Cstr IVA HD:%d\n", bw); | ||
2632 | } | ||
2633 | |||
2634 | return PM_SUCCESS; | ||
2635 | } | ||
2636 | |||
2637 | /* | ||
2638 | Release an ISS constraint on behalf of an IPU client | ||
2639 | * | ||
2640 | */ | ||
2641 | static inline int ipu_pm_rel_cstr_iss(int proc_id, u32 rcb_num) | ||
2642 | { | ||
2643 | struct ipu_pm_object *handle; | ||
2644 | struct ipu_pm_params *params; | ||
2645 | struct rcb_block *rcb_p; | ||
2646 | int perf; | ||
2647 | int lat; | ||
2648 | int bw; | ||
2649 | u32 cstr_flags; | ||
2650 | |||
2651 | /* get the handle to proper ipu pm object */ | ||
2652 | handle = ipu_pm_get_handle(proc_id); | ||
2653 | if (WARN_ON(unlikely(handle == NULL))) | ||
2654 | return PM_NOT_INSTANTIATED; | ||
2655 | |||
2656 | params = handle->params; | ||
2657 | if (WARN_ON(unlikely(params == NULL))) | ||
2658 | return PM_NOT_INSTANTIATED; | ||
2659 | |||
2660 | /* Get pointer to the proper RCB */ | ||
2661 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
2662 | return PM_INVAL_RCB_NUM; | ||
2663 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
2664 | |||
2665 | /* Get the configurable constraints */ | ||
2666 | cstr_flags = rcb_p->data[0]; | ||
2667 | |||
2668 | /* TODO: call the baseport APIs */ | ||
2669 | if (cstr_flags & PM_CSTR_PERF_MASK) { | ||
2670 | perf = rcb_p->data[1]; | ||
2671 | pr_info("Release perfomance Cstr ISS:%d\n", perf); | ||
2672 | } | ||
2673 | |||
2674 | if (cstr_flags & PM_CSTR_LAT_MASK) { | ||
2675 | lat = rcb_p->data[2]; | ||
2676 | pr_info("Release latency Cstr ISS:%d\n", lat); | ||
2677 | } | ||
2678 | |||
2679 | if (cstr_flags & PM_CSTR_BW_MASK) { | ||
2680 | bw = rcb_p->data[3]; | ||
2681 | pr_info("Release bandwidth Cstr ISS:%d\n", bw); | ||
2682 | } | ||
2683 | |||
2684 | return PM_SUCCESS; | ||
2685 | } | ||
2686 | |||
2687 | /* | ||
2688 | Release an MPU constraint on behalf of an IPU client | ||
2689 | * | ||
2690 | */ | ||
2691 | static inline int ipu_pm_rel_cstr_mpu(int proc_id, u32 rcb_num) | ||
2692 | { | ||
2693 | struct ipu_pm_object *handle; | ||
2694 | struct ipu_pm_params *params; | ||
2695 | struct rcb_block *rcb_p; | ||
2696 | int perf; | ||
2697 | int lat; | ||
2698 | int bw; | ||
2699 | u32 cstr_flags; | ||
2700 | |||
2701 | /* get the handle to proper ipu pm object */ | ||
2702 | handle = ipu_pm_get_handle(proc_id); | ||
2703 | if (WARN_ON(unlikely(handle == NULL))) | ||
2704 | return PM_NOT_INSTANTIATED; | ||
2705 | |||
2706 | params = handle->params; | ||
2707 | if (WARN_ON(unlikely(params == NULL))) | ||
2708 | return PM_NOT_INSTANTIATED; | ||
2709 | |||
2710 | /* Get pointer to the proper RCB */ | ||
2711 | if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX))) | ||
2712 | return PM_INVAL_RCB_NUM; | ||
2713 | rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num]; | ||
2714 | |||
2715 | /* Get the configurable constraints */ | ||
2716 | cstr_flags = rcb_p->data[0]; | ||
2717 | |||
2718 | /* TODO: call the baseport APIs */ | ||
2719 | if (cstr_flags & PM_CSTR_PERF_MASK) { | ||
2720 | perf = rcb_p->data[1]; | ||
2721 | pr_info("Release perfomance Cstr MPU:%d\n", perf); | ||
2722 | } | ||
2723 | |||
2724 | if (cstr_flags & PM_CSTR_LAT_MASK) { | ||
2725 | lat = rcb_p->data[2]; | ||
2726 | pr_info("Release latency Cstr MPU:%d\n", lat); | ||
2727 | } | ||
2728 | |||
2729 | if (cstr_flags & PM_CSTR_BW_MASK) { | ||
2730 | bw = rcb_p->data[3]; | ||
2731 | pr_info("Release bandwidth Cstr MPU:%d\n", bw); | ||
2732 | } | ||
2733 | |||
2734 | return PM_SUCCESS; | ||
2735 | } | ||
2736 | |||
2737 | /* | ||
2738 | Function to set init parameters | ||
2739 | * | ||
2740 | */ | ||
2741 | void ipu_pm_params_init(struct ipu_pm_params *params) | ||
2742 | { | ||
2743 | int retval = 0; | ||
2744 | |||
2745 | if (WARN_ON(unlikely(params == NULL))) { | ||
2746 | retval = -EINVAL; | ||
2747 | goto exit; | ||
2748 | } | ||
2749 | |||
2750 | memcpy(params, &(pm_params), sizeof(struct ipu_pm_params)); | ||
2751 | return; | ||
2752 | exit: | ||
2753 | pr_err("ipu_pm_params_init failed status(0x%x)\n", retval); | ||
2754 | } | ||
2755 | EXPORT_SYMBOL(ipu_pm_params_init); | ||
2756 | |||
2757 | /* | ||
2758 | Function to calculate ipu_pm mem required | ||
2759 | * | ||
2760 | */ | ||
2761 | int ipu_pm_mem_req(const struct ipu_pm_params *params) | ||
2762 | { | ||
2763 | /* Memory required for ipu pm module */ | ||
2764 | /* FIXME: Maybe more than this is needed */ | ||
2765 | return sizeof(struct sms); | ||
2766 | } | ||
2767 | EXPORT_SYMBOL(ipu_pm_mem_req); | ||
2768 | |||
2769 | /* | ||
2770 | Function to register events | ||
2771 | This function will register the events needed for ipu_pm | ||
2772 | the events reserved for power management are 2 and 3 | ||
2773 | both sysm3 and appm3 will use the same events. | ||
2774 | */ | ||
2775 | int ipu_pm_init_transport(struct ipu_pm_object *handle) | ||
2776 | { | ||
2777 | int retval = 0; | ||
2778 | struct ipu_pm_params *params; | ||
2779 | |||
2780 | if (WARN_ON(unlikely(handle == NULL))) { | ||
2781 | retval = -EINVAL; | ||
2782 | goto pm_register_fail; | ||
2783 | } | ||
2784 | |||
2785 | params = handle->params; | ||
2786 | if (WARN_ON(unlikely(params == NULL))) { | ||
2787 | retval = -EINVAL; | ||
2788 | goto pm_register_fail; | ||
2789 | } | ||
2790 | |||
2791 | retval = notify_register_event( | ||
2792 | params->remote_proc_id, | ||
2793 | params->line_id, | ||
2794 | params->pm_resource_event | \ | ||
2795 | (NOTIFY_SYSTEMKEY << 16), | ||
2796 | (notify_fn_notify_cbck)ipu_pm_callback, | ||
2797 | (void *)NULL); | ||
2798 | if (retval < 0) | ||
2799 | goto pm_register_fail; | ||
2800 | |||
2801 | retval = notify_register_event( | ||
2802 | params->remote_proc_id, | ||
2803 | params->line_id, | ||
2804 | params->pm_notification_event | \ | ||
2805 | (NOTIFY_SYSTEMKEY << 16), | ||
2806 | (notify_fn_notify_cbck)ipu_pm_notify_callback, | ||
2807 | (void *)NULL); | ||
2808 | |||
2809 | if (retval < 0) { | ||
2810 | retval = notify_unregister_event( | ||
2811 | params->remote_proc_id, | ||
2812 | params->line_id, | ||
2813 | params->pm_resource_event | \ | ||
2814 | (NOTIFY_SYSTEMKEY << 16), | ||
2815 | (notify_fn_notify_cbck)ipu_pm_callback, | ||
2816 | (void *)NULL); | ||
2817 | if (retval < 0) | ||
2818 | pr_err("Error sending notify event\n"); | ||
2819 | goto pm_register_fail; | ||
2820 | } | ||
2821 | return retval; | ||
2822 | |||
2823 | pm_register_fail: | ||
2824 | pr_err("pm register events failed status(0x%x)", retval); | ||
2825 | return retval; | ||
2826 | } | ||
2827 | |||
2828 | /* | ||
2829 | Function to create ipu pm object | ||
2830 | * | ||
2831 | */ | ||
2832 | struct ipu_pm_object *ipu_pm_create(const struct ipu_pm_params *params) | ||
2833 | { | ||
2834 | int i; | ||
2835 | int retval = 0; | ||
2836 | |||
2837 | if (WARN_ON(unlikely(params == NULL))) { | ||
2838 | retval = -EINVAL; | ||
2839 | goto exit; | ||
2840 | } | ||
2841 | |||
2842 | if (params->remote_proc_id == SYS_M3) { | ||
2843 | pm_handle_sysm3 = kmalloc(sizeof(struct ipu_pm_object), | ||
2844 | GFP_ATOMIC); | ||
2845 | |||
2846 | if (WARN_ON(unlikely(pm_handle_sysm3 == NULL))) { | ||
2847 | retval = -EINVAL; | ||
2848 | goto exit; | ||
2849 | } | ||
2850 | |||
2851 | pm_handle_sysm3->rcb_table = (struct sms *)params->shared_addr; | ||
2852 | |||
2853 | pm_handle_sysm3->pm_event = kzalloc(sizeof(struct pm_event) | ||
2854 | * params->pm_num_events, GFP_KERNEL); | ||
2855 | |||
2856 | if (WARN_ON(unlikely(pm_handle_sysm3->pm_event == NULL))) { | ||
2857 | retval = -EINVAL; | ||
2858 | kfree(pm_handle_sysm3); | ||
2859 | goto exit; | ||
2860 | } | ||
2861 | |||
2862 | /* Each event has it own sem */ | ||
2863 | for (i = 0; i < params->pm_num_events; i++) { | ||
2864 | sema_init(&pm_handle_sysm3->pm_event[i].sem_handle, 0); | ||
2865 | pm_handle_sysm3->pm_event[i].event_type = i; | ||
2866 | } | ||
2867 | |||
2868 | pm_handle_sysm3->params = kzalloc(sizeof(struct ipu_pm_params) | ||
2869 | , GFP_KERNEL); | ||
2870 | |||
2871 | if (WARN_ON(unlikely(pm_handle_sysm3->params == NULL))) { | ||
2872 | retval = -EINVAL; | ||
2873 | kfree(pm_handle_sysm3->pm_event); | ||
2874 | kfree(pm_handle_sysm3); | ||
2875 | goto exit; | ||
2876 | } | ||
2877 | |||
2878 | memcpy(pm_handle_sysm3->params, params, | ||
2879 | sizeof(struct ipu_pm_params)); | ||
2880 | |||
2881 | /* Check the SW version on both sides */ | ||
2882 | if (WARN_ON(pm_handle_sysm3->rcb_table->pm_version != | ||
2883 | PM_VERSION)) | ||
2884 | pr_warning("Mismatch in PM version Host:0x%08x " | ||
2885 | "Remote:0x%08x", PM_VERSION, | ||
2886 | pm_handle_sysm3->rcb_table->pm_version); | ||
2887 | |||
2888 | spin_lock_init(&pm_handle_sysm3->lock); | ||
2889 | INIT_WORK(&pm_handle_sysm3->work, ipu_pm_work); | ||
2890 | |||
2891 | if (!kfifo_alloc(&pm_handle_sysm3->fifo, | ||
2892 | IPU_KFIFO_SIZE * sizeof(struct ipu_pm_msg), | ||
2893 | GFP_KERNEL)) | ||
2894 | return pm_handle_sysm3; | ||
2895 | |||
2896 | retval = -ENOMEM; | ||
2897 | kfree(pm_handle_sysm3->params); | ||
2898 | kfree(pm_handle_sysm3->pm_event); | ||
2899 | kfree(pm_handle_sysm3); | ||
2900 | } else if (params->remote_proc_id == APP_M3) { | ||
2901 | pm_handle_appm3 = kmalloc(sizeof(struct ipu_pm_object), | ||
2902 | GFP_ATOMIC); | ||
2903 | |||
2904 | if (WARN_ON(unlikely(pm_handle_appm3 == NULL))) { | ||
2905 | retval = -EINVAL; | ||
2906 | goto exit; | ||
2907 | } | ||
2908 | |||
2909 | pm_handle_appm3->rcb_table = (struct sms *)params->shared_addr; | ||
2910 | |||
2911 | pm_handle_appm3->pm_event = kzalloc(sizeof(struct pm_event) | ||
2912 | * params->pm_num_events, GFP_KERNEL); | ||
2913 | |||
2914 | if (WARN_ON(unlikely(pm_handle_appm3->pm_event == NULL))) { | ||
2915 | retval = -EINVAL; | ||
2916 | kfree(pm_handle_appm3); | ||
2917 | goto exit; | ||
2918 | } | ||
2919 | |||
2920 | /* Each event has it own sem */ | ||
2921 | for (i = 0; i < params->pm_num_events; i++) { | ||
2922 | sema_init(&pm_handle_appm3->pm_event[i].sem_handle, 0); | ||
2923 | pm_handle_appm3->pm_event[i].event_type = i; | ||
2924 | } | ||
2925 | |||
2926 | pm_handle_appm3->params = kzalloc(sizeof(struct ipu_pm_params) | ||
2927 | , GFP_KERNEL); | ||
2928 | |||
2929 | if (WARN_ON(unlikely(pm_handle_appm3->params == NULL))) { | ||
2930 | retval = -EINVAL; | ||
2931 | kfree(pm_handle_appm3->pm_event); | ||
2932 | kfree(pm_handle_appm3); | ||
2933 | goto exit; | ||
2934 | } | ||
2935 | |||
2936 | memcpy(pm_handle_appm3->params, params, | ||
2937 | sizeof(struct ipu_pm_params)); | ||
2938 | |||
2939 | /* Check the SW version on both sides */ | ||
2940 | if (WARN_ON(pm_handle_appm3->rcb_table->pm_version != | ||
2941 | PM_VERSION)) | ||
2942 | pr_warning("Mismatch in PM version Host:0x%08x " | ||
2943 | "Remote:0x%08x", PM_VERSION, | ||
2944 | pm_handle_appm3->rcb_table->pm_version); | ||
2945 | |||
2946 | spin_lock_init(&pm_handle_appm3->lock); | ||
2947 | INIT_WORK(&pm_handle_appm3->work, ipu_pm_work); | ||
2948 | |||
2949 | if (!kfifo_alloc(&pm_handle_appm3->fifo, | ||
2950 | IPU_KFIFO_SIZE * sizeof(struct ipu_pm_msg), | ||
2951 | GFP_KERNEL)) | ||
2952 | return pm_handle_appm3; | ||
2953 | |||
2954 | retval = -ENOMEM; | ||
2955 | kfree(pm_handle_appm3->params); | ||
2956 | kfree(pm_handle_appm3->pm_event); | ||
2957 | kfree(pm_handle_appm3); | ||
2958 | } else | ||
2959 | retval = -EINVAL; | ||
2960 | |||
2961 | exit: | ||
2962 | pr_err("ipu_pm_create failed! " | ||
2963 | "status = 0x%x\n", retval); | ||
2964 | return NULL; | ||
2965 | } | ||
2966 | |||
2967 | /* | ||
2968 | Function to delete ipu pm object | ||
2969 | * | ||
2970 | */ | ||
2971 | void ipu_pm_delete(struct ipu_pm_object *handle) | ||
2972 | { | ||
2973 | int retval = 0; | ||
2974 | struct ipu_pm_params *params; | ||
2975 | |||
2976 | if (WARN_ON(unlikely(handle == NULL))) { | ||
2977 | retval = -EINVAL; | ||
2978 | goto exit; | ||
2979 | } | ||
2980 | |||
2981 | params = handle->params; | ||
2982 | if (WARN_ON(unlikely(params == NULL))) { | ||
2983 | retval = -EINVAL; | ||
2984 | goto exit; | ||
2985 | } | ||
2986 | |||
2987 | /* Release the shared RCB */ | ||
2988 | handle->rcb_table = NULL; | ||
2989 | |||
2990 | kfree(handle->pm_event); | ||
2991 | if (params->remote_proc_id == SYS_M3) | ||
2992 | pm_handle_sysm3 = NULL; | ||
2993 | else | ||
2994 | pm_handle_appm3 = NULL; | ||
2995 | kfree(handle->params); | ||
2996 | kfree(handle); | ||
2997 | return; | ||
2998 | exit: | ||
2999 | pr_err("ipu_pm_delete is already NULL " | ||
3000 | "status = 0x%x\n", retval); | ||
3001 | } | ||
3002 | |||
3003 | /* | ||
3004 | Function to get the ducati state flag from Share memory | ||
3005 | * | ||
3006 | */ | ||
3007 | u32 ipu_pm_get_state(int proc_id) | ||
3008 | { | ||
3009 | struct ipu_pm_object *handle; | ||
3010 | |||
3011 | /* get the handle to proper ipu pm object */ | ||
3012 | handle = ipu_pm_get_handle(proc_id); | ||
3013 | if (WARN_ON(unlikely(handle == NULL))) | ||
3014 | return -EINVAL; | ||
3015 | |||
3016 | return handle->rcb_table->state_flag; | ||
3017 | } | ||
3018 | |||
3019 | /* | ||
3020 | Function to get ipu pm object | ||
3021 | * | ||
3022 | */ | ||
3023 | struct ipu_pm_object *ipu_pm_get_handle(int proc_id) | ||
3024 | { | ||
3025 | if (proc_id == SYS_M3) | ||
3026 | return pm_handle_sysm3; | ||
3027 | else if (proc_id == APP_M3) | ||
3028 | return pm_handle_appm3; | ||
3029 | else | ||
3030 | return NULL; | ||
3031 | } | ||
3032 | EXPORT_SYMBOL(ipu_pm_get_handle); | ||
3033 | |||
3034 | /* | ||
3035 | Function to save a processor context and send it to hibernate | ||
3036 | * | ||
3037 | */ | ||
3038 | int ipu_pm_save_ctx(int proc_id) | ||
3039 | { | ||
3040 | int retval = 0; | ||
3041 | int flag; | ||
3042 | int num_loaded_cores = 0; | ||
3043 | int sys_loaded; | ||
3044 | int app_loaded; | ||
3045 | unsigned long timeout; | ||
3046 | struct ipu_pm_object *handle; | ||
3047 | |||
3048 | /* get the handle to proper ipu pm object */ | ||
3049 | handle = ipu_pm_get_handle(proc_id); | ||
3050 | if (WARN_ON(unlikely(handle == NULL))) | ||
3051 | return -EINVAL; | ||
3052 | |||
3053 | /* Check if the M3 was loaded */ | ||
3054 | sys_loaded = (ipu_pm_get_state(proc_id) & SYS_PROC_LOADED) >> | ||
3055 | PROC_LD_SHIFT; | ||
3056 | app_loaded = (ipu_pm_get_state(proc_id) & APP_PROC_LOADED) >> | ||
3057 | PROC_LD_SHIFT; | ||
3058 | |||
3059 | /* Because of the current scheme, we need to check | ||
3060 | * if APPM3 is enable and we need to shut it down too | ||
3061 | * Sysm3 is the only want sending the hibernate message | ||
3062 | */ | ||
3063 | mutex_lock(ipu_pm_state.gate_handle); | ||
3064 | if (proc_id == SYS_M3 || proc_id == APP_M3) { | ||
3065 | if (!sys_loaded) | ||
3066 | goto exit; | ||
3067 | |||
3068 | num_loaded_cores = app_loaded + sys_loaded; | ||
3069 | |||
3070 | flag = 1; | ||
3071 | timeout = jiffies + msecs_to_jiffies(WAIT_FOR_IDLE_TIMEOUT); | ||
3072 | /* Wait fot Ducati to hibernate */ | ||
3073 | do { | ||
3074 | /* Checking if IPU is really in idle */ | ||
3075 | if (NUM_IDLE_CORES == num_loaded_cores) { | ||
3076 | flag = 0; | ||
3077 | break; | ||
3078 | } | ||
3079 | } while (!time_after(jiffies, timeout)); | ||
3080 | if (flag) | ||
3081 | goto error; | ||
3082 | |||
3083 | /* Check for APPM3, if loaded reset first */ | ||
3084 | if (app_loaded) { | ||
3085 | retval = rproc_sleep(app_rproc); | ||
3086 | if (retval) | ||
3087 | goto error; | ||
3088 | handle->rcb_table->state_flag |= APP_PROC_DOWN; | ||
3089 | } | ||
3090 | retval = rproc_sleep(sys_rproc); | ||
3091 | if (retval) | ||
3092 | goto error; | ||
3093 | handle->rcb_table->state_flag |= SYS_PROC_DOWN; | ||
3094 | omap_mbox_save_ctx(ducati_mbox); | ||
3095 | iommu_save_ctx(ducati_iommu); | ||
3096 | } else | ||
3097 | goto error; | ||
3098 | exit: | ||
3099 | mutex_unlock(ipu_pm_state.gate_handle); | ||
3100 | return 0; | ||
3101 | error: | ||
3102 | mutex_unlock(ipu_pm_state.gate_handle); | ||
3103 | pr_info("Aborting hibernation process\n"); | ||
3104 | return -EINVAL; | ||
3105 | } | ||
3106 | EXPORT_SYMBOL(ipu_pm_save_ctx); | ||
3107 | |||
3108 | /* | ||
3109 | Function to check if a processor is shutdown | ||
3110 | if shutdown then restore context else return. | ||
3111 | * | ||
3112 | */ | ||
3113 | int ipu_pm_restore_ctx(int proc_id) | ||
3114 | { | ||
3115 | int retval = 0; | ||
3116 | int sys_loaded; | ||
3117 | int app_loaded; | ||
3118 | struct ipu_pm_object *handle; | ||
3119 | |||
3120 | /*If feature not supported by proc, return*/ | ||
3121 | if (!proc_supported(proc_id)) | ||
3122 | return 0; | ||
3123 | |||
3124 | /* get the handle to proper ipu pm object */ | ||
3125 | handle = ipu_pm_get_handle(proc_id); | ||
3126 | |||
3127 | if (WARN_ON(unlikely(handle == NULL))) | ||
3128 | return -EINVAL; | ||
3129 | |||
3130 | /* By default Ducati Hibernation is disable | ||
3131 | * enabling just the first time and if | ||
3132 | * CONFIG_SYSLINK_DUCATI_PM is defined | ||
3133 | */ | ||
3134 | if (first_time) { | ||
3135 | handle->rcb_table->state_flag |= ENABLE_IPU_HIB; | ||
3136 | handle->rcb_table->pm_flags.hibernateAllowed = 1; | ||
3137 | first_time = 0; | ||
3138 | } | ||
3139 | |||
3140 | /* Check if the M3 was loaded */ | ||
3141 | sys_loaded = (ipu_pm_get_state(proc_id) & SYS_PROC_LOADED) >> | ||
3142 | PROC_LD_SHIFT; | ||
3143 | app_loaded = (ipu_pm_get_state(proc_id) & APP_PROC_LOADED) >> | ||
3144 | PROC_LD_SHIFT; | ||
3145 | |||
3146 | /* Because of the current scheme, we need to check | ||
3147 | * if APPM3 is enable and we need to enable it too | ||
3148 | * In both cases we should check if for both cores | ||
3149 | * and enable them if they were loaded. | ||
3150 | */ | ||
3151 | mutex_lock(ipu_pm_state.gate_handle); | ||
3152 | if (proc_id == SYS_M3 || proc_id == APP_M3) { | ||
3153 | if (!(ipu_pm_get_state(proc_id) & SYS_PROC_DOWN)) | ||
3154 | goto exit; | ||
3155 | |||
3156 | omap_mbox_restore_ctx(ducati_mbox); | ||
3157 | iommu_restore_ctx(ducati_iommu); | ||
3158 | retval = rproc_wakeup(sys_rproc); | ||
3159 | if (retval) | ||
3160 | goto error; | ||
3161 | handle->rcb_table->state_flag &= ~SYS_PROC_DOWN; | ||
3162 | if (ipu_pm_get_state(proc_id) & APP_PROC_LOADED) { | ||
3163 | retval = rproc_wakeup(app_rproc); | ||
3164 | if (retval) | ||
3165 | goto error; | ||
3166 | handle->rcb_table->state_flag &= ~APP_PROC_DOWN; | ||
3167 | } | ||
3168 | } else | ||
3169 | goto error; | ||
3170 | exit: | ||
3171 | mutex_unlock(ipu_pm_state.gate_handle); | ||
3172 | return 0; | ||
3173 | error: | ||
3174 | mutex_unlock(ipu_pm_state.gate_handle); | ||
3175 | pr_info("Aborting restoring process\n"); | ||
3176 | return -EINVAL; | ||
3177 | } | ||
3178 | EXPORT_SYMBOL(ipu_pm_restore_ctx); | ||
3179 | |||
3180 | /* | ||
3181 | Function to start a module | ||
3182 | * | ||
3183 | */ | ||
3184 | int ipu_pm_module_start(unsigned res_type) | ||
3185 | { | ||
3186 | return 0; | ||
3187 | } | ||
3188 | |||
3189 | /* | ||
3190 | Function to stop a module | ||
3191 | * | ||
3192 | */ | ||
3193 | int ipu_pm_module_stop(unsigned res_type) | ||
3194 | { | ||
3195 | return 0; | ||
3196 | } | ||
3197 | |||
3198 | /* | ||
3199 | Get the default configuration for the ipu_pm module. | ||
3200 | needed in ipu_pm_setup. | ||
3201 | */ | ||
3202 | void ipu_pm_get_config(struct ipu_pm_config *cfg) | ||
3203 | { | ||
3204 | int retval = 0; | ||
3205 | |||
3206 | if (WARN_ON(unlikely(cfg == NULL))) { | ||
3207 | retval = -EINVAL; | ||
3208 | goto exit; | ||
3209 | } | ||
3210 | |||
3211 | if (atomic_cmpmask_and_lt(&(ipu_pm_state.ref_count), | ||
3212 | IPU_PM_MAKE_MAGICSTAMP(0), | ||
3213 | IPU_PM_MAKE_MAGICSTAMP(1)) == true) | ||
3214 | memcpy(cfg, &ipu_pm_state.def_cfg, | ||
3215 | sizeof(struct ipu_pm_config)); | ||
3216 | else | ||
3217 | memcpy(cfg, &ipu_pm_state.cfg, sizeof(struct ipu_pm_config)); | ||
3218 | return; | ||
3219 | |||
3220 | exit: | ||
3221 | if (retval < 0) | ||
3222 | pr_err("ipu_pm_get_config failed! status = 0x%x", retval); | ||
3223 | return; | ||
3224 | } | ||
3225 | EXPORT_SYMBOL(ipu_pm_get_config); | ||
3226 | |||
3227 | /* | ||
3228 | Function to setup ipu pm object | ||
3229 | This function is called in platform_setup() | ||
3230 | This function will load the default configuration for ipu_pm | ||
3231 | in this function we can decide what is going to be controled | ||
3232 | by ipu_pm (DVFS, NOTIFICATIONS, ...) this configuration can | ||
3233 | can be changed on run-time. | ||
3234 | Also the workqueue is created and the local mutex | ||
3235 | */ | ||
3236 | int ipu_pm_setup(struct ipu_pm_config *cfg) | ||
3237 | { | ||
3238 | struct ipu_pm_config tmp_cfg; | ||
3239 | int retval = 0; | ||
3240 | struct mutex *lock = NULL; | ||
3241 | |||
3242 | /* This sets the ref_count variable is not initialized, upper 16 bits is | ||
3243 | written with module Id to ensure correctness of refCount variable. | ||
3244 | */ | ||
3245 | atomic_cmpmask_and_set(&ipu_pm_state.ref_count, | ||
3246 | IPU_PM_MAKE_MAGICSTAMP(0), | ||
3247 | IPU_PM_MAKE_MAGICSTAMP(0)); | ||
3248 | if (atomic_inc_return(&ipu_pm_state.ref_count) | ||
3249 | != IPU_PM_MAKE_MAGICSTAMP(1)) { | ||
3250 | return 1; | ||
3251 | } | ||
3252 | |||
3253 | if (cfg == NULL) { | ||
3254 | ipu_pm_get_config(&tmp_cfg); | ||
3255 | cfg = &tmp_cfg; | ||
3256 | } | ||
3257 | |||
3258 | /* Create a default gate handle for local module protection */ | ||
3259 | lock = kmalloc(sizeof(struct mutex), GFP_KERNEL); | ||
3260 | if (lock == NULL) { | ||
3261 | retval = -ENOMEM; | ||
3262 | goto exit; | ||
3263 | } | ||
3264 | mutex_init(lock); | ||
3265 | ipu_pm_state.gate_handle = lock; | ||
3266 | |||
3267 | /* Create the wq for req/rel resources */ | ||
3268 | ipu_wq = create_singlethread_workqueue("ipu_wq"); | ||
3269 | |||
3270 | /* No proc attached yet */ | ||
3271 | pm_handle_appm3 = NULL; | ||
3272 | pm_handle_sysm3 = NULL; | ||
3273 | ducati_iommu = NULL; | ||
3274 | ducati_mbox = NULL; | ||
3275 | sys_rproc = NULL; | ||
3276 | app_rproc = NULL; | ||
3277 | |||
3278 | /* Get mailbox and iommu to save/restore */ | ||
3279 | /* FIXME: This is not ready for Tesla */ | ||
3280 | ducati_mbox = omap_mbox_get("mailbox-2", NULL); | ||
3281 | if (ducati_mbox == NULL) { | ||
3282 | retval = -ENOMEM; | ||
3283 | goto exit; | ||
3284 | } | ||
3285 | ducati_iommu = iommu_get("ducati"); | ||
3286 | if (ducati_iommu == NULL) { | ||
3287 | retval = -ENOMEM; | ||
3288 | goto exit; | ||
3289 | } | ||
3290 | |||
3291 | memcpy(&ipu_pm_state.cfg, cfg, sizeof(struct ipu_pm_config)); | ||
3292 | ipu_pm_state.is_setup = true; | ||
3293 | |||
3294 | sysm3Idle = ioremap(SYSM3_IDLE_FLAG_PHY_ADDR, sizeof(int)); | ||
3295 | if (!sysm3Idle) { | ||
3296 | retval = -ENOMEM; | ||
3297 | goto exit; | ||
3298 | } | ||
3299 | |||
3300 | appm3Idle = ioremap(APPM3_IDLE_FLAG_PHY_ADDR, sizeof(int)); | ||
3301 | |||
3302 | if (!appm3Idle) { | ||
3303 | retval = -ENOMEM; | ||
3304 | goto exit; | ||
3305 | } | ||
3306 | |||
3307 | pm_gpt = omap_dm_timer_request_specific(GP_TIMER_3); | ||
3308 | if (pm_gpt == NULL) | ||
3309 | retval = -EINVAL; | ||
3310 | |||
3311 | return retval; | ||
3312 | exit: | ||
3313 | pr_err("ipu_pm_setup failed! retval = 0x%x", retval); | ||
3314 | return retval; | ||
3315 | } | ||
3316 | EXPORT_SYMBOL(ipu_pm_setup); | ||
3317 | |||
3318 | /* | ||
3319 | Function to attach ipu pm object | ||
3320 | This function is called in ipc_attach() | ||
3321 | This function will create the object based on the remoteproc id | ||
3322 | It is also recieving the shared address pointer to use in rcb | ||
3323 | */ | ||
3324 | int ipu_pm_attach(u16 remote_proc_id, void *shared_addr) | ||
3325 | { | ||
3326 | struct ipu_pm_params params; | ||
3327 | struct ipu_pm_object *handle; | ||
3328 | int retval = 0; | ||
3329 | |||
3330 | ipu_pm_params_init(¶ms); | ||
3331 | params.remote_proc_id = remote_proc_id; | ||
3332 | params.shared_addr = (void *)shared_addr; | ||
3333 | params.line_id = LINE_ID; | ||
3334 | params.shared_addr_size = ipu_pm_mem_req(NULL); | ||
3335 | |||
3336 | handle = ipu_pm_create(¶ms); | ||
3337 | |||
3338 | if (WARN_ON(unlikely(handle == NULL))) { | ||
3339 | retval = -EINVAL; | ||
3340 | goto exit; | ||
3341 | } | ||
3342 | |||
3343 | retval = ipu_pm_init_transport(handle); | ||
3344 | |||
3345 | /* Get remote processor handle to save/restore */ | ||
3346 | if (remote_proc_id == SYS_M3) { | ||
3347 | sys_rproc = omap_rproc_get("ducati-proc0"); | ||
3348 | if (sys_rproc == NULL) { | ||
3349 | retval = -ENOMEM; | ||
3350 | goto exit; | ||
3351 | } | ||
3352 | } else if (remote_proc_id == APP_M3) { | ||
3353 | app_rproc = omap_rproc_get("ducati-proc1"); | ||
3354 | if (app_rproc == NULL) { | ||
3355 | retval = -ENOMEM; | ||
3356 | goto exit; | ||
3357 | } | ||
3358 | } | ||
3359 | |||
3360 | if (retval < 0) | ||
3361 | goto exit; | ||
3362 | |||
3363 | /* FIXME the physical address should be calculated */ | ||
3364 | pr_info("ipu_pm_attach at va0x%x pa0x9cf00400\n", | ||
3365 | (unsigned int)shared_addr); | ||
3366 | |||
3367 | return retval; | ||
3368 | exit: | ||
3369 | pr_err("ipu_pm_attach failed! retval = 0x%x", retval); | ||
3370 | return retval; | ||
3371 | } | ||
3372 | EXPORT_SYMBOL(ipu_pm_attach); | ||
3373 | |||
3374 | /* | ||
3375 | Function to deattach ipu pm object | ||
3376 | This function is called in ipc_detach() | ||
3377 | This function will delete the object based | ||
3378 | on the remoteproc id and unregister the notify | ||
3379 | events used by ipu_pm module | ||
3380 | */ | ||
3381 | int ipu_pm_detach(u16 remote_proc_id) | ||
3382 | { | ||
3383 | struct ipu_pm_object *handle; | ||
3384 | struct ipu_pm_params *params; | ||
3385 | int retval = 0; | ||
3386 | |||
3387 | /* get the handle to proper ipu pm object */ | ||
3388 | handle = ipu_pm_get_handle(remote_proc_id); | ||
3389 | if (WARN_ON(unlikely(handle == NULL))) { | ||
3390 | retval = -EINVAL; | ||
3391 | goto exit; | ||
3392 | } | ||
3393 | |||
3394 | params = handle->params; | ||
3395 | if (WARN_ON(unlikely(params == NULL))) { | ||
3396 | retval = -EINVAL; | ||
3397 | goto exit; | ||
3398 | } | ||
3399 | |||
3400 | /* unregister the events used for ipu_pm */ | ||
3401 | retval = notify_unregister_event( | ||
3402 | params->remote_proc_id, | ||
3403 | params->line_id, | ||
3404 | params->pm_resource_event | (NOTIFY_SYSTEMKEY << 16), | ||
3405 | (notify_fn_notify_cbck)ipu_pm_callback, | ||
3406 | (void *)NULL); | ||
3407 | if (retval < 0) { | ||
3408 | pr_err("Error registering notify event\n"); | ||
3409 | goto exit; | ||
3410 | } | ||
3411 | retval = notify_unregister_event( | ||
3412 | params->remote_proc_id, | ||
3413 | params->line_id, | ||
3414 | params->pm_notification_event | (NOTIFY_SYSTEMKEY << 16), | ||
3415 | (notify_fn_notify_cbck)ipu_pm_notify_callback, | ||
3416 | (void *)NULL); | ||
3417 | if (retval < 0) { | ||
3418 | pr_err("Error registering notify event\n"); | ||
3419 | goto exit; | ||
3420 | } | ||
3421 | |||
3422 | /* Deleting the handle based on remote_proc_id */ | ||
3423 | ipu_pm_delete(handle); | ||
3424 | if (remote_proc_id == SYS_M3) { | ||
3425 | omap_rproc_put(sys_rproc); | ||
3426 | sys_rproc = NULL; | ||
3427 | } else if (remote_proc_id == APP_M3) { | ||
3428 | omap_rproc_put(app_rproc); | ||
3429 | app_rproc = NULL; | ||
3430 | } | ||
3431 | return retval; | ||
3432 | exit: | ||
3433 | pr_err("ipu_pm_detach failed handle null retval 0x%x", retval); | ||
3434 | return retval; | ||
3435 | } | ||
3436 | EXPORT_SYMBOL(ipu_pm_detach); | ||
3437 | |||
3438 | /* | ||
3439 | Function to destroy ipu_pm module | ||
3440 | this function will destroy the structs | ||
3441 | created to set the configuration | ||
3442 | */ | ||
3443 | int ipu_pm_destroy(void) | ||
3444 | { | ||
3445 | int retval = 0; | ||
3446 | struct mutex *lock = NULL; | ||
3447 | |||
3448 | if (WARN_ON(unlikely(atomic_cmpmask_and_lt( | ||
3449 | &ipu_pm_state.ref_count, | ||
3450 | IPU_PM_MAKE_MAGICSTAMP(0), | ||
3451 | IPU_PM_MAKE_MAGICSTAMP(1)) == true))) { | ||
3452 | retval = -ENODEV; | ||
3453 | goto exit; | ||
3454 | } | ||
3455 | |||
3456 | if (!(atomic_dec_return(&ipu_pm_state.ref_count) | ||
3457 | == IPU_PM_MAKE_MAGICSTAMP(0))) { | ||
3458 | retval = 1; | ||
3459 | goto exit; | ||
3460 | } | ||
3461 | |||
3462 | if (WARN_ON(ipu_pm_state.gate_handle == NULL)) { | ||
3463 | retval = -ENODEV; | ||
3464 | goto exit; | ||
3465 | } | ||
3466 | |||
3467 | retval = mutex_lock_interruptible(ipu_pm_state.gate_handle); | ||
3468 | if (retval) | ||
3469 | goto exit; | ||
3470 | |||
3471 | lock = ipu_pm_state.gate_handle; | ||
3472 | ipu_pm_state.gate_handle = NULL; | ||
3473 | mutex_unlock(lock); | ||
3474 | kfree(lock); | ||
3475 | /* Delete the wq for req/rel resources */ | ||
3476 | destroy_workqueue(ipu_wq); | ||
3477 | |||
3478 | omap_mbox_put(ducati_mbox, NULL); | ||
3479 | ducati_mbox = NULL; | ||
3480 | iommu_put(ducati_iommu); | ||
3481 | ducati_iommu = NULL; | ||
3482 | first_time = 1; | ||
3483 | omap_dm_timer_free(pm_gpt); | ||
3484 | return retval; | ||
3485 | exit: | ||
3486 | if (retval < 0) | ||
3487 | pr_err("ipu_pm_destroy failed, retval: %x\n", retval); | ||
3488 | return retval; | ||
3489 | } | ||
3490 | EXPORT_SYMBOL(ipu_pm_destroy); | ||
diff --git a/drivers/dsp/syslink/ipu_pm/ipu_pm.h b/drivers/dsp/syslink/ipu_pm/ipu_pm.h new file mode 100644 index 00000000000..612cf2fbe56 --- /dev/null +++ b/drivers/dsp/syslink/ipu_pm/ipu_pm.h | |||
@@ -0,0 +1,467 @@ | |||
1 | /* | ||
2 | * ipu_pm.h | ||
3 | * | ||
4 | * Syslink IPU Power Managament support functions for TI OMAP processors. | ||
5 | * | ||
6 | * Copyright (C) 2009-2010 Texas Instruments, Inc. | ||
7 | * | ||
8 | * This package is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
13 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
14 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
15 | * | ||
16 | * -------------------------------------------------------------------- | ||
17 | * | rcb_num | | | | | | ||
18 | * | msg_type | | | | | | ||
19 | * | sub_type | | | | | | ||
20 | * | rqst_cpu | 1-|word | | | | ||
21 | * | extd_mem_flag | | | | | | ||
22 | * | num_chan | | | | | | ||
23 | * | fill9 | | | | | | ||
24 | * |-------------------------------------| ------ 4-words 4-words | | ||
25 | * | process_id | 1-word | | | | ||
26 | * |-------------------------------------| ------ | | | | ||
27 | * | sem_hnd | 1-word | | | | ||
28 | * |-------------------------------------| ------ | | | | ||
29 | * | mod_base_addr | 1-word | | | | ||
30 | * |-------------------------------------| ------ ----- ----- | | ||
31 | * | channels[0] | data[0] | datax[0] | | | | | | ||
32 | * | channels[1] | | | 1-word | | RCB_SIZE | ||
33 | * | channels[2] | | | | | | = | ||
34 | * | channels[3] | | | | | | 8WORDS | ||
35 | * |--------------|---------|------------| ------ | | | | ||
36 | * | channels[4] | data[0] | datax[1] | | | | | | ||
37 | * | channels[5] | | | 1-word | RCB_SIZE-5 | | ||
38 | * | channels[6] | | | | | | | | ||
39 | * | channels[7] | | | | RCB_SIZE-4 | | | ||
40 | * |--------------|---------|------------| ------ | | | | ||
41 | * | channels[8] | data[0] | datax[2] | | | | | | ||
42 | * | channels[9] | | | 1-word | | | | ||
43 | * | channels[10] | | | | | | | | ||
44 | * | channels[11] | | | | | | | | ||
45 | * |--------------|---------|------------| ------ | ----- | | ||
46 | * | channels[12] | data[0] |extd_mem_hnd| | | | | | ||
47 | * | channels[13] | | | 1-word | 1-word | | ||
48 | * | channels[14] | | | | | | | | ||
49 | * | channels[15] | | | | | | | | ||
50 | * -------------------------------------------------------------------- | ||
51 | * | ||
52 | *The Ducati Power Management sub-system uses a structure called RCB_struct or | ||
53 | *just RCB to share information with the MPU about a particular resource involved | ||
54 | *in the communication. The information stored in this structure is needed to get | ||
55 | *attributes and other useful data about the resource. | ||
56 | *The fisrt fields of the RCB resemble the Rcb message sent across the NotifyDver | ||
57 | *It retains the rcb_num, msg_type and msg_subtype from the rcb message as its | ||
58 | *first 3 fields. The rqst_cpu fields indicates which remote processor originates | ||
59 | *the request/release petition. When a particular resource is requested, some of | ||
60 | *its parameters should be specify. | ||
61 | *For devices like Gptimer and GPIO, the most significant attribute its itemID. | ||
62 | *This value should be placed in the "fill9" field of the Rcb sruct. This field | ||
63 | *should be fill by the requester if asking for a particular resource or by the | ||
64 | *receiver if the resource granted is other than the one asked. | ||
65 | * | ||
66 | *Other variables related with the resource are: | ||
67 | *"sem_hnd" which storage the semaphore handle associated in the ducati side. | ||
68 | *We are pending on this semaphore when asked for the resource and | ||
69 | *posted when granted. | ||
70 | *"mod_base_addr". It is the virtual base addres for the resource. | ||
71 | *"process_id". It is the Task Id where the petition for the resource was called. | ||
72 | * | ||
73 | *The last 16 bytes of the structure could be interpreted in 3 different ways | ||
74 | *according to the context. | ||
75 | *1) For the case of the Rcb is for SDMA. The last 16 bytes correspond to a array | ||
76 | * of 16 channels[ ]. Each entry has the number of the SDMA channel granted. | ||
77 | * As many number of channels indicated in num_chan as many are meaningful | ||
78 | * in the channels[] array. | ||
79 | *2) If the extd_mem_flag bit is NOT set the 16 last bytes are used as a data[] | ||
80 | * array. Each entry is 4bytes long so the maximum number of entries is 4. | ||
81 | *3) If the extd_mem_flag bit is NOT set the 16 last bytes are used as an array | ||
82 | * datax[ ] 3 members Each entry 4bytes long and one additional field of | ||
83 | * "extd_mem_hnd" which is a pointer to the continuation of this datax array | ||
84 | */ | ||
85 | |||
86 | #ifndef _IPU_PM_H_ | ||
87 | #define _IPU_PM_H_ | ||
88 | |||
89 | #include <linux/types.h> | ||
90 | #include <linux/semaphore.h> | ||
91 | #include <linux/workqueue.h> | ||
92 | #include <linux/kfifo.h> | ||
93 | |||
94 | /* Pm notify ducati driver */ | ||
95 | /* Suspend/resume/other... */ | ||
96 | #define NUMBER_PM_EVENTS 4 | ||
97 | |||
98 | #define PM_CSTR_PERF_MASK 0x00000001 | ||
99 | #define PM_CSTR_LAT_MASK 0x00000002 | ||
100 | #define PM_CSTR_BW_MASK 0x00000004 | ||
101 | |||
102 | #define IPU_PM_MM_MPU_LAT_CONSTRAINT 10 | ||
103 | #define IPU_PM_NO_MPU_LAT_CONSTRAINT -1 | ||
104 | |||
105 | #define RCB_SIZE 8 | ||
106 | |||
107 | #define DATA_MAX (RCB_SIZE - 4) | ||
108 | #define DATAX_MAX (RCB_SIZE - 5) | ||
109 | #define SDMA_CHANNELS_MAX 16 | ||
110 | #define I2C_BUS_MIN 1 | ||
111 | #define I2C_BUS_MAX 4 | ||
112 | #define REGULATOR_MIN 1 | ||
113 | #define REGULATOR_MAX 1 | ||
114 | #define AUX_CLK_MIN 1 | ||
115 | #define AUX_CLK_MAX 3 | ||
116 | |||
117 | #define GP_TIMER_3 3 | ||
118 | #define GP_TIMER_4 4 | ||
119 | #define GP_TIMER_9 9 | ||
120 | #define GP_TIMER_11 11 | ||
121 | #define NUM_IPU_TIMERS 4 | ||
122 | |||
123 | #define I2C_SL_INVAL -1 | ||
124 | #define I2C_1_SL 0 | ||
125 | #define I2C_2_SL 1 | ||
126 | #define I2C_3_SL 2 | ||
127 | #define I2C_4_SL 3 | ||
128 | |||
129 | #define RCB_MIN 1 | ||
130 | #define RCB_MAX 33 | ||
131 | |||
132 | #define PM_RESOURCE 2 | ||
133 | #define PM_NOTIFICATION 3 | ||
134 | #define PM_SUCCESS 0 | ||
135 | #define PM_FAILURE -1 | ||
136 | #define PM_SHM_BASE_ADDR 0x9cff0000 | ||
137 | |||
138 | /* Auxiliar Clocks Registers */ | ||
139 | #define SCRM_BASE OMAP2_L4_IO_ADDRESS(0x4a30A000) | ||
140 | #define SCRM_BASE_AUX_CLK 0x00000314 | ||
141 | #define SCRM_BASE_AUX_CLK_REQ 0x00000214 | ||
142 | #define SCRM_AUX_CLK_OFFSET 0x4 | ||
143 | /* Auxiliar Clocks bit fields */ | ||
144 | #define SCRM_AUX_CLK_POLARITY 0x0 | ||
145 | #define SCRM_AUX_CLK_SRCSELECT 0x1 | ||
146 | #define SCRM_AUX_CLK_ENABLE 0x8 | ||
147 | #define SCRM_AUX_CLK_CLKDIV 0x10 | ||
148 | /* Auxiliar Clocks Masks */ | ||
149 | #define SCRM_AUX_CLK_POLARITY_MASK 0x00000001 | ||
150 | #define SCRM_AUX_CLK_SRCSELECT_MASK 0x00000006 | ||
151 | #define SCRM_AUX_CLK_ENABLE_MASK 0x00000100 | ||
152 | #define SCRM_AUX_CLK_CLKDIV_MASK 0x000F0000 | ||
153 | /* Auxiliar Clocks Request bit fields */ | ||
154 | #define SCRM_AUX_CLK_REQ_POLARITY 0x0 | ||
155 | #define SCRM_AUX_CLK_REQ_ACCURACY 0x1 | ||
156 | #define SCRM_AUX_CLK_REQ_MAPPING 0x2 | ||
157 | /* Auxiliar Clocks Request Masks */ | ||
158 | #define SCRM_AUX_CLK_REQ_POLARITY_MASK 0x00000001 | ||
159 | #define SCRM_AUX_CLK_REQ_ACCURACY_MASK 0x00000002 | ||
160 | #define SCRM_AUX_CLK_REQ_MAPPING_MASK 0x0000001C | ||
161 | |||
162 | /* Macro to set a val in a bitfield*/ | ||
163 | #define MASK_SET_FIELD(tmp, bitfield, val) { \ | ||
164 | tmp |= \ | ||
165 | ((val << SCRM_##bitfield)\ | ||
166 | & SCRM_##bitfield##_MASK);\ | ||
167 | } | ||
168 | |||
169 | /* Macro to return the address of the aux clk */ | ||
170 | #define AUX_CLK_REG(clk) (SCRM_BASE + (SCRM_BASE_AUX_CLK + \ | ||
171 | (SCRM_AUX_CLK_OFFSET * clk))) | ||
172 | |||
173 | /* Macro to return the address of the aux clk req */ | ||
174 | #define AUX_CLK_REG_REQ(clk) (SCRM_BASE + (SCRM_BASE_AUX_CLK_REQ + \ | ||
175 | (SCRM_AUX_CLK_OFFSET * clk))) | ||
176 | |||
177 | |||
178 | /* | ||
179 | * IPU_PM_MODULEID | ||
180 | * Unique module ID | ||
181 | */ | ||
182 | #define IPU_PM_MODULEID (0x6A6A) | ||
183 | |||
184 | /* A9 state flag 0000 | 0000 Ducati internal use*/ | ||
185 | #define SYS_PROC_DOWN 0x00010000 | ||
186 | #define APP_PROC_DOWN 0x00020000 | ||
187 | #define ENABLE_IPU_HIB 0x00000040 | ||
188 | |||
189 | #define SYS_PROC_IDLING 0x00000001 | ||
190 | #define APP_PROC_IDLING 0x00000002 | ||
191 | |||
192 | #define SYS_PROC_LOADED 0x00000010 | ||
193 | #define APP_PROC_LOADED 0x00000020 | ||
194 | #define IPU_PROC_LOADED 0x00000030 | ||
195 | #define PROC_LD_SHIFT 4u | ||
196 | |||
197 | #define IPU_PROC_IDLING 0x0000c000 | ||
198 | #define IPU_IDLING_SHIFT 14u | ||
199 | |||
200 | #define SYS_IDLING_BIT 14 | ||
201 | #define APP_IDLING_BIT 15 | ||
202 | |||
203 | #define SYS_LOADED_BIT 4 | ||
204 | #define APP_LOADED_BIT 5 | ||
205 | |||
206 | #define ONLY_APPM3_IDLE 0x2 | ||
207 | #define ONLY_SYSM3_IDLE 0x1 | ||
208 | #define ALL_CORES_IDLE 0x3 | ||
209 | #define WAIT_FOR_IDLE_TIMEOUT 40u | ||
210 | |||
211 | /* Macro to make a correct module magic number with refCount */ | ||
212 | #define IPU_PM_MAKE_MAGICSTAMP(x) ((IPU_PM_MODULEID << 12u) | (x)) | ||
213 | |||
214 | enum pm_failure_codes{ | ||
215 | PM_INSUFFICIENT_CHANNELS = 1, | ||
216 | PM_NO_GPTIMER, | ||
217 | PM_NO_GPIO, | ||
218 | PM_NO_I2C, | ||
219 | PM_NO_REGULATOR, | ||
220 | PM_REGULATOR_IN_USE, | ||
221 | PM_INVAL_RCB_NUM, | ||
222 | PM_INVAL_NUM_CHANNELS, | ||
223 | PM_INVAL_NUM_I2C, | ||
224 | PM_INVAL_REGULATOR, | ||
225 | PM_NOT_INSTANTIATED, | ||
226 | PM_UNSUPPORTED, | ||
227 | PM_NO_AUX_CLK, | ||
228 | PM_INVAL_AUX_CLK | ||
229 | }; | ||
230 | |||
231 | enum pm_msgtype_codes{PM_FAIL, | ||
232 | PM_NULLMSG, | ||
233 | PM_ACKNOWLEDGEMENT, | ||
234 | PM_REQUEST_RESOURCE, | ||
235 | PM_RELEASE_RESOURCE, | ||
236 | PM_NOTIFICATIONS, | ||
237 | PM_ENABLE_RESOURCE, | ||
238 | PM_WRITE_RESOURCE, | ||
239 | PM_READ_RESOURCE, | ||
240 | PM_DISABLE_RESOURCE, | ||
241 | PM_REQUEST_CONSTRAINTS, | ||
242 | PM_RELEASE_CONSTRAINTS, | ||
243 | PM_NOTIFY_HIBERNATE | ||
244 | }; | ||
245 | |||
246 | enum pm_regulator_action{PM_SET_VOLTAGE, | ||
247 | PM_SET_CURRENT, | ||
248 | PM_SET_MODE, | ||
249 | PM_GET_MODE, | ||
250 | PM_GET_CURRENT, | ||
251 | PM_GET_VOLTAGE | ||
252 | }; | ||
253 | |||
254 | enum res_type{ | ||
255 | FDIF, | ||
256 | IPU, | ||
257 | SYSM3, | ||
258 | APPM3, | ||
259 | ISS, | ||
260 | IVA_HD, | ||
261 | IVASEQ0, | ||
262 | IVASEQ1, | ||
263 | L3_BUS, | ||
264 | MPU, | ||
265 | SDMA, | ||
266 | GP_TIMER, | ||
267 | GP_IO, | ||
268 | I2C, | ||
269 | REGULATOR, | ||
270 | AUX_CLK, | ||
271 | }; | ||
272 | |||
273 | enum pm_event_type{PM_SUSPEND, | ||
274 | PM_RESUME, | ||
275 | PM_PID_DEATH, | ||
276 | PM_HIBERNATE | ||
277 | }; | ||
278 | |||
279 | struct rcb_message { | ||
280 | unsigned rcb_flag:1; | ||
281 | unsigned rcb_num:6; | ||
282 | unsigned reply_flag:1; | ||
283 | unsigned msg_type:4; | ||
284 | unsigned msg_subtype:4; | ||
285 | unsigned parm:16; | ||
286 | }; | ||
287 | |||
288 | union message_slicer { | ||
289 | struct rcb_message fields; | ||
290 | int whole; | ||
291 | }; | ||
292 | |||
293 | struct ipu_pm_override { | ||
294 | unsigned hibernateAllowed:1; | ||
295 | unsigned retentionAllowed:1; | ||
296 | unsigned inactiveAllowed:1; | ||
297 | unsigned cmAutostateAllowed:1; | ||
298 | unsigned deepSleepAllowed:1; | ||
299 | unsigned wfiAllowed:1; | ||
300 | unsigned idleAllowed:1; | ||
301 | unsigned reserved:24; | ||
302 | unsigned highbit:1; | ||
303 | }; | ||
304 | |||
305 | struct rcb_block { | ||
306 | unsigned rcb_num:6; | ||
307 | unsigned msg_type:4; | ||
308 | unsigned sub_type:4; | ||
309 | unsigned rqst_cpu:4; | ||
310 | unsigned extd_mem_flag:1; | ||
311 | unsigned num_chan:4; | ||
312 | unsigned fill9:9; | ||
313 | |||
314 | unsigned process_id; | ||
315 | unsigned *sem_hnd; | ||
316 | unsigned mod_base_addr; | ||
317 | union { | ||
318 | unsigned int data[DATA_MAX]; | ||
319 | struct { | ||
320 | unsigned datax[DATAX_MAX]; | ||
321 | unsigned extd_mem_hnd; | ||
322 | }; | ||
323 | unsigned char channels[SDMA_CHANNELS_MAX]; | ||
324 | }; | ||
325 | }; | ||
326 | |||
327 | struct sms { | ||
328 | unsigned rat; | ||
329 | unsigned pm_version; | ||
330 | unsigned gp_msg; | ||
331 | unsigned state_flag; | ||
332 | struct ipu_pm_override pm_flags; | ||
333 | unsigned hib_time; | ||
334 | struct rcb_block rcb[RCB_MAX]; | ||
335 | }; | ||
336 | |||
337 | struct pm_event { | ||
338 | enum pm_event_type event_type; | ||
339 | struct semaphore sem_handle; | ||
340 | int pm_msg; | ||
341 | }; | ||
342 | |||
343 | struct ipu_pm_params { | ||
344 | int pm_fdif_counter; | ||
345 | int pm_ipu_counter; | ||
346 | int pm_sys_m3_counter; | ||
347 | int pm_app_m3_counter; | ||
348 | int pm_iss_counter; | ||
349 | int pm_iva_hd_counter; | ||
350 | int pm_ivaseq0_counter; | ||
351 | int pm_ivaseq1_counter; | ||
352 | int pm_l3_bus_counter; | ||
353 | int pm_mpu_counter; | ||
354 | int pm_sdmachan_counter; | ||
355 | int pm_gptimer_counter; | ||
356 | int pm_gpio_counter; | ||
357 | int pm_i2c_bus_counter; | ||
358 | int pm_regulator_counter; | ||
359 | int pm_aux_clk_counter; | ||
360 | int timeout; | ||
361 | void *shared_addr; | ||
362 | int shared_addr_size; | ||
363 | int pm_num_events; | ||
364 | int pm_resource_event; | ||
365 | int pm_notification_event; | ||
366 | int proc_id; | ||
367 | int remote_proc_id; | ||
368 | int line_id; | ||
369 | void *gate_mp; | ||
370 | }; | ||
371 | |||
372 | /* This structure defines attributes for initialization of the ipu_pm module. */ | ||
373 | struct ipu_pm_config { | ||
374 | u32 reserved; | ||
375 | }; | ||
376 | |||
377 | /* Defines the ipu_pm state object, which contains all the module | ||
378 | * specific information. */ | ||
379 | struct ipu_pm_module_object { | ||
380 | atomic_t ref_count; | ||
381 | /* Reference count */ | ||
382 | struct ipu_pm_config cfg; | ||
383 | /* ipu_pm configuration structure */ | ||
384 | struct ipu_pm_config def_cfg; | ||
385 | /* Default module configuration */ | ||
386 | struct mutex *gate_handle; | ||
387 | /* Handle of gate to be used for local thread safety */ | ||
388 | bool is_setup; | ||
389 | /* Indicates whether the ipu_pm module is setup. */ | ||
390 | }; | ||
391 | |||
392 | /* Store the payload and processor id for the wq */ | ||
393 | struct ipu_pm_msg { | ||
394 | u16 proc_id; | ||
395 | int pm_msg; | ||
396 | }; | ||
397 | |||
398 | /* ipu_pm handle one for each proc SYSM3/APPM3 */ | ||
399 | struct ipu_pm_object { | ||
400 | struct sms *rcb_table; | ||
401 | struct pm_event *pm_event; | ||
402 | struct ipu_pm_params *params; | ||
403 | struct work_struct work; | ||
404 | struct kfifo fifo; | ||
405 | spinlock_t lock; | ||
406 | }; | ||
407 | |||
408 | /* Function for PM resources Callback */ | ||
409 | void ipu_pm_callback(u16 proc_id, u16 line_id, u32 event_id, | ||
410 | uint *arg, u32 payload); | ||
411 | |||
412 | /* Function for PM notifications Callback */ | ||
413 | void ipu_pm_notify_callback(u16 proc_id, u16 line_id, u32 event_id, | ||
414 | uint *arg, u32 payload); | ||
415 | |||
416 | /* Function for send PM Notifications */ | ||
417 | int ipu_pm_notifications(enum pm_event_type event_type, void *data); | ||
418 | |||
419 | /* Function to set init parameters */ | ||
420 | void ipu_pm_params_init(struct ipu_pm_params *params); | ||
421 | |||
422 | /* Function to calculate ipu pm mem */ | ||
423 | int ipu_pm_mem_req(const struct ipu_pm_params *params); | ||
424 | |||
425 | /* Function to config ipu_pm module */ | ||
426 | void ipu_pm_get_config(struct ipu_pm_config *cfg); | ||
427 | |||
428 | /* Function to set up ipu_pm module */ | ||
429 | int ipu_pm_setup(struct ipu_pm_config *cfg); | ||
430 | |||
431 | /* Function to create ipu pm object */ | ||
432 | struct ipu_pm_object *ipu_pm_create(const struct ipu_pm_params *params); | ||
433 | |||
434 | /* Function to delete ipu pm object */ | ||
435 | void ipu_pm_delete(struct ipu_pm_object *handle); | ||
436 | |||
437 | /* Function to destroy ipu_pm module */ | ||
438 | int ipu_pm_destroy(void); | ||
439 | |||
440 | /* Function to attach ipu_pm module */ | ||
441 | int ipu_pm_attach(u16 remote_proc_id, void *shared_addr); | ||
442 | |||
443 | /* Function to deattach ipu_pm module */ | ||
444 | int ipu_pm_detach(u16 remote_proc_id); | ||
445 | |||
446 | /* Function to register the ipu_pm events */ | ||
447 | int ipu_pm_init_transport(struct ipu_pm_object *handle); | ||
448 | |||
449 | /* Function to get ipu pm object */ | ||
450 | struct ipu_pm_object *ipu_pm_get_handle(int proc_id); | ||
451 | |||
452 | /* Function to save a processor from hibernation */ | ||
453 | int ipu_pm_save_ctx(int proc_id); | ||
454 | |||
455 | /* Function to restore a processor from hibernation */ | ||
456 | int ipu_pm_restore_ctx(int proc_id); | ||
457 | |||
458 | /* Function to start a module */ | ||
459 | int ipu_pm_module_start(unsigned res_type); | ||
460 | |||
461 | /* Function to stop a module */ | ||
462 | int ipu_pm_module_stop(unsigned res_type); | ||
463 | |||
464 | /* Function to get ducati state flag from share memory */ | ||
465 | u32 ipu_pm_get_state(int proc_id); | ||
466 | |||
467 | #endif | ||