2 * linux/arch/arm/mach-omap2/resource34xx.c
3 * OMAP3 resource init/change_level/validate_level functions
5 * Copyright (C) 2007-2008 Texas Instruments, Inc.
6 * Rajendra Nayak <rnayak@ti.com>
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.
12 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
13 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
14 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 #include <linux/pm_qos_params.h>
20 #include <linux/cpufreq.h>
21 #include <linux/delay.h>
23 #include <plat/powerdomain.h>
24 #include <plat/clockdomain.h>
25 #include <plat/omap34xx.h>
27 #include "smartreflex.h"
28 #include "resource34xx.h"
31 #include "cm-regbits-34xx.h"
34 * init_latency - Initializes the mpu/core latency resource.
35 * @resp: Latency resource to be initalized
39 void init_latency(struct shared_resource
*resp
)
41 resp
->no_of_users
= 0;
42 resp
->curr_level
= RES_DEFAULTLEVEL
;
43 *((u8
*)resp
->resource_data
) = 0;
48 * set_latency - Adds/Updates and removes the CPU_DMA_LATENCY in *pm_qos_params.
49 * @resp: resource pointer
50 * @latency: target latency to be set
52 * Returns 0 on success, or error values as returned by
53 * pm_qos_update_requirement/pm_qos_add_requirement.
55 int set_latency(struct shared_resource
*resp
, u32 latency
)
59 if (resp
->curr_level
== latency
)
62 /* Update the resources current level */
63 resp
->curr_level
= latency
;
65 pm_qos_req_added
= resp
->resource_data
;
66 if (latency
== RES_DEFAULTLEVEL
)
67 /* No more users left, remove the pm_qos_req if present */
68 if (*pm_qos_req_added
) {
69 pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY
,
71 *pm_qos_req_added
= 0;
75 if (*pm_qos_req_added
) {
76 return pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY
,
79 *pm_qos_req_added
= 1;
80 return pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY
,
86 * init_pd_latency - Initializes the power domain latency resource.
87 * @resp: Power Domain Latency resource to be initialized.
91 void init_pd_latency(struct shared_resource
*resp
)
93 struct pd_latency_db
*pd_lat_db
;
95 resp
->no_of_users
= 0;
97 resp
->curr_level
= PD_LATENCY_OFF
;
99 resp
->curr_level
= PD_LATENCY_RET
;
100 pd_lat_db
= resp
->resource_data
;
101 /* Populate the power domain associated with the latency resource */
102 pd_lat_db
->pd
= pwrdm_lookup(pd_lat_db
->pwrdm_name
);
103 set_pwrdm_state(pd_lat_db
->pd
, resp
->curr_level
);
108 * set_pd_latency - Updates the curr_level of the power domain resource.
109 * @resp: Power domain latency resource.
110 * @latency: New latency value acceptable.
112 * This function maps the latency in microsecs to the acceptable
113 * Power domain state using the latency DB.
114 * It then programs the power domain to enter the target state.
117 int set_pd_latency(struct shared_resource
*resp
, u32 latency
)
119 u32 pd_lat_level
, ind
;
120 struct pd_latency_db
*pd_lat_db
;
121 struct powerdomain
*pwrdm
;
123 pd_lat_db
= resp
->resource_data
;
124 pwrdm
= pd_lat_db
->pd
;
125 pd_lat_level
= PD_LATENCY_OFF
;
126 /* using the latency db map to the appropriate PD state */
127 for (ind
= 0; ind
< PD_LATENCY_MAXLEVEL
; ind
++) {
128 if (pd_lat_db
->latency
[ind
] < latency
) {
134 if (!enable_off_mode
&& pd_lat_level
== PD_LATENCY_OFF
)
135 pd_lat_level
= PD_LATENCY_RET
;
137 resp
->curr_level
= pd_lat_level
;
138 set_pwrdm_state(pwrdm
, pd_lat_level
);
142 static struct shared_resource
*vdd1_resp
;
143 static struct shared_resource
*vdd2_resp
;
144 static struct device dummy_mpu_dev
;
145 static struct device dummy_dsp_dev
;
146 static struct device vdd2_dev
;
147 static int vdd1_lock
;
148 static int vdd2_lock
;
149 static struct clk
*dpll1_clk
, *dpll2_clk
, *dpll3_clk
;
150 static int curr_vdd1_opp
;
151 static int curr_vdd2_opp
;
152 static DEFINE_MUTEX(dvfs_mutex
);
154 static unsigned short get_opp(struct omap_opp
*opp_freq_table
,
157 struct omap_opp
*prcm_config
;
158 prcm_config
= opp_freq_table
;
160 if (prcm_config
->rate
<= freq
)
161 return prcm_config
->opp_id
; /* Return the Highest OPP */
162 for (; prcm_config
->rate
; prcm_config
--)
163 if (prcm_config
->rate
< freq
)
164 return (prcm_config
+1)->opp_id
;
165 else if (prcm_config
->rate
== freq
)
166 return prcm_config
->opp_id
;
167 /* Return the least OPP */
168 return (prcm_config
+1)->opp_id
;
172 * init_opp - Initialize the OPP resource
174 void init_opp(struct shared_resource
*resp
)
177 resp
->no_of_users
= 0;
179 if (!mpu_opps
|| !dsp_opps
|| !l3_opps
)
182 /* Initialize the current level of the OPP resource
183 * to the opp set by u-boot.
185 if (strcmp(resp
->name
, "vdd1_opp") == 0) {
187 dpll1_clk
= clk_get(NULL
, "dpll1_ck");
188 dpll2_clk
= clk_get(NULL
, "dpll2_ck");
189 resp
->curr_level
= get_opp(mpu_opps
+ MAX_VDD1_OPP
,
191 curr_vdd1_opp
= resp
->curr_level
;
192 } else if (strcmp(resp
->name
, "vdd2_opp") == 0) {
194 dpll3_clk
= clk_get(NULL
, "dpll3_m2_ck");
195 l3_clk
= clk_get(NULL
, "l3_ick");
196 resp
->curr_level
= get_opp(l3_opps
+ MAX_VDD2_OPP
,
198 curr_vdd2_opp
= resp
->curr_level
;
203 int resource_access_opp_lock(int res
, int delta
)
205 if (res
== VDD1_OPP
) {
208 } else if (res
== VDD2_OPP
) {
215 #ifndef CONFIG_CPU_FREQ
216 static unsigned long compute_lpj(unsigned long ref
, u_int div
, u_int mult
)
218 unsigned long new_jiffy_l
, new_jiffy_h
;
221 * Recalculate loops_per_jiffy. We do it this way to
222 * avoid math overflow on 32-bit machines. Maybe we
223 * should make this architecture dependent? If you have
224 * a better way of doing this, please replace!
226 * new = old * mult / div
228 new_jiffy_h
= ref
/ div
;
229 new_jiffy_l
= (ref
% div
) / 100;
231 new_jiffy_l
= new_jiffy_l
* mult
/ div
;
233 return new_jiffy_h
+ new_jiffy_l
* 100;
237 static int program_opp_freq(int res
, int target_level
, int current_level
)
242 if (res
== VDD1_OPP
) {
243 curr_opp
= &curr_vdd1_opp
;
244 clk_set_rate(dpll1_clk
, mpu_opps
[target_level
].rate
);
245 clk_set_rate(dpll2_clk
, dsp_opps
[target_level
].rate
);
246 #ifndef CONFIG_CPU_FREQ
247 /*Update loops_per_jiffy if processor speed is being changed*/
248 loops_per_jiffy
= compute_lpj(loops_per_jiffy
,
249 mpu_opps
[current_level
].rate
/1000,
250 mpu_opps
[target_level
].rate
/1000);
253 curr_opp
= &curr_vdd2_opp
;
254 l3_div
= cm_read_mod_reg(CORE_MOD
, CM_CLKSEL
) &
255 OMAP3430_CLKSEL_L3_MASK
;
256 ret
= clk_set_rate(dpll3_clk
,
257 l3_opps
[target_level
].rate
* l3_div
);
260 return current_level
;
262 omap3_save_scratchpad_contents();
264 *curr_opp
= target_level
;
268 static int program_opp(int res
, struct omap_opp
*opp
, int target_level
,
271 int i
, ret
= 0, raise
;
272 #ifdef CONFIG_OMAP_SMARTREFLEX
275 t_opp
= ID_VDD(res
) | ID_OPP_NO(opp
[target_level
].opp_id
);
277 if (target_level
> current_level
)
282 for (i
= 0; i
< 2; i
++) {
284 ret
= program_opp_freq(res
, target_level
,
286 #ifdef CONFIG_OMAP_SMARTREFLEX
288 sr_voltagescale_vcbypass(t_opp
,
289 opp
[target_level
].vsel
);
296 int resource_set_opp_level(int res
, u32 target_level
, int flags
)
298 unsigned long mpu_freq
, mpu_old_freq
;
299 #ifdef CONFIG_CPU_FREQ
300 struct cpufreq_freqs freqs_notify
;
302 struct shared_resource
*resp
;
306 else if (res
== VDD2_OPP
)
311 if (resp
->curr_level
== target_level
)
314 if (!mpu_opps
|| !dsp_opps
|| !l3_opps
)
317 mutex_lock(&dvfs_mutex
);
319 if (res
== VDD1_OPP
) {
320 if (flags
!= OPP_IGNORE_LOCK
&& vdd1_lock
) {
321 mutex_unlock(&dvfs_mutex
);
324 mpu_old_freq
= mpu_opps
[resp
->curr_level
].rate
;
325 mpu_freq
= mpu_opps
[target_level
].rate
;
327 #ifdef CONFIG_CPU_FREQ
328 freqs_notify
.old
= mpu_old_freq
/1000;
329 freqs_notify
.new = mpu_freq
/1000;
330 freqs_notify
.cpu
= 0;
331 /* Send pre notification to CPUFreq */
332 cpufreq_notify_transition(&freqs_notify
, CPUFREQ_PRECHANGE
);
334 resp
->curr_level
= program_opp(res
, mpu_opps
, target_level
,
336 #ifdef CONFIG_CPU_FREQ
337 /* Send a post notification to CPUFreq */
338 cpufreq_notify_transition(&freqs_notify
, CPUFREQ_POSTCHANGE
);
341 if (!(flags
& OPP_IGNORE_LOCK
) && vdd2_lock
) {
342 mutex_unlock(&dvfs_mutex
);
345 resp
->curr_level
= program_opp(res
, l3_opps
, target_level
,
348 mutex_unlock(&dvfs_mutex
);
352 int set_opp(struct shared_resource
*resp
, u32 target_level
)
355 unsigned long req_l3_freq
;
358 if (resp
== vdd1_resp
) {
359 if (target_level
< 3)
360 resource_release("vdd2_opp", &vdd2_dev
);
362 resource_set_opp_level(VDD1_OPP
, target_level
, 0);
364 * For VDD1 OPP3 and above, make sure the interconnect
365 * is at 100Mhz or above.
366 * throughput in KiB/s for 100 Mhz = 100 * 1000 * 4.
368 if (target_level
>= 3)
369 resource_request("vdd2_opp", &vdd2_dev
, 400000);
371 } else if (resp
== vdd2_resp
) {
374 /* Convert the tput in KiB/s to Bus frequency in MHz */
375 req_l3_freq
= (tput
* 1000)/4;
377 for (ind
= 2; ind
<= MAX_VDD2_OPP
; ind
++)
378 if ((l3_opps
+ ind
)->rate
>= req_l3_freq
) {
383 /* Set the highest OPP possible */
384 if (ind
> MAX_VDD2_OPP
)
385 target_level
= ind
-1;
386 resource_set_opp_level(VDD2_OPP
, target_level
, 0);
392 * validate_opp - Validates if valid VDD1 OPP's are passed as the
394 * VDD2 OPP levels are passed as L3 throughput, which are then mapped
395 * to an appropriate OPP.
397 int validate_opp(struct shared_resource
*resp
, u32 target_level
)
403 * init_freq - Initialize the frequency resource.
405 void init_freq(struct shared_resource
*resp
)
407 char *linked_res_name
;
408 resp
->no_of_users
= 0;
410 if (!mpu_opps
|| !dsp_opps
)
413 linked_res_name
= (char *)resp
->resource_data
;
414 /* Initialize the current level of the Freq resource
415 * to the frequency set by u-boot.
417 if (strcmp(resp
->name
, "mpu_freq") == 0)
418 /* MPU freq in Mhz */
419 resp
->curr_level
= mpu_opps
[curr_vdd1_opp
].rate
;
420 else if (strcmp(resp
->name
, "dsp_freq") == 0)
421 /* DSP freq in Mhz */
422 resp
->curr_level
= dsp_opps
[curr_vdd1_opp
].rate
;
426 int set_freq(struct shared_resource
*resp
, u32 target_level
)
428 unsigned int vdd1_opp
;
430 if (!mpu_opps
|| !dsp_opps
)
433 if (strcmp(resp
->name
, "mpu_freq") == 0) {
434 vdd1_opp
= get_opp(mpu_opps
+ MAX_VDD1_OPP
, target_level
);
435 resource_request("vdd1_opp", &dummy_mpu_dev
, vdd1_opp
);
436 } else if (strcmp(resp
->name
, "dsp_freq") == 0) {
437 vdd1_opp
= get_opp(dsp_opps
+ MAX_VDD1_OPP
, target_level
);
438 resource_request("vdd1_opp", &dummy_dsp_dev
, vdd1_opp
);
440 resp
->curr_level
= target_level
;
444 int validate_freq(struct shared_resource
*resp
, u32 target_level
)