Skip to content

Commit 86c1d0e

Browse files
Paul HuntLuis Henriques
authored andcommitted
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 <[email protected]> omap:ipu_pm: add ipu_utility to mach-omap2 tree IVAHD Sequencer WFI Boot Code for IPU PM Driver Signed-off-by: Paul Hunt <[email protected]> omap:ipu_pm: add ipu_drv to mach-omap2 tree Add needed api for ipu_pm module Signed-off-by: Paul Hunt <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> Temporary path using cmm_write_reg to enable CAM_PHY Signed-off-by: Paul Hunt <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> Signed-off-by: Miguel Vadillo <[email protected]> syslink:ipu_pm: DFVS support for freq Fix bug in error message string referencing Signed-off-by: Paul Hunt <[email protected]> Add platform data for DSP resource and fix attributes for MPU and L3 interconnect. Signed-off-by: Paul Hunt <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> Signed-off-by: Paul Hunt <[email protected]> (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 <[email protected]> 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 <[email protected]> Signed-off-by: Paul Hunt <[email protected]> Signed-off-by: Juan Gutierrez <[email protected]> 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 <[email protected]> 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 <[email protected]> Signed-off-by: Juan Gutierrez <[email protected]> Signed-off-by: Paul Hunt <[email protected]> IPU PM: adapt aux clk funcs to new framework entities Signed-off-by: Paul Hunt <[email protected]> IPU PM: temporary workaround for missing MM AUX_CLK requests Signed-off-by: Paul Hunt <[email protected]> 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 <[email protected]> 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 <[email protected]> Signed-off-by: Paul Hunt <[email protected]> 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 <[email protected]>
1 parent a1b0890 commit 86c1d0e

File tree

6 files changed

+1439
-183
lines changed

6 files changed

+1439
-183
lines changed

arch/arm/mach-omap2/ipu_dev.c

Lines changed: 384 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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 <[email protected]>
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+
33+
struct omap_ipupm_mod_platform_data *ipupm_get_plat_data(void);
34+
35+
static 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+
};
44+
static 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+
54+
inline 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+
}
68+
EXPORT_SYMBOL(ipu_pm_module_start);
69+
70+
inline 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+
}
84+
EXPORT_SYMBOL(ipu_pm_module_stop);
85+
86+
inline 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);
119+
err_ret:
120+
return ret;
121+
}
122+
EXPORT_SYMBOL(ipu_pm_module_set_rate);
123+
124+
inline 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);
169+
err_ret:
170+
return ret;
171+
}
172+
EXPORT_SYMBOL(ipu_pm_module_set_latency);
173+
174+
inline 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+
}
202+
EXPORT_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 */
222+
static struct omap_ipupm_mod_ops omap_ipupm_ops = {
223+
.start = NULL,
224+
.stop = NULL,
225+
};
226+
227+
static 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+
313+
struct omap_ipupm_mod_platform_data *ipupm_get_plat_data(void)
314+
{
315+
return omap_ipupm_data;
316+
}
317+
EXPORT_SYMBOL(ipupm_get_plat_data);
318+
319+
static 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+
327+
static 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+
380+
err_init:
381+
return status;
382+
}
383+
384+
arch_initcall(omap_ipussdev_init);

0 commit comments

Comments
 (0)