PSP-03.00.00.03
[linux-ginger.git] / arch / arm / plat-omap / omap-pm-srf.c
bloba28945bdab7e252f6ef1d38a80c91b8edea7bed1
1 /*
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
12 * Paul Walmsley
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
19 #undef DEBUG
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
38 /**
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);
52 return;
56 * Device-driver-originated constraints (via board-*.c files)
59 void omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t)
61 if (!dev || t < -1) {
62 WARN_ON(1);
63 return;
66 if (t == -1) {
67 pr_debug("OMAP PM: remove max MPU wakeup latency constraint: "
68 "dev %s\n", dev_name(dev));
69 resource_release("mpu_latency", dev);
70 } else {
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)) {
81 WARN_ON(1);
82 return;
85 if (r == 0) {
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);
89 } else {
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;
102 char *lat_res_name;
104 if (!dev || t < -1) {
105 WARN_ON(1);
106 return;
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");
121 return;
124 odev = omap_device_find_pdev(pdev);
125 if (odev) {
126 pwrdm_dev = omap_device_get_pwrdm(odev);
127 } else {
128 printk(KERN_ERR "OMAP-PM: Error: Could not find omapdev "
129 "for %s\n", pdev->name);
130 return;
133 lat_res_name = kmalloc(MAX_LATENCY_RES_NAME, GFP_KERNEL);
134 if (!lat_res_name) {
135 printk(KERN_ERR "OMAP-PM: FATAL ERROR: kmalloc failed\n");
136 return;
138 get_lat_res_name(pwrdm_dev->name, &lat_res_name, MAX_LATENCY_RES_NAME);
140 if (t == -1) {
141 pr_debug("OMAP PM: remove max device latency constraint: "
142 "dev %s\n", dev_name(dev));
143 resource_release(lat_res_name, dev);
144 } else {
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);
150 kfree(lat_res_name);
151 return;
154 void omap_pm_set_max_sdma_lat(struct device *dev, long t)
156 if (!dev || t < -1) {
157 WARN_ON(1);
158 return;
161 if (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);
165 } else {
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.
186 return NULL;
188 EXPORT_SYMBOL(omap_pm_dsp_get_opp_table);
190 void omap_pm_dsp_set_min_opp(u8 opp_id)
192 if (opp_id == 0) {
193 WARN_ON(1);
194 return;
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);
204 return;
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
233 * functions.
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
243 * table
246 return NULL;
249 static struct device dummy_cpufreq_dev;
251 void omap_pm_cpu_set_freq(unsigned long f)
253 if (f == 0) {
254 WARN_ON(1);
255 return;
258 pr_debug("OMAP PM: CPUFreq requests CPU frequency to be set to %lu\n",
261 resource_request("mpu_freq", &dummy_cpufreq_dev, f);
262 return;
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;
283 if (!dev) {
284 WARN_ON(1);
285 return -EINVAL;
288 pr_debug("OMAP PM: returning context loss count for dev %s\n",
289 dev_name(dev));
292 * Map the device to the powerdomain. Return the powerdomain
293 * off counter.
295 pdev = to_platform_device(dev);
296 odev = omap_device_find_pdev(pdev);
298 if (odev) {
299 pwrdm = omap_device_get_pwrdm(odev);
300 if (pwrdm)
301 return pwrdm->state_counter[0];
303 return 0;
307 * Powerdomain usecounting hooks
310 void omap_pm_pwrdm_active(struct powerdomain *pwrdm)
312 if (!pwrdm) {
313 WARN_ON(1);
314 return;
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)
327 if (!pwrdm) {
328 WARN_ON(1);
329 return;
332 pr_debug("OMAP PM: powerdomain %s is becoming inactive\n",
333 pwrdm->name);
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;
352 return 0;
355 /* Must be called after clock framework is initialized */
356 int __init omap_pm_if_init(void)
358 resource_init(resources_omap);
359 return 0;
362 void omap_pm_if_exit(void)
364 /* Deallocate CPUFreq frequency table here */