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>
25 #include <plat/omap-pm.h>
26 #include <plat/powerdomain.h>
27 #include <plat/resource.h>
28 #include <plat/omapdev.h>
30 struct omap_opp
*dsp_opps
;
31 struct omap_opp
*mpu_opps
;
32 struct omap_opp
*l3_opps
;
34 #define LAT_RES_POSTAMBLE "_latency"
35 #define MAX_LATENCY_RES_NAME 30
38 * get_lat_res_name - gets the latency resource name given a power domain name
39 * @pwrdm_name: Name of the power domain.
40 * @lat_name: Buffer in which latency resource name is populated
41 * @size: Max size of the latency resource name
43 * Returns the latency resource name populated in lat_name.
45 void get_lat_res_name(const char *pwrdm_name
, char **lat_name
, int size
)
47 strcpy(*lat_name
, "");
48 WARN_ON(strlen(pwrdm_name
) + strlen(LAT_RES_POSTAMBLE
) > size
);
49 strcpy(*lat_name
, pwrdm_name
);
50 strcat(*lat_name
, LAT_RES_POSTAMBLE
);
55 * Device-driver-originated constraints (via board-*.c files)
58 void omap_pm_set_max_mpu_wakeup_lat(struct device
*dev
, long t
)
66 pr_debug("OMAP PM: remove max MPU wakeup latency constraint: "
67 "dev %s\n", dev_name(dev
));
68 resource_release("mpu_latency", dev
);
70 pr_debug("OMAP PM: add max MPU wakeup latency constraint: "
71 "dev %s, t = %ld usec\n", dev_name(dev
), t
);
72 resource_request("mpu_latency", dev
, t
);
76 void omap_pm_set_min_bus_tput(struct device
*dev
, u8 agent_id
, unsigned long r
)
78 if (!dev
|| agent_id
!= OCP_INITIATOR_AGENT
||
79 agent_id
!= OCP_TARGET_AGENT
) {
85 pr_debug("OMAP PM: remove min bus tput constraint: "
86 "dev %s for agent_id %d\n", dev_name(dev
), agent_id
);
88 pr_debug("OMAP PM: add min bus tput constraint: "
89 "dev %s for agent_id %d: rate %ld KiB\n",
90 dev_name(dev
), agent_id
, r
);
93 * This code should model the interconnect and compute the
94 * required clock frequency, convert that to a VDD2 OPP ID, then
95 * set the VDD2 OPP appropriately.
97 * TI CDP code can call constraint_set here on the VDD2 OPP.
101 void omap_pm_set_max_dev_wakeup_lat(struct device
*dev
, long t
)
103 struct omapdev
*odev
;
104 struct powerdomain
*pwrdm_dev
;
105 struct platform_device
*pdev
;
108 if (!dev
|| t
< -1) {
112 /* Look for the devices Power Domain */
114 * WARNING! If device is not a platform device, container_of will
115 * return a pointer to unknown memory!
116 * TODO: Either change omap-pm interface to support only platform
117 * devices, or change the underlying omapdev implementation to
118 * support normal devices.
120 pdev
= container_of(dev
, struct platform_device
, dev
);
122 /* Try to catch non platform devices. */
123 if (pdev
->name
== NULL
) {
124 printk(KERN_ERR
"OMAP-PM: Error: platform device not valid\n");
128 odev
= omapdev_find_pdev(pdev
);
130 pwrdm_dev
= omapdev_get_pwrdm(odev
);
132 printk(KERN_ERR
"OMAP-PM: Error: Could not find omapdev "
133 "for %s\n", pdev
->name
);
137 lat_res_name
= kmalloc(MAX_LATENCY_RES_NAME
, GFP_KERNEL
);
139 printk(KERN_ERR
"OMAP-PM: FATAL ERROR: kmalloc failed\n");
142 get_lat_res_name(pwrdm_dev
->name
, &lat_res_name
, MAX_LATENCY_RES_NAME
);
145 pr_debug("OMAP PM: remove max device latency constraint: "
146 "dev %s\n", dev_name(dev
));
147 resource_release(lat_res_name
, dev
);
149 pr_debug("OMAP PM: add max device latency constraint: "
150 "dev %s, t = %ld usec\n", dev_name(dev
), t
);
151 resource_request(lat_res_name
, dev
, t
);
158 void omap_pm_set_max_sdma_lat(struct device
*dev
, long t
)
160 if (!dev
|| t
< -1) {
166 pr_debug("OMAP PM: remove max DMA latency constraint: "
167 "dev %s\n", dev_name(dev
));
168 resource_release("core_latency", dev
);
170 pr_debug("OMAP PM: add max DMA latency constraint: "
171 "dev %s, t = %ld usec\n", dev_name(dev
), t
);
172 resource_request("core_latency", dev
, t
);
178 * DSP Bridge-specific constraints
180 const struct omap_opp
*omap_pm_dsp_get_opp_table(void)
182 pr_debug("OMAP PM: DSP request for OPP table\n");
185 * Return DSP frequency table here: The final item in the
186 * array should have .rate = .opp_id = 0.
192 void omap_pm_dsp_set_min_opp(u8 opp_id
)
199 pr_debug("OMAP PM: DSP requests minimum VDD1 OPP to be %d\n", opp_id
);
203 * For l-o dev tree, our VDD1 clk is keyed on OPP ID, so we
204 * can just test to see which is higher, the CPU's desired OPP
205 * ID or the DSP's desired OPP ID, and use whichever is
208 * In CDP12.14+, the VDD1 OPP custom clock that controls the DSP
209 * rate is keyed on MPU speed, not the OPP ID. So we need to
210 * map the OPP ID to the MPU speed for use with clk_set_rate()
211 * if it is higher than the current OPP clock rate.
216 u8
omap_pm_dsp_get_opp(void)
218 pr_debug("OMAP PM: DSP requests current DSP OPP ID\n");
221 * For l-o dev tree, call clk_get_rate() on VDD1 OPP clock
224 * Call clk_get_rate() on the OPP custom clock, map that to an
225 * OPP ID using the tables defined in board-*.c/chip-*.c files.
232 * CPUFreq-originated constraint
234 * In the future, this should be handled by custom OPP clocktype
238 struct cpufreq_frequency_table
**omap_pm_cpu_get_freq_table(void)
240 pr_debug("OMAP PM: CPUFreq request for frequency table\n");
243 * Return CPUFreq frequency table here: loop over
244 * all VDD1 clkrates, pull out the mpu_ck frequencies, build
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",
262 * For l-o dev tree, determine whether MPU freq or DSP OPP id
263 * freq is higher. Find the OPP ID corresponding to the
264 * higher frequency. Call clk_round_rate() and clk_set_rate()
265 * on the OPP custom clock.
267 * CDP should just be able to set the VDD1 OPP clock rate here.
271 unsigned long omap_pm_cpu_get_freq(void)
273 pr_debug("OMAP PM: CPUFreq requests current CPU frequency\n");
276 * Call clk_get_rate() on the mpu_ck.
283 * Device context loss tracking
286 int omap_pm_get_dev_context_loss_count(struct device
*dev
)
293 pr_debug("OMAP PM: returning context loss count for dev %s\n",
297 * Map the device to the powerdomain. Return the powerdomain
305 * Powerdomain usecounting hooks
308 void omap_pm_pwrdm_active(struct powerdomain
*pwrdm
)
315 pr_debug("OMAP PM: powerdomain %s is becoming active\n", pwrdm
->name
);
318 * CDP code apparently will need these for the enable_power_domain()
319 * and disable_power_domain() functions.
323 void omap_pm_pwrdm_inactive(struct powerdomain
*pwrdm
)
330 pr_debug("OMAP PM: powerdomain %s is becoming inactive\n",
334 * CDP code apparently will need these for the enable_power_domain()
335 * and disable_power_domain() functions.
340 * Should be called before clk framework since clk fw will call
341 * omap_pm_pwrdm_{in,}active()
343 int __init
omap_pm_if_early_init(struct omap_opp
*mpu_opp_table
,
344 struct omap_opp
*dsp_opp_table
,
345 struct omap_opp
*l3_opp_table
)
347 mpu_opps
= mpu_opp_table
;
348 dsp_opps
= dsp_opp_table
;
349 l3_opps
= l3_opp_table
;
353 /* Must be called after clock framework is initialized */
354 int __init
omap_pm_if_init(void)
356 resource_init(resources_omap
);
360 void omap_pm_if_exit(void)
362 /* Deallocate CPUFreq frequency table here */