OMAP3 SRF: Voltage scaling support
[linux-ginger.git] / arch / arm / mach-omap2 / resource34xx.c
blob0eecf3bab7a19ca5c4ec46e57ebed2d797ab3abe
1 /*
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.
15 * History:
19 #include <linux/pm_qos_params.h>
21 #include <plat/powerdomain.h>
22 #include <plat/clockdomain.h>
24 #include "smartreflex.h"
25 #include "resource34xx.h"
26 #include "pm.h"
28 /**
29 * init_latency - Initializes the mpu/core latency resource.
30 * @resp: Latency resource to be initalized
32 * No return value.
34 void init_latency(struct shared_resource *resp)
36 resp->no_of_users = 0;
37 resp->curr_level = RES_DEFAULTLEVEL;
38 *((u8 *)resp->resource_data) = 0;
39 return;
42 /**
43 * set_latency - Adds/Updates and removes the CPU_DMA_LATENCY in *pm_qos_params.
44 * @resp: resource pointer
45 * @latency: target latency to be set
47 * Returns 0 on success, or error values as returned by
48 * pm_qos_update_requirement/pm_qos_add_requirement.
50 int set_latency(struct shared_resource *resp, u32 latency)
52 u8 *pm_qos_req_added;
54 if (resp->curr_level == latency)
55 return 0;
56 else
57 /* Update the resources current level */
58 resp->curr_level = latency;
60 pm_qos_req_added = resp->resource_data;
61 if (latency == RES_DEFAULTLEVEL)
62 /* No more users left, remove the pm_qos_req if present */
63 if (*pm_qos_req_added) {
64 pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY,
65 resp->name);
66 *pm_qos_req_added = 0;
67 return 0;
70 if (*pm_qos_req_added) {
71 return pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY,
72 resp->name, latency);
73 } else {
74 *pm_qos_req_added = 1;
75 return pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY,
76 resp->name, latency);
80 /**
81 * init_pd_latency - Initializes the power domain latency resource.
82 * @resp: Power Domain Latency resource to be initialized.
84 * No return value.
86 void init_pd_latency(struct shared_resource *resp)
88 struct pd_latency_db *pd_lat_db;
90 resp->no_of_users = 0;
91 if (enable_off_mode)
92 resp->curr_level = PD_LATENCY_OFF;
93 else
94 resp->curr_level = PD_LATENCY_RET;
95 pd_lat_db = resp->resource_data;
96 /* Populate the power domain associated with the latency resource */
97 pd_lat_db->pd = pwrdm_lookup(pd_lat_db->pwrdm_name);
98 set_pwrdm_state(pd_lat_db->pd, resp->curr_level);
99 return;
103 * set_pd_latency - Updates the curr_level of the power domain resource.
104 * @resp: Power domain latency resource.
105 * @latency: New latency value acceptable.
107 * This function maps the latency in microsecs to the acceptable
108 * Power domain state using the latency DB.
109 * It then programs the power domain to enter the target state.
110 * Always returns 0.
112 int set_pd_latency(struct shared_resource *resp, u32 latency)
114 u32 pd_lat_level, ind;
115 struct pd_latency_db *pd_lat_db;
116 struct powerdomain *pwrdm;
118 pd_lat_db = resp->resource_data;
119 pwrdm = pd_lat_db->pd;
120 pd_lat_level = PD_LATENCY_OFF;
121 /* using the latency db map to the appropriate PD state */
122 for (ind = 0; ind < PD_LATENCY_MAXLEVEL; ind++) {
123 if (pd_lat_db->latency[ind] < latency) {
124 pd_lat_level = ind;
125 break;
129 if (!enable_off_mode && pd_lat_level == PD_LATENCY_OFF)
130 pd_lat_level = PD_LATENCY_RET;
132 resp->curr_level = pd_lat_level;
133 set_pwrdm_state(pwrdm, pd_lat_level);
134 return 0;
137 static struct clk *vdd1_clk;
138 static struct clk *vdd2_clk;
139 static struct device dummy_srf_dev;
142 * init_opp - Initialize the OPP resource
144 void init_opp(struct shared_resource *resp)
146 resp->no_of_users = 0;
147 /* Initialize the current level of the OPP resource
148 * to the opp set by u-boot.
150 if (strcmp(resp->name, "vdd1_opp") == 0) {
151 resp->curr_level = curr_vdd1_prcm_set->opp_id;
152 vdd1_clk = clk_get(NULL, "virt_vdd1_prcm_set");
153 } else if (strcmp(resp->name, "vdd2_opp") == 0) {
154 resp->curr_level = curr_vdd2_prcm_set->opp_id;
155 vdd2_clk = clk_get(NULL, "virt_vdd2_prcm_set");
157 return;
160 int set_opp(struct shared_resource *resp, u32 target_level)
162 unsigned long mpu_freq;
164 if (resp->curr_level == target_level)
165 return 0;
167 if (strcmp(resp->name, "vdd1_opp") == 0) {
168 mpu_freq = get_freq(mpu_opps + MAX_VDD1_OPP,
169 target_level);
170 if (resp->curr_level > target_level) {
171 /* Scale Frequency and then voltage */
172 clk_set_rate(vdd1_clk, mpu_freq);
173 sr_voltagescale_vcbypass(PRCM_VDD1,
174 mpu_opps[target_level-1].vsel);
175 } else {
176 /* Scale Voltage and then frequency */
177 sr_voltagescale_vcbypass(PRCM_VDD1,
178 mpu_opps[target_level-1].vsel);
179 clk_set_rate(vdd1_clk, mpu_freq);
181 resp->curr_level = curr_vdd1_prcm_set->opp_id;
182 } else if (strcmp(resp->name, "vdd2_opp") == 0) {
183 /* Not supported yet */
185 return 0;
189 * validate_opp - Validates if valid VDD1 OPP's are passed as the
190 * target_level.
191 * VDD2 OPP levels are passed as L3 throughput, which are then mapped
192 * to an appropriate OPP.
194 int validate_opp(struct shared_resource *resp, u32 target_level)
196 return 0;
200 * init_freq - Initialize the frequency resource.
202 void init_freq(struct shared_resource *resp)
204 char *linked_res_name;
205 resp->no_of_users = 0;
207 linked_res_name = (char *)resp->resource_data;
208 /* Initialize the current level of the Freq resource
209 * to the frequency set by u-boot.
211 if (strcmp(resp->name, "mpu_freq") == 0)
212 /* MPU freq in Mhz */
213 resp->curr_level = curr_vdd1_prcm_set->rate;
214 else if (strcmp(resp->name, "dsp_freq") == 0)
215 /* DSP freq in Mhz */
216 resp->curr_level = get_freq(dsp_opps + MAX_VDD2_OPP,
217 curr_vdd1_prcm_set->opp_id);
218 return;
221 int set_freq(struct shared_resource *resp, u32 target_level)
223 unsigned int vdd1_opp;
225 if (strcmp(resp->name, "mpu_freq") == 0)
226 vdd1_opp = get_opp(mpu_opps + MAX_VDD1_OPP, target_level);
227 else if (strcmp(resp->name, "dsp_freq") == 0)
228 vdd1_opp = get_opp(dsp_opps + MAX_VDD1_OPP, target_level);
230 if (vdd1_opp == MIN_VDD1_OPP)
231 resource_release("vdd1_opp", &dummy_srf_dev);
232 else
233 resource_request("vdd1_opp", &dummy_srf_dev, vdd1_opp);
235 resp->curr_level = target_level;
236 return 0;
239 int validate_freq(struct shared_resource *resp, u32 target_level)
241 return 0;