1/* 2 * omap-pm-noop.c - OMAP power management interface - dummy version 3 * 4 * This code implements the OMAP power management interface to 5 * drivers, CPUIdle, CPUFreq, and DSP Bridge. It is strictly for 6 * debug/demonstration use, as it does nothing but printk() whenever a 7 * function is called (when DEBUG is defined, below) 8 * 9 * Copyright (C) 2008-2009 Texas Instruments, Inc. 10 * Copyright (C) 2008-2009 Nokia Corporation 11 * Paul Walmsley 12 * 13 * Interface developed by (in alphabetical order): 14 * Karthik Dasu, Tony Lindgren, Rajendra Nayak, Sakari Poussa, Veeramanikandan 15 * Raju, Anand Sawant, Igor Stoppa, Paul Walmsley, Richard Woodruff 16 */ 17 18#undef DEBUG 19 20#include <linux/init.h> 21#include <linux/cpufreq.h> 22#include <linux/device.h> 23 24/* Interface documentation is in mach/omap-pm.h */ 25#include <plat/omap-pm.h> 26 27#include <plat/powerdomain.h> 28 29struct omap_opp *dsp_opps; 30struct omap_opp *mpu_opps; 31struct omap_opp *l3_opps; 32 33/* 34 * Device-driver-originated constraints (via board-*.c files) 35 */ 36 37int omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t) 38{ 39 if (!dev || t < -1) { 40 WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); 41 return -EINVAL; 42 }; 43 44 if (t == -1) 45 pr_debug("OMAP PM: remove max MPU wakeup latency constraint: " 46 "dev %s\n", dev_name(dev)); 47 else 48 pr_debug("OMAP PM: add max MPU wakeup latency constraint: " 49 "dev %s, t = %ld usec\n", dev_name(dev), t); 50 51 /* 52 * For current Linux, this needs to map the MPU to a 53 * powerdomain, then go through the list of current max lat 54 * constraints on the MPU and find the smallest. If 55 * the latency constraint has changed, the code should 56 * recompute the state to enter for the next powerdomain 57 * state. 58 * 59 * TI CDP code can call constraint_set here. 60 */ 61 62 return 0; 63} 64 65int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r) 66{ 67 if (!dev || (agent_id != OCP_INITIATOR_AGENT && 68 agent_id != OCP_TARGET_AGENT)) { 69 WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); 70 return -EINVAL; 71 }; 72 73 if (r == 0) 74 pr_debug("OMAP PM: remove min bus tput constraint: " 75 "dev %s for agent_id %d\n", dev_name(dev), agent_id); 76 else 77 pr_debug("OMAP PM: add min bus tput constraint: " 78 "dev %s for agent_id %d: rate %ld KiB\n", 79 dev_name(dev), agent_id, r); 80 81 /* 82 * This code should model the interconnect and compute the 83 * required clock frequency, convert that to a VDD2 OPP ID, then 84 * set the VDD2 OPP appropriately. 85 * 86 * TI CDP code can call constraint_set here on the VDD2 OPP. 87 */ 88 89 return 0; 90} 91 92int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev, 93 long t) 94{ 95 if (!req_dev || !dev || t < -1) { 96 WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); 97 return -EINVAL; 98 }; 99 100 if (t == -1) 101 pr_debug("OMAP PM: remove max device latency constraint: " 102 "dev %s\n", dev_name(dev)); 103 else 104 pr_debug("OMAP PM: add max device latency constraint: " 105 "dev %s, t = %ld usec\n", dev_name(dev), t); 106 107 /* 108 * For current Linux, this needs to map the device to a 109 * powerdomain, then go through the list of current max lat 110 * constraints on that powerdomain and find the smallest. If 111 * the latency constraint has changed, the code should 112 * recompute the state to enter for the next powerdomain 113 * state. Conceivably, this code should also determine 114 * whether to actually disable the device clocks or not, 115 * depending on how long it takes to re-enable the clocks. 116 * 117 * TI CDP code can call constraint_set here. 118 */ 119 120 return 0; 121} 122 123int omap_pm_set_max_sdma_lat(struct device *dev, long t) 124{ 125 if (!dev || t < -1) { 126 WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); 127 return -EINVAL; 128 }; 129 130 if (t == -1) 131 pr_debug("OMAP PM: remove max DMA latency constraint: " 132 "dev %s\n", dev_name(dev)); 133 else 134 pr_debug("OMAP PM: add max DMA latency constraint: " 135 "dev %s, t = %ld usec\n", dev_name(dev), t); 136 137 /* 138 * For current Linux PM QOS params, this code should scan the 139 * list of maximum CPU and DMA latencies and select the 140 * smallest, then set cpu_dma_latency pm_qos_param 141 * accordingly. 142 * 143 * For future Linux PM QOS params, with separate CPU and DMA 144 * latency params, this code should just set the dma_latency param. 145 * 146 * TI CDP code can call constraint_set here. 147 */ 148 149 return 0; 150} 151 152int omap_pm_set_min_clk_rate(struct device *dev, struct clk *c, long r) 153{ 154 if (!dev || !c || r < 0) { 155 WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); 156 return -EINVAL; 157 } 158 159 if (r == 0) 160 pr_debug("OMAP PM: remove min clk rate constraint: " 161 "dev %s\n", dev_name(dev)); 162 else 163 pr_debug("OMAP PM: add min clk rate constraint: " 164 "dev %s, rate = %ld Hz\n", dev_name(dev), r); 165 166 /* 167 * Code in a real implementation should keep track of these 168 * constraints on the clock, and determine the highest minimum 169 * clock rate. It should iterate over each OPP and determine 170 * whether the OPP will result in a clock rate that would 171 * satisfy this constraint (and any other PM constraint in effect 172 * at that time). Once it finds the lowest-voltage OPP that 173 * meets those conditions, it should switch to it, or return 174 * an error if the code is not capable of doing so. 175 */ 176 177 return 0; 178} 179 180/* 181 * DSP Bridge-specific constraints 182 */ 183 184const struct omap_opp *omap_pm_dsp_get_opp_table(void) 185{ 186 pr_debug("OMAP PM: DSP request for OPP table\n"); 187 188 /* 189 * Return DSP frequency table here: The final item in the 190 * array should have .rate = .opp_id = 0. 191 */ 192 193 return NULL; 194} 195 196void omap_pm_dsp_set_min_opp(u8 opp_id) 197{ 198 if (opp_id == 0) { 199 WARN_ON(1); 200 return; 201 } 202 203 pr_debug("OMAP PM: DSP requests minimum VDD1 OPP to be %d\n", opp_id); 204 205 /* 206 * 207 * For l-o dev tree, our VDD1 clk is keyed on OPP ID, so we 208 * can just test to see which is higher, the CPU's desired OPP 209 * ID or the DSP's desired OPP ID, and use whichever is 210 * highest. 211 * 212 * In CDP12.14+, the VDD1 OPP custom clock that controls the DSP 213 * rate is keyed on MPU speed, not the OPP ID. So we need to 214 * map the OPP ID to the MPU speed for use with clk_set_rate() 215 * if it is higher than the current OPP clock rate. 216 * 217 */ 218} 219 220 221u8 omap_pm_dsp_get_opp(void) 222{ 223 pr_debug("OMAP PM: DSP requests current DSP OPP ID\n"); 224 225 /* 226 * For l-o dev tree, call clk_get_rate() on VDD1 OPP clock 227 * 228 * CDP12.14+: 229 * Call clk_get_rate() on the OPP custom clock, map that to an 230 * OPP ID using the tables defined in board-*.c/chip-*.c files. 231 */ 232 233 return 0; 234} 235 236/* 237 * CPUFreq-originated constraint 238 * 239 * In the future, this should be handled by custom OPP clocktype 240 * functions. 241 */ 242 243struct cpufreq_frequency_table **omap_pm_cpu_get_freq_table(void) 244{ 245 pr_debug("OMAP PM: CPUFreq request for frequency table\n"); 246 247 /* 248 * Return CPUFreq frequency table here: loop over 249 * all VDD1 clkrates, pull out the mpu_ck frequencies, build 250 * table 251 */ 252 253 return NULL; 254} 255 256void omap_pm_cpu_set_freq(unsigned long f) 257{ 258 if (f == 0) { 259 WARN_ON(1); 260 return; 261 } 262 263 pr_debug("OMAP PM: CPUFreq requests CPU frequency to be set to %lu\n", 264 f); 265 266 /* 267 * For l-o dev tree, determine whether MPU freq or DSP OPP id 268 * freq is higher. Find the OPP ID corresponding to the 269 * higher frequency. Call clk_round_rate() and clk_set_rate() 270 * on the OPP custom clock. 271 * 272 * CDP should just be able to set the VDD1 OPP clock rate here. 273 */ 274} 275 276unsigned long omap_pm_cpu_get_freq(void) 277{ 278 pr_debug("OMAP PM: CPUFreq requests current CPU frequency\n"); 279 280 /* 281 * Call clk_get_rate() on the mpu_ck. 282 */ 283 284 return 0; 285} 286 287/* 288 * Device context loss tracking 289 */ 290 291int omap_pm_get_dev_context_loss_count(struct device *dev) 292{ 293 if (!dev) { 294 WARN_ON(1); 295 return -EINVAL; 296 }; 297 298 pr_debug("OMAP PM: returning context loss count for dev %s\n", 299 dev_name(dev)); 300 301 /* 302 * Map the device to the powerdomain. Return the powerdomain 303 * off counter. 304 */ 305 306 return 0; 307} 308 309 310/* Should be called before clk framework init */ 311int __init omap_pm_if_early_init(struct omap_opp *mpu_opp_table, 312 struct omap_opp *dsp_opp_table, 313 struct omap_opp *l3_opp_table) 314{ 315 mpu_opps = mpu_opp_table; 316 dsp_opps = dsp_opp_table; 317 l3_opps = l3_opp_table; 318 return 0; 319} 320 321/* Must be called after clock framework is initialized */ 322int __init omap_pm_if_init(void) 323{ 324 return 0; 325} 326 327void omap_pm_if_exit(void) 328{ 329 /* Deallocate CPUFreq frequency table here */ 330} 331