2 * omap-pm-srf.c - OMAP power management interface implemented
3 * using Shared resource framework
5 * This code implements the OMAP power management interface to
6 * drivers, CPUIdle, CPUFreq, and DSP Bridge. It is strictly for
7 * debug/demonstration use, as it does nothing but printk() whenever a
8 * function is called (when DEBUG is defined, below)
10 * Copyright (C) 2008 Texas Instruments, Inc.
11 * Copyright (C) 2008 Nokia Corporation
14 * Interface developed by (in alphabetical order):
15 * Karthik Dasu, Tony Lindgren, Rajendra Nayak, Sakari Poussa, Veeramanikandan
16 * Raju, Anand Sawant, Igor Stoppa, Paul Walmsley, Richard Woodruff
21 #include <linux/init.h>
22 #include <linux/cpufreq.h>
23 #include <linux/device.h>
24 #include <linux/module.h>
26 #include <plat/omap-pm.h>
27 #include <plat/powerdomain.h>
28 #include <plat/resource.h>
29 #include <plat/omap_device.h>
31 struct omap_opp
*dsp_opps
;
32 struct omap_opp
*mpu_opps
;
33 struct omap_opp
*l3_opps
;
35 #define LAT_RES_POSTAMBLE "_latency"
36 #define MAX_LATENCY_RES_NAME 30
39 * get_lat_res_name - gets the latency resource name given a power domain name
40 * @pwrdm_name: Name of the power domain.
41 * @lat_name: Buffer in which latency resource name is populated
42 * @size: Max size of the latency resource name
44 * Returns the latency resource name populated in lat_name.
46 void get_lat_res_name(const char *pwrdm_name
, char **lat_name
, int size
)
48 strcpy(*lat_name
, "");
49 WARN_ON(strlen(pwrdm_name
) + strlen(LAT_RES_POSTAMBLE
) > size
);
50 strcpy(*lat_name
, pwrdm_name
);
51 strcat(*lat_name
, LAT_RES_POSTAMBLE
);
56 * Device-driver-originated constraints (via board-*.c files)
59 void omap_pm_set_max_mpu_wakeup_lat(struct device
*dev
, long t
)
67 pr_debug("OMAP PM: remove max MPU wakeup latency constraint: "
68 "dev %s\n", dev_name(dev
));
69 resource_release("mpu_latency", dev
);
71 pr_debug("OMAP PM: add max MPU wakeup latency constraint: "
72 "dev %s, t = %ld usec\n", dev_name(dev
), t
);
73 resource_request("mpu_latency", dev
, t
);
77 void omap_pm_set_min_bus_tput(struct device
*dev
, u8 agent_id
, unsigned long r
)
79 if (!dev
|| (agent_id
!= OCP_INITIATOR_AGENT
&&
80 agent_id
!= OCP_TARGET_AGENT
)) {
86 pr_debug("OMAP PM: remove min bus tput constraint: "
87 "dev %s for agent_id %d\n", dev_name(dev
), agent_id
);
88 resource_release("vdd2_opp", dev
);
90 pr_debug("OMAP PM: add min bus tput constraint: "
91 "dev %s for agent_id %d: rate %ld KiB\n",
92 dev_name(dev
), agent_id
, r
);
93 resource_request("vdd2_opp", dev
, r
);
97 void omap_pm_set_max_dev_wakeup_lat(struct device
*dev
, long t
)
99 struct omap_device
*odev
;
100 struct powerdomain
*pwrdm_dev
;
101 struct platform_device
*pdev
;
104 if (!dev
|| t
< -1) {
108 /* Look for the devices Power Domain */
110 * WARNING! If device is not a platform device, container_of will
111 * return a pointer to unknown memory!
112 * TODO: Either change omap-pm interface to support only platform
113 * devices, or change the underlying omapdev implementation to
114 * support normal devices.
116 pdev
= container_of(dev
, struct platform_device
, dev
);
118 /* Try to catch non platform devices. */
119 if (pdev
->name
== NULL
) {
120 printk(KERN_ERR
"OMAP-PM: Error: platform device not valid\n");
124 odev
= omap_device_find_pdev(pdev
);
126 pwrdm_dev
= omap_device_get_pwrdm(odev
);
128 printk(KERN_ERR
"OMAP-PM: Error: Could not find omapdev "
129 "for %s\n", pdev
->name
);
133 lat_res_name
= kmalloc(MAX_LATENCY_RES_NAME
, GFP_KERNEL
);
135 printk(KERN_ERR
"OMAP-PM: FATAL ERROR: kmalloc failed\n");
138 get_lat_res_name(pwrdm_dev
->name
, &lat_res_name
, MAX_LATENCY_RES_NAME
);
141 pr_debug("OMAP PM: remove max device latency constraint: "
142 "dev %s\n", dev_name(dev
));
143 resource_release(lat_res_name
, dev
);
145 pr_debug("OMAP PM: add max device latency constraint: "
146 "dev %s, t = %ld usec\n", dev_name(dev
), t
);
147 resource_request(lat_res_name
, dev
, t
);
154 void omap_pm_set_max_sdma_lat(struct device
*dev
, long t
)
156 if (!dev
|| t
< -1) {
162 pr_debug("OMAP PM: remove max DMA latency constraint: "
163 "dev %s\n", dev_name(dev
));
164 resource_release("core_latency", dev
);
166 pr_debug("OMAP PM: add max DMA latency constraint: "
167 "dev %s, t = %ld usec\n", dev_name(dev
), t
);
168 resource_request("core_latency", dev
, t
);
172 static struct device dummy_dsp_dev
;
175 * DSP Bridge-specific constraints
177 const struct omap_opp
*omap_pm_dsp_get_opp_table(void)
179 pr_debug("OMAP PM: DSP request for OPP table\n");
182 * Return DSP frequency table here: The final item in the
183 * array should have .rate = .opp_id = 0.
188 EXPORT_SYMBOL(omap_pm_dsp_get_opp_table
);
190 void omap_pm_dsp_set_min_opp(u8 opp_id
)
197 pr_debug("OMAP PM: DSP requests minimum VDD1 OPP to be %d\n", opp_id
);
200 * For now pass a dummy_dev struct for SRF to identify the caller.
201 * Maybe its good to have DSP pass this as an argument
203 resource_request("vdd1_opp", &dummy_dsp_dev
, opp_id
);
206 EXPORT_SYMBOL(omap_pm_dsp_set_min_opp
);
208 u8
omap_pm_dsp_get_opp(void)
210 pr_debug("OMAP PM: DSP requests current DSP OPP ID\n");
211 return resource_get_level("vdd1_opp");
213 EXPORT_SYMBOL(omap_pm_dsp_get_opp
);
215 u8
omap_pm_vdd1_get_opp(void)
217 pr_debug("OMAP PM: User requests current VDD1 OPP\n");
218 return resource_get_level("vdd1_opp");
220 EXPORT_SYMBOL(omap_pm_vdd1_get_opp
);
222 u8
omap_pm_vdd2_get_opp(void)
224 pr_debug("OMAP PM: User requests current VDD2 OPP\n");
225 return resource_get_level("vdd2_opp");
227 EXPORT_SYMBOL(omap_pm_vdd2_get_opp
);
230 * CPUFreq-originated constraint
232 * In the future, this should be handled by custom OPP clocktype
236 struct cpufreq_frequency_table
**omap_pm_cpu_get_freq_table(void)
238 pr_debug("OMAP PM: CPUFreq request for frequency table\n");
241 * Return CPUFreq frequency table here: loop over
242 * all VDD1 clkrates, pull out the mpu_ck frequencies, build
249 static struct device dummy_cpufreq_dev
;
251 void omap_pm_cpu_set_freq(unsigned long f
)
258 pr_debug("OMAP PM: CPUFreq requests CPU frequency to be set to %lu\n",
261 resource_request("mpu_freq", &dummy_cpufreq_dev
, f
);
264 EXPORT_SYMBOL(omap_pm_cpu_set_freq
);
266 unsigned long omap_pm_cpu_get_freq(void)
268 pr_debug("OMAP PM: CPUFreq requests current CPU frequency\n");
269 return resource_get_level("mpu_freq");
271 EXPORT_SYMBOL(omap_pm_cpu_get_freq
);
274 * Device context loss tracking
277 int omap_pm_get_dev_context_loss_count(struct device
*dev
)
279 struct platform_device
*pdev
;
280 struct omap_device
*odev
;
281 struct powerdomain
*pwrdm
;
288 pr_debug("OMAP PM: returning context loss count for dev %s\n",
292 * Map the device to the powerdomain. Return the powerdomain
295 pdev
= to_platform_device(dev
);
296 odev
= omap_device_find_pdev(pdev
);
299 pwrdm
= omap_device_get_pwrdm(odev
);
301 return pwrdm
->state_counter
[0];
307 * Powerdomain usecounting hooks
310 void omap_pm_pwrdm_active(struct powerdomain
*pwrdm
)
317 pr_debug("OMAP PM: powerdomain %s is becoming active\n", pwrdm
->name
);
320 * CDP code apparently will need these for the enable_power_domain()
321 * and disable_power_domain() functions.
325 void omap_pm_pwrdm_inactive(struct powerdomain
*pwrdm
)
332 pr_debug("OMAP PM: powerdomain %s is becoming inactive\n",
336 * CDP code apparently will need these for the enable_power_domain()
337 * and disable_power_domain() functions.
342 * Should be called before clk framework since clk fw will call
343 * omap_pm_pwrdm_{in,}active()
345 int __init
omap_pm_if_early_init(struct omap_opp
*mpu_opp_table
,
346 struct omap_opp
*dsp_opp_table
,
347 struct omap_opp
*l3_opp_table
)
349 mpu_opps
= mpu_opp_table
;
350 dsp_opps
= dsp_opp_table
;
351 l3_opps
= l3_opp_table
;
355 /* Must be called after clock framework is initialized */
356 int __init
omap_pm_if_init(void)
358 resource_init(resources_omap
);
362 void omap_pm_if_exit(void)
364 /* Deallocate CPUFreq frequency table here */