aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorPaul Hunt <hunt@ti.com>2010-09-08 15:04:12 -0400
committerPaolo Pisati <paolo.pisati@canonical.com>2012-08-17 04:19:08 -0400
commitaaca0103c44efa5cbca6720309856ddfacd6ffa6 (patch)
tree09c34b1698d739d60a7eaf0e54fab58cd9a7b2bf /arch/arm
parent77508e0bdabffccd9106c79b74170a8a4a87f321 (diff)
omap:ipu_pm: Patchset to introduce ipu_pm functionality. omap:ipu_pm: add ipu_dev header to mach-omap2 tree
Header file needed fot mach-omap2/ipu_dev.c file Signed-off-by: Paul Hunt <hunt@ti.com> omap:ipu_pm: add ipu_utility to mach-omap2 tree IVAHD Sequencer WFI Boot Code for IPU PM Driver Signed-off-by: Paul Hunt <hunt@ti.com> omap:ipu_pm: add ipu_drv to mach-omap2 tree Add needed api for ipu_pm module Signed-off-by: Paul Hunt <hunt@ti.com> omap:ipu_pm: add ipu_dev to mach-omap2 tree. Platform Device handling for IPU PM Driver Includes: - ipu_pm_module_start - ipu_pm_module_stop - platform data definition for the following devices: + fdif + ipu + ipu_c0 + ipu_c1 + iss + iva + iva_seq0 + iva_seq1 + L3 + mpu -ipussdev_init to init all devices. Signed-off-by: Paul Hunt <hunt@ti.com> syslink:ipu_pm: add/remove ipu_pm_start/stop Add the calls to api that will enable: - iva_hd - iva_seq0 - iva_seq1 - fdif - iss modules using the hwmod implementation. Hibernation disabled. Gptimer3 used for hibernation was disabled. Setting CM_MPU_M3_CLKSTCTRL.CLKTRCTRL[1:0] = HW_AUTO Retention is disable by default. Signed-off-by: Paul Hunt <hunt@ti.com> syslink:ipu_pm: fix req/rel aux_clk/iss/iva/idle The current implementation was not meeting all the requiriments needed to properly enable and use aux_clk. Anyway this is a hack way to do it, the proper implementation is still pending. Signed-off-by: Miguel Vadillo <vadillo@ti.com> Temporary path using cmm_write_reg to enable CAM_PHY Signed-off-by: Paul Hunt <hunt@ti.com> Ivahd requesting was not fully working since sl2 was not being requested and that is needed for ivahd to be fully functional. In ipu_dev sl2 is initialized In ipu_pm the flow to request iva should be: - Requesting (ivaseq1 call is requesting sl2) ivahd>ivaseq0>(ivaseq1>sl2) - Releasing (iva call is first releasing sl2) ivaseq0>ivaseq1>(sl2>ivahd) Signed-off-by: Miguel Vadillo <vadillo@ti.com> Setting IdleAllowed flag that enables the idle mode in Ducati. WFI can be called in Ducati flag whenever this flag is set Signed-off-by: Juan Gutierrez <jgutierrez@ti.com> Fix a compile error related to iva/iss when trying to build with ES1.0 configuration. In ES1.0, the PM is not supported. Signed-off-by: Hari Kanigeri <h-kanigeri2@ti.com> Signed-off-by: Miguel Vadillo <vadillo@ti.com> syslink:ipu_pm: DFVS support for freq Fix bug in error message string referencing Signed-off-by: Paul Hunt <hunt@ti.com> Add platform data for DSP resource and fix attributes for MPU and L3 interconnect. Signed-off-by: Paul Hunt <hunt@ti.com> Provide internal APIs for performance and latency constraint frameworks to use to assert these constraints into the system power management. Signed-off-by: Paul Hunt <hunt@ti.com> MPU and CORE freq/lat cstrs Add special handling for MPU and CORE frequency and latency constraints. To specify a constraint to MPU or CORE the api needs to be called passing the following to the api: - IPUPM_SELF - IPUPM_MPU - IPUPM_CORE Signed-off-by: Paul Hunt <hunt@ti.com> DVFS support in ipu_pm Calling the dvfs apis per resource. Included: - ipu[perf|lat] - iss[perf|lat] - ivahd[perf|lat] - L3 bus[lat] - mpu[perf|lat] Pending: - fdif - dsp Note: Latency calls are working but hasnt been tested. Perf/rate calls are working. Signed-off-by: Miguel Vadillo <vadillo@ti.com> Signed-off-by: Paul Hunt <hunt@ti.com> (cherry picked from commit 3c1cdb45bb67d11eda14420a7b8eaacff0c24173) SYSLINK:IPU-PM-move iommu handles to attach and detach Move getting iommu handle to attach and detach from setup/destroy. Having the iommu get in setup is causing the mmu fault recovery fail since the iommu object gets incremented before the fault application closes the iommu handle which leads to failure in shutting down the iommu device completely. Signed-off-by: Hari Kanigeri <h-kanigeri2@ti.com> syslink:ipu_pm: add L3 bw and fdif cstr ipu_pm api to set the bandwidth constraint for L3 bus New api is: ipu_pm_module_set_bandwidth(rsrc, target_rsrc, bw); bw is received in KiB/s and converted into Hz Add support to set performance and latency cstrs to fdif. Signed-off-by: Miguel Vadillo <vadillo@ti.com> Signed-off-by: Paul Hunt <hunt@ti.com> Signed-off-by: Juan Gutierrez <jgutierrez@ti.com> syslink:ipu_pm: send pid_death just to appm3 ipu_pm_notification is broadcasting all events to both sys/app processors whenever an event is sent using that api. For PID_DEATH event the requirement is only to send the message to APPM3 since is the one that will be executing the resource manager; also because of that sending the message to SYSM3 is unnecessary. Signed-off-by: Miguel Vadillo <vadillo@ti.com> syslink:ipu_pm: allow IPU hibernation -IPU self hibernation- After 5 seconds of inactivity ipu will send a notification to MPU indicating it can be turned off, mpu can proceed to turn off IPU just if there is no message (notify_send_event) going to IPU, in that case hibernation will be aborted. IPU is prepared to abort hibernation when a message arrives to its mbox. When mpu is hibernating IPU the iommu and mbox context will be saved and then rproc_sleep will be called to disable each core and also the associated gptimer, that is needed to allow retention. Whenever a message is sent to IPU the ipu_pm_restore will check and wake up IPU, if needed, restoring the iommu and mbox context and calling rproc_wake that will enable IPU and the associated gptimer again. -MPU hibernating IPU- Whenever the system suspend is sent to ipu_drv the suspend_drv will send a SUSPEND notification to IPU, it will send back an ack to MPU and then start the hibernation proccess by it self following the same scheme mentioned above but without waiting the 5 seconds, once ipu_drv receives the suspend ack it will call ipu_pm_save_ctx() in order to wait for IPU to be hibernated and in really idle then turn IPU off. This will work even if self hibernation in IPU is disable. Signed-off-by: Miguel Vadillo <vadillo@ti.com> Signed-off-by: Juan Gutierrez <jgutierrez@ti.com> Signed-off-by: Paul Hunt <hunt@ti.com> IPU PM: adapt aux clk funcs to new framework entities Signed-off-by: Paul Hunt <hunt@ti.com> IPU PM: temporary workaround for missing MM AUX_CLK requests Signed-off-by: Paul Hunt <hunt@ti.com> syslink: ipu_pm: add support for all the auxclk Previously ipu_pm was only supporting the request of AUX_CLK_1/3 now all the available aux_clk 0-5 are supported and can be requested/released via ipu_pm. Also the base address of the AUX_CLK was fixed since it was assuming AUX_CLK_0 as AUX_CLK_1 leading to a misalignment when requesting. Signed-off-by: Miguel Vadillo <vadillo@ti.com> syslink: ipu_pm: add a core latency constraint when the ipu is running. Due to the enabling of C4 and C5 states IPU was being put in reset without allowing it to properly save the context leading to an invalid resume operation and an MMU fault by IPU side. Putting a latency constraint on IPU_CORE whenever IPU is up and running is avoiding this scenario. The constraint is released once the IPU has properly saved the context and requested again when resuming to avoid letting the ipu_core going to retention. Change-Id: Iced64ff0744b2d6b0a0ecfc1952ed26e9e560278 Signed-off-by: Miguel Vadillo <vadillo@ti.com> Signed-off-by: Paul Hunt <hunt@ti.com> omap:syslink: removing gpt4 as available Gptimers 3 & 4 are reserving for ipu_pm internal use gpt3 was removed in previous patch from the list of available gptimers that IPU can request but gpt4 was still in the list. This patch removes gpt4 from the list. Signed-off-by: Miguel Vadillo <vadillo@ti.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-omap2/ipu_dev.c384
-rw-r--r--arch/arm/mach-omap2/ipu_drv.c343
-rw-r--r--arch/arm/mach-omap2/ipu_utility.c69
-rw-r--r--arch/arm/plat-omap/include/plat/ipu_dev.h107
4 files changed, 903 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/ipu_dev.c b/arch/arm/mach-omap2/ipu_dev.c
new file mode 100644
index 00000000000..8d3386f1f86
--- /dev/null
+++ b/arch/arm/mach-omap2/ipu_dev.c
@@ -0,0 +1,384 @@
1/**
2 * linux/arch/arm/mach-omap2/ipu_dev.c
3 *
4 * Copyright (C) 2010 Texas Instruments, Inc.
5 * Paul Hunt <hunt@ti.com>
6 *
7 * OMAP4 Image Processing Unit
8 * This program 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
13#include <linux/clk.h>
14#include <linux/delay.h>
15#include <linux/io.h>
16#include <linux/err.h>
17
18#include <mach/irqs.h>
19#include <plat/omap_hwmod.h>
20#include <plat/omap_device.h>
21#include <plat/omap-pm.h>
22#include <linux/platform_device.h>
23#include <plat/remoteproc.h>
24
25#include <plat/ipu_dev.h>
26
27#include "../../../drivers/dsp/syslink/ipu_pm/ipu_pm.h"
28
29#define IPU_DRIVER_NAME "omap-ipu-pm"
30#define ISS_IPU_BUS_ID 0
31#define IVA_IPU_BUS_ID 1
32
33struct omap_ipupm_mod_platform_data *ipupm_get_plat_data(void);
34
35static char *hwmod_state_strings[] = {
36 "_HWMOD_STATE_UNKNOWN",
37 "_HWMOD_STATE_REGISTERED",
38 "_HWMOD_STATE_CLKS_INITED",
39 "_HWMOD_STATE_INITIALIZED",
40 "_HWMOD_STATE_ENABLED",
41 "_HWMOD_STATE_IDLE",
42 "_HWMOD_STATE_DISABLED",
43};
44static void print_hwmod_state(struct omap_hwmod *oh)
45{
46 u32 _state = (u32) oh->_state;
47 pr_info("HWMOD name = %s\n", oh->name);
48 if (_state > _HWMOD_STATE_LAST)
49 WARN(1, "Illegal hwmod _state = %d\n", _state);
50 else
51 pr_info("state = %s\n", hwmod_state_strings[_state]);
52}
53
54inline int ipu_pm_module_start(unsigned rsrc)
55{
56 int ret;
57 struct omap_ipupm_mod_platform_data *pd;
58
59 pd = ipupm_get_plat_data();
60
61 print_hwmod_state(pd[rsrc].oh);
62 ret = omap_device_enable(pd[rsrc].pdev);
63 if (ret)
64 pr_err("device enable failed %s", pd[rsrc].oh_name);
65
66 return ret;
67}
68EXPORT_SYMBOL(ipu_pm_module_start);
69
70inline int ipu_pm_module_stop(unsigned rsrc)
71{
72 int ret;
73 struct omap_ipupm_mod_platform_data *pd;
74
75 pd = ipupm_get_plat_data();
76
77 print_hwmod_state(pd[rsrc].oh);
78 ret = omap_device_shutdown(pd[rsrc].pdev);
79 if (ret)
80 pr_err("device disable failed %s", pd[rsrc].oh_name);
81
82 return ret;
83}
84EXPORT_SYMBOL(ipu_pm_module_stop);
85
86inline int ipu_pm_module_set_rate(unsigned rsrc,
87 unsigned target_rsrc,
88 unsigned rate)
89{
90 int ret;
91 unsigned target;
92 struct device *dp;
93 struct omap_ipupm_mod_platform_data *pd;
94
95 pd = ipupm_get_plat_data();
96
97 if (target_rsrc == IPU_PM_MPU)
98 dp = omap2_get_mpuss_device();
99 else if (target_rsrc == IPU_PM_CORE)
100 dp = omap2_get_l3_device();
101 else {
102 if (target_rsrc == IPU_PM_SELF)
103 target = rsrc;
104 else
105 target = target_rsrc;
106
107 if ((pd[target].caps & IPUPM_CAPS_PERF) == 0) {
108 pr_err("device set rate not supported for %s",
109 pd[target].oh_name);
110 ret = -EINVAL;
111 goto err_ret;
112 } else
113 dp = pd[target].dev;
114 }
115
116 ret = omap_device_set_rate(pd[rsrc].dev, dp, rate);
117 if (ret)
118 pr_err("device set rate failed %s", pd[target_rsrc].oh_name);
119err_ret:
120 return ret;
121}
122EXPORT_SYMBOL(ipu_pm_module_set_rate);
123
124inline int ipu_pm_module_set_latency(unsigned rsrc,
125 unsigned target_rsrc,
126 int latency)
127{
128 int ret = 0;
129 unsigned target;
130 struct omap_ipupm_mod_platform_data *pd;
131
132 pd = ipupm_get_plat_data();
133
134 if (target_rsrc == IPU_PM_MPU) {
135#ifdef CONFIG_OMAP_PM
136 ret = omap_pm_set_max_mpu_wakeup_lat(&pd[rsrc].qos_request,
137 latency);
138#endif
139 if (ret)
140 goto err_ret;
141 } else if (target_rsrc == IPU_PM_CORE) {
142#ifdef CONFIG_OMAP_PM
143 ret = omap_pm_set_max_sdma_lat(&pd[rsrc].qos_request,
144 latency);
145#endif
146 if (ret)
147 goto err_ret;
148 } else {
149 if (target_rsrc == IPU_PM_SELF)
150 target = rsrc;
151 else
152 target = target_rsrc;
153
154 if ((pd[target].caps & IPUPM_CAPS_LAT) == 0) {
155 pr_err("device set latency not supported for %s",
156 pd[target].oh_name);
157 ret = -EINVAL;
158 } else {
159#ifdef CONFIG_OMAP_PM
160 ret = omap_pm_set_max_dev_wakeup_lat(pd[rsrc].dev,
161 pd[target].dev,
162 latency);
163#endif
164 }
165 }
166
167 if (ret)
168 pr_err("module set latency failed %s", pd[target].oh_name);
169err_ret:
170 return ret;
171}
172EXPORT_SYMBOL(ipu_pm_module_set_latency);
173
174inline int ipu_pm_module_set_bandwidth(unsigned rsrc,
175 unsigned target_rsrc,
176 int bandwidth)
177{
178 int ret = 0;
179 struct omap_ipupm_mod_platform_data *pd;
180
181 pd = ipupm_get_plat_data();
182
183 if ((pd[target_rsrc].caps & IPUPM_CAPS_BDW) == 0) {
184 pr_err("device set bandwidth not supported for %s",
185 pd[target_rsrc].oh_name);
186 ret = -EINVAL;
187 } else {
188#ifdef CONFIG_OMAP_PM
189 struct device *dp;
190 dp = omap2_get_l3_device();
191 ret = omap_pm_set_min_bus_tput(dp,
192 OCP_INITIATOR_AGENT,
193 bandwidth);
194#endif
195 }
196
197 if (ret)
198 pr_err("module set bandwidth failed %s",
199 pd[target_rsrc].oh_name);
200 return ret;
201}
202EXPORT_SYMBOL(ipu_pm_module_set_bandwidth);
203
204/* FIXME: not in use now
205 * static struct omap_ipupm_mod_ops omap_ipu_ops = {
206 * .start = NULL,
207 * .stop = NULL,
208 * };
209 *
210 * static struct omap_ipupm_mod_ops omap_ipu0_ops = {
211 * .start = NULL,
212 * .stop = NULL,
213 * };
214 *
215 * static struct omap_ipupm_mod_ops omap_ipu1_ops = {
216 * .start = NULL,
217 * .stop = NULL,
218 * };
219 */
220
221/* ipupm generic operations */
222static struct omap_ipupm_mod_ops omap_ipupm_ops = {
223 .start = NULL,
224 .stop = NULL,
225};
226
227static struct omap_ipupm_mod_platform_data omap_ipupm_data[] = {
228 {
229 .name = "omap-ipu-pm",
230 .oh_name = "fdif",
231 .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP
232 | IPUPM_CAPS_PERF | IPUPM_CAPS_LAT,
233 .ops = &omap_ipupm_ops,
234 },
235 {
236 .name = "omap-ipu-pm",
237 .oh_name = "ipu",
238 .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP
239 | IPUPM_CAPS_PERF | IPUPM_CAPS_LAT
240 | IPUPM_CAPS_EXTINIT,
241 .ops = &omap_ipupm_ops,
242 },
243 {
244 .name = "omap-ipu-pm",
245 .oh_name = "ipu_c0",
246 .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP
247 | IPUPM_CAPS_EXTINIT,
248 .ops = &omap_ipupm_ops,
249 },
250 {
251 .name = "omap-ipu-pm",
252 .oh_name = "ipu_c1",
253 .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP
254 | IPUPM_CAPS_EXTINIT,
255 .ops = &omap_ipupm_ops,
256 },
257 {
258 .name = "omap-ipu-pm",
259 .oh_name = "iss",
260 .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP
261 | IPUPM_CAPS_PERF | IPUPM_CAPS_LAT,
262 .ops = &omap_ipupm_ops,
263 },
264 {
265 .name = "omap-ipu-pm",
266 .oh_name = "iva",
267 .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP
268 | IPUPM_CAPS_PERF | IPUPM_CAPS_LAT,
269 .ops = &omap_ipupm_ops,
270 },
271 {
272 .name = "omap-ipu-pm",
273 .oh_name = "iva_seq0",
274 .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP,
275 .ops = &omap_ipupm_ops,
276 },
277 {
278 .name = "omap-ipu-pm",
279 .oh_name = "iva_seq1",
280 .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP,
281 .ops = &omap_ipupm_ops,
282 },
283 {
284 .name = "omap-ipu-pm",
285 .oh_name = "l3_main_1",
286 .caps = IPUPM_CAPS_LAT | IPUPM_CAPS_BDW
287 | IPUPM_CAPS_EXTINIT,
288 .ops = &omap_ipupm_ops,
289 },
290 {
291 .name = "omap-ipu-pm",
292 .oh_name = "mpu",
293 .caps = IPUPM_CAPS_PERF | IPUPM_CAPS_LAT
294 | IPUPM_CAPS_EXTINIT,
295 .ops = &omap_ipupm_ops,
296 },
297 {
298 .name = "omap-ipu-pm",
299 .oh_name = "sl2if",
300 .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP,
301 .ops = &omap_ipupm_ops,
302 },
303 {
304 .name = "omap-ipu-pm",
305 .oh_name = "dsp",
306 .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP
307 | IPUPM_CAPS_PERF | IPUPM_CAPS_LAT
308 | IPUPM_CAPS_EXTINIT,
309 .ops = &omap_ipupm_ops,
310 },
311};
312
313struct omap_ipupm_mod_platform_data *ipupm_get_plat_data(void)
314{
315 return omap_ipupm_data;
316}
317EXPORT_SYMBOL(ipupm_get_plat_data);
318
319static struct omap_device_pm_latency omap_ipupm_latency[] = {
320 {
321 .deactivate_func = omap_device_idle_hwmods,
322 .activate_func = omap_device_enable_hwmods,
323 .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
324 },
325};
326
327static int __init omap_ipussdev_init(void)
328{
329 int status = -ENODEV;
330 int i;
331 int first = 1;
332 struct omap_hwmod *oh;
333 struct omap_device *od;
334 char *oh_name;
335 char *pdev_name = IPU_DRIVER_NAME;
336 struct omap_device_pm_latency *ohl = omap_ipupm_latency;
337 int ohl_cnt = ARRAY_SIZE(omap_ipupm_latency);
338
339 for (i = 0; i < ARRAY_SIZE(omap_ipupm_data); i++) {
340 oh_name = omap_ipupm_data[i].oh_name;
341
342 if (omap_ipupm_data[i].caps & IPUPM_CAPS_EXTINIT)
343 continue;
344
345 oh = omap_hwmod_lookup(oh_name);
346 if (!oh) {
347 pr_err("%s: could not look up %s\n", __func__, oh_name);
348
349 continue; /* to allow init to continue with other IPs
350 * we probably do not want to completely stop progress
351 * due to one module anyway, but need to be able to
352 * not try to use it if init fails
353 * this was put in to handle disabled hwmods
354 */
355
356 status = -ENODEV;
357 goto err_init;
358 }
359 omap_ipupm_data[i].oh = oh;
360
361 od = omap_device_build(pdev_name, IVA_IPU_BUS_ID+i, oh,
362 &omap_ipupm_data[i],
363 sizeof(struct omap_ipupm_mod_platform_data),
364 ohl, ohl_cnt, false);
365
366 status = IS_ERR(od);
367 WARN(status, "Could not build omap_device for %s %s\n",
368 pdev_name, oh_name);
369 if (!status) {
370 /* Save the id of the first registered dev */
371 if (first) {
372 ipu_pm_first_dev = od->pdev.id;
373 first = 0;
374 }
375 omap_ipupm_data[i].pdev = &od->pdev;
376 omap_ipupm_data[i].dev = &od->pdev.dev;
377 }
378 }
379
380err_init:
381 return status;
382}
383
384arch_initcall(omap_ipussdev_init);
diff --git a/arch/arm/mach-omap2/ipu_drv.c b/arch/arm/mach-omap2/ipu_drv.c
new file mode 100644
index 00000000000..88a78ba7be2
--- /dev/null
+++ b/arch/arm/mach-omap2/ipu_drv.c
@@ -0,0 +1,343 @@
1/*
2 * linux/arch/arm/mach-omap2/ipu_drv.c
3 *
4 * OMAP Image Processing Unit Power Management Driver
5 *
6 * Copyright (C) 2010 Texas Instruments
7 * Paul Hunt <hunt@ti.com>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 *
14 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
17 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
21 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 *
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 675 Mass Ave, Cambridge, MA 02139, USA.
26 */
27
28#include <linux/init.h>
29#include <linux/io.h>
30#include <linux/types.h>
31#include <linux/mm.h>
32#include <linux/kernel.h>
33#include <linux/module.h>
34#include <linux/device.h>
35#include <linux/file.h>
36#include <linux/fs.h>
37#include <linux/sysfs.h>
38#include <linux/proc_fs.h>
39#include <linux/seq_file.h>
40#include <linux/platform_device.h>
41#include <asm/uaccess.h>
42#include <plat/ipu_dev.h>
43
44#define IPU_CLASS_NAME "ipu-power"
45#define IPU_DRIVER_NAME "omap-ipu-pm"
46
47static struct class *omap_ipu_pm_class;
48static dev_t omap_ipu_pm_dev;
49
50int ipu_pm_first_dev;
51
52static struct proc_dir_entry *ipu_pm_proc_entry;
53/* we could iterate over something much more
54 * complicated than a set of lines of text
55 * Just debugging.
56 */
57static char *lines[] = {
58 "This is the first line from ipu_pm_seq",
59 "This is the second line from ipu_pm_seq",
60};
61
62static int ipu_pm_num_procs = ARRAY_SIZE(lines);
63
64static void *ipu_pm_seq_start(struct seq_file *s, loff_t *pos)
65{
66 if (*pos >= ipu_pm_num_procs)
67 return NULL;/* no more to read */
68 return lines[*pos];
69}
70static void *ipu_pm_seq_next(struct seq_file *s, void *v, loff_t *pos)
71{
72 (*pos)++;
73 if (*pos >= ipu_pm_num_procs)
74 return NULL;/* no more to read */
75 return lines[*pos];
76}
77static void ipu_pm_seq_stop(struct seq_file *s, void *v)
78{
79 /* nothing to do */
80}
81static int ipu_pm_seq_show(struct seq_file *s, void *v)
82{
83 seq_printf(s, "IPU_PM: %s\n", (char *) v);
84 return 0;
85}
86static const struct seq_operations ipu_pm_seq_ops = {
87 .start = ipu_pm_seq_start,
88 .next = ipu_pm_seq_next,
89 .stop = ipu_pm_seq_stop,
90 .show = ipu_pm_seq_show,
91};
92static int ipu_pm_proc_open(struct inode *inode, struct file *file)
93{
94 return seq_open(file, &ipu_pm_seq_ops);
95}
96
97static const struct file_operations ipu_pm_proc_ops = {
98 .owner = THIS_MODULE,
99 .open = ipu_pm_proc_open,
100 .read = seq_read,
101 .llseek = seq_lseek,
102 .release = seq_release,
103};
104
105static void _suspend_stub(void)
106{
107 pr_info("Suspend IOCTL received\n");
108}
109
110static void _resume_stub(void)
111{
112 pr_info("Resume IOCTL received!\n");
113}
114
115/* arg should encode the IPU-managed HWMOD
116 * to be suspended, 0 for system wide
117 */
118static int ipu_pm_ioctl(struct inode *inode, struct file *filp,
119 unsigned int cmd, unsigned long arg)
120{
121 int ret = 0;
122 /* struct omap_ipu_pm *ipu_pm = filp->private_data; */
123
124 /* FIXME: check for ipu_pm when requested */
125
126 if (_IOC_TYPE(cmd) != IPU_PM_IOC_MAGIC)
127 return -ENOTTY;
128 if (_IOC_NR(cmd) > IPU_PM_IOC_MAXNR)
129 return -ENOTTY;
130
131 /* FIXME:not using the next two yet, since no args */
132 if (_IOC_DIR(cmd) & _IOC_READ) {
133 if (!access_ok(VERIFY_WRITE,
134 (void __user *)arg,
135 _IOC_SIZE(cmd)))
136 return -EFAULT;
137 } else if (_IOC_DIR(cmd) & _IOC_WRITE) {
138 if (!access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)))
139 return -EFAULT;
140 }
141
142 switch (cmd) {
143 case IPU_PM_IOC_SUSPEND:
144 _suspend_stub();
145 break;
146 case IPU_PM_IOC_RESUME:
147 _resume_stub();
148 break;
149
150 default:
151 return -ENOTTY;
152 }
153
154 return ret;
155}
156
157
158#ifdef ZERO
159static const struct sysfs_ops {
160 ssize_t (*show)(struct kobject *, struct attribute *, char *);
161 ssize_t (*store)(struct kobject *, struct attribute *, const char *,
162 size_t);
163};
164#endif
165
166static int is_driver_init;
167
168static const struct file_operations ipm_pm_fops = {
169 .owner = THIS_MODULE,
170 .ioctl = ipu_pm_ioctl,
171 .open = NULL,
172};
173
174static struct ipu_pm_dev ipu_pm_dev;
175
176static int __devinit ipu_pm_probe(struct platform_device *pdev)
177{
178 /* FIXME: get pdata */
179 /* struct ipu_pm_platform_data *pdata = pdev->dev.platform_data; */
180 /* int id = pdev->id; */
181 /* ivahd.pdev = pdev; */
182
183 if (!is_driver_init) {
184 is_driver_init = 1;
185 /* FIXME: maybe needed for multiple dev */
186 /* spin_lock_init(&ipu_pm_lock); */
187 }
188 /* FIXME: add kobjects to kset */
189
190 return 0;
191}
192
193static int ipu_pm_drv_suspend(struct device *dev)
194{
195 struct platform_device *pdev = to_platform_device(dev);
196 int retval = 0;
197
198 if (pdev->id == ipu_pm_first_dev) {
199 pr_debug("%s.%d ASKED TO SUSPEND", pdev->name, pdev->id);
200 /* save any local context,
201 * BIOS timers could be saved locally or on Ducati
202 */
203
204 /* call our notification function */
205 retval = ipu_pm_notifications(PM_SUSPEND, NULL);
206
207 /* FIXME: Currently sending SUSPEND is enough to send
208 * Ducati to hibernate, save ctx can be called at this
209 * point to save ctx and reset remote procs
210 * Currently the save ctx process can be called using
211 * which ever proc_id, maybe this will change when
212 * Tesla support is added.
213 */
214 /* sysm3 is handling hibernation of ducati currently */
215 ipu_pm_save_ctx(SYS_M3);
216
217 /* return result, should be zero if all Ducati clients
218 * returned zero else fail code
219 */
220 }
221
222 return retval;
223}
224
225static int ipu_pm_drv_resume(struct device *dev)
226{
227 struct platform_device *pdev = to_platform_device(dev);
228 int retval = 0;
229
230 if (pdev->id == ipu_pm_first_dev) {
231 pr_debug("%s.%d ASKED TO RESUME", pdev->name, pdev->id);
232 /* restore any local context,
233 * BIOS timers could be restored locally or on Ducati
234 */
235
236 /* call our notification function */
237 retval = ipu_pm_notifications(PM_RESUME, NULL);
238
239 /* return result, should be zero if all Ducati clients
240 * returned zero else fail code
241 */
242 }
243
244 return retval;
245}
246
247static const struct dev_pm_ops ipu_pm_ops = {
248 .suspend = ipu_pm_drv_suspend,
249 .resume = ipu_pm_drv_resume,
250};
251
252static struct platform_driver ipu_pm_driver = {
253 .probe = ipu_pm_probe,
254 /*.remove = ipu_pm_remove, */
255 .driver = {
256 .name = IPU_DRIVER_NAME,
257 .owner = THIS_MODULE,
258 .pm = &ipu_pm_ops,
259 },
260};
261
262static int __init ipu_pm_init(void)
263{
264 int ret;
265 struct device *tmpdev;
266
267 if (!is_driver_init) {
268 is_driver_init = 1;
269 /* FIXME: maybe needed for multiple dev */
270 /* spin_lock_init(&ipu_pm_lock); */
271 }
272
273 ret = alloc_chrdev_region(&omap_ipu_pm_dev, 0, 2, IPU_CLASS_NAME);
274 if (ret) {
275 pr_err("%s: alloc_chrdev_region failed: %d\n", __func__, ret);
276 return ret;
277 }
278
279 /* create device class */
280 omap_ipu_pm_class = class_create(THIS_MODULE, IPU_CLASS_NAME);
281 if (IS_ERR(omap_ipu_pm_class)) {
282 ret = PTR_ERR(omap_ipu_pm_class);
283 pr_err("%s: class_create failed: %d\n", __func__, ret);
284 return ret;
285 }
286
287 /* create an instance of this device class */
288 cdev_init(&ipu_pm_dev.cdev, &ipm_pm_fops);
289 ipu_pm_dev.cdev.owner = THIS_MODULE;
290 ipu_pm_dev.cdev.ops = &ipm_pm_fops;
291 ret = cdev_add(&ipu_pm_dev.cdev, omap_ipu_pm_dev, 1);
292 if (ret)
293 pr_err("%s: cdev_add failed: %d\n", __func__, omap_ipu_pm_dev);
294
295 tmpdev = device_create(omap_ipu_pm_class, NULL,
296 omap_ipu_pm_dev,
297 NULL,
298 "ipu%d",
299 MINOR(omap_ipu_pm_dev));
300
301 if (IS_ERR(tmpdev)) {
302 ret = PTR_ERR(tmpdev);
303 pr_err("%s: device_create failed: %d\n", __func__, ret);
304 /* FIXME: add clean_cdev when error */
305 /*goto clean_cdev;*/
306 }
307 dev_info(tmpdev, "Test of writing to the device message log,"
308 "done from %s\n", __func__);
309
310 pr_info("%s initialized %s, major: %d, minor: %d\n",
311 IPU_CLASS_NAME,
312 /*pdata->name,*/
313 "ipu",
314 MAJOR(omap_ipu_pm_dev),
315 MINOR(omap_ipu_pm_dev));
316
317 /* FIXME:add a kset pointing to this new class */
318 /* omap_ipu_pm_class->dev_kobj */
319
320 /* add proc interface */
321 ipu_pm_proc_entry = create_proc_entry("ipu_proc_loads", 0, NULL);
322 if (ipu_pm_proc_entry)
323 ipu_pm_proc_entry->proc_fops = &ipu_pm_proc_ops;
324 else
325 pr_err("%s: proc entry create failed for: %s\n",
326 __func__, IPU_CLASS_NAME);
327
328 return platform_driver_register(&ipu_pm_driver);
329}
330
331static void __exit ipu_pm_exit(void)
332{
333 platform_driver_unregister(&ipu_pm_driver);
334}
335
336/* early_platform_init("earlytimer", &ipu_pm_driver); */
337module_init(ipu_pm_init);
338module_exit(ipu_pm_exit);
339
340MODULE_DESCRIPTION("OMAP IMAGE PROCESSING UNIT POWER MGMT DRIVER");
341MODULE_LICENSE("GPL");
342MODULE_ALIAS("platform:" IPU_CLASS_NAME);
343MODULE_AUTHOR("Texas Instruments Inc");
diff --git a/arch/arm/mach-omap2/ipu_utility.c b/arch/arm/mach-omap2/ipu_utility.c
new file mode 100644
index 00000000000..b16b5ad891d
--- /dev/null
+++ b/arch/arm/mach-omap2/ipu_utility.c
@@ -0,0 +1,69 @@
1/*
2 * OMAP IPU_PM utility
3 *
4 * Copyright (C) 2010 Texas Instruments Inc.
5 *
6 * Written by Paul Hunt <hunt@ti.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/kernel.h>
25#include <linux/module.h>
26#include <linux/io.h>
27#include <asm/io.h>
28#include <plat/io.h>
29
30#define ICONT1_ITCM_BASE 0x5A008000
31#define ICONT2_ITCM_BASE 0x5A018000
32
33static void __iomem *icont_itcm_ptr;
34
35/* Op-codes for simple boot sequence ending in WFI */
36static const u32 ICONT_Boot_WFI[] = {
37 0xEA000006,
38 0xEAFFFFFE,
39 0xEAFFFFFE,
40 0xEAFFFFFE,
41 0xEAFFFFFE,
42 0xEAFFFFFE,
43 0xEAFFFFFE,
44 0xEAFFFFFE,
45 0xE3A00000,
46 0xEE070F9A,
47 0xEE070F90,
48 0xE3A00000,
49 0xEAFFFFFE,
50 0xEAFFFFF1,
51};
52
53static const u32 ICONT_Boot_WFI_length = ARRAY_SIZE(ICONT_Boot_WFI);
54
55static void load_ivahd_idle_boot_code(void)
56{
57 int i;
58
59 icont_itcm_ptr = ioremap((u32) ICONT1_ITCM_BASE, 0x1000);
60 for (i = 0; i < ICONT_Boot_WFI_length; i++)
61 __raw_writel(ICONT_Boot_WFI[i], (icont_itcm_ptr + i));
62 iounmap(icont_itcm_ptr);
63
64 icont_itcm_ptr = ioremap((u32) ICONT2_ITCM_BASE, 0x1000);
65 for (i = 0; i < ICONT_Boot_WFI_length; i++)
66 __raw_writel(ICONT_Boot_WFI[i], (icont_itcm_ptr + i));
67 iounmap(icont_itcm_ptr);
68}
69EXPORT_SYMBOL(load_ivahd_idle_boot_code);
diff --git a/arch/arm/plat-omap/include/plat/ipu_dev.h b/arch/arm/plat-omap/include/plat/ipu_dev.h
new file mode 100644
index 00000000000..c7b7959c38b
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/ipu_dev.h
@@ -0,0 +1,107 @@
1/*
2 * OMAP IPU_PM driver
3 *
4 * Copyright (C) 2010 Texas Instruments Inc.
5 *
6 * Written by Paul Hunt <hunt@ti.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#ifndef IPU_PM_H
25#define IPU_PM_H
26
27#include <linux/ioctl.h>
28#include <linux/cdev.h>
29
30#include "../../../drivers/dsp/syslink/ipu_pm/ipu_pm.h"
31
32#define IPU_PM_IOC_MAGIC (0xDB)
33
34/* magic char is irrelevant until trying to upstream
35 * except for reducing exposure to misdirected ioctls
36 * see Documentation/ioctl/ioctl-number.txt
37 */
38#define IPU_PM_IOC_SUSPEND _IOW(IPU_PM_IOC_MAGIC, 0, int)
39#define IPU_PM_IOC_RESUME _IOW(IPU_PM_IOC_MAGIC, 1, int)
40
41#define IPU_PM_IOC_MAXNR 3
42
43#define IPUPM_CAPS_START_BIT 0
44#define IPUPM_CAPS_STOP_BIT 1
45#define IPUPM_CAPS_PERF_BIT 2
46#define IPUPM_CAPS_LAT_BIT 3
47#define IPUPM_CAPS_BDW_BIT 4
48/* omap_device built elsewhere */
49#define IPUPM_CAPS_EXTINIT_BIT 5
50#define IPUPM_CAPS_START (1 << IPUPM_CAPS_START_BIT)
51#define IPUPM_CAPS_STOP (1 << IPUPM_CAPS_STOP_BIT)
52#define IPUPM_CAPS_PERF (1 << IPUPM_CAPS_PERF_BIT)
53#define IPUPM_CAPS_LAT (1 << IPUPM_CAPS_LAT_BIT)
54#define IPUPM_CAPS_BDW (1 << IPUPM_CAPS_BDW_BIT)
55#define IPUPM_CAPS_EXTINIT (1 << IPUPM_CAPS_EXTINIT_BIT)
56
57#define IPU_PM_SELF 100
58#define IPU_PM_MPU 101
59#define IPU_PM_CORE 102
60
61struct omap_ipupm_mod;
62
63struct omap_ipupm_mod_ops {
64 int (*start)(enum res_type ipupm_modnum);
65 int (*stop)(enum res_type ipupm_modnum);
66};
67
68struct omap_ipupm_mod_platform_data {
69 struct platform_device *pdev;
70 struct device *dev;
71 char *name;
72 char *oh_name;
73 struct omap_hwmod *oh;
74 struct kobject kobj;
75 u32 caps;
76 struct pm_qos_request_list *qos_request;
77 struct omap_ipupm_mod_ops *ops;
78};
79
80struct omap_ipupm_mod {
81 struct device *dev;
82 struct cdev cdev;
83 atomic_t count;
84 int state;
85 int minor;
86};
87
88struct ipu_pm_dev {
89 /* FIXME: maybe more is needed */
90 struct cdev cdev;
91};
92
93extern int ipu_pm_first_dev;
94
95extern int ipu_pm_module_start(unsigned rsrc);
96extern int ipu_pm_module_stop(unsigned rsrc);
97extern int ipu_pm_module_set_rate(unsigned rsrc,
98 unsigned target_rsrc,
99 unsigned rate);
100extern int ipu_pm_module_set_latency(unsigned rsrc,
101 unsigned target_rsrc,
102 int latency);
103extern int ipu_pm_module_set_bandwidth(unsigned rsrc,
104 unsigned target_rsrc,
105 int bandwidth);
106
107#endif /* IPU_PM_H */