diff options
-rw-r--r-- | arch/arm/mach-omap2/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-omap2/vc.c | 285 | ||||
-rw-r--r-- | arch/arm/mach-omap2/vc.h | 12 | ||||
-rw-r--r-- | arch/arm/mach-omap2/voltage.c | 264 |
4 files changed, 302 insertions, 261 deletions
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index cce9bc300af5..59db6d9ba244 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile | |||
@@ -90,7 +90,7 @@ obj-$(CONFIG_ARCH_OMAP4) += prcm.o cm2xxx_3xxx.o cminst44xx.o \ | |||
90 | 90 | ||
91 | # OMAP voltage domains | 91 | # OMAP voltage domains |
92 | ifeq ($(CONFIG_PM),y) | 92 | ifeq ($(CONFIG_PM),y) |
93 | voltagedomain-common := voltage.o | 93 | voltagedomain-common := voltage.o vc.o |
94 | obj-$(CONFIG_ARCH_OMAP2) += $(voltagedomain-common) \ | 94 | obj-$(CONFIG_ARCH_OMAP2) += $(voltagedomain-common) \ |
95 | voltagedomains2xxx_data.o | 95 | voltagedomains2xxx_data.o |
96 | obj-$(CONFIG_ARCH_OMAP3) += $(voltagedomain-common) \ | 96 | obj-$(CONFIG_ARCH_OMAP3) += $(voltagedomain-common) \ |
diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c new file mode 100644 index 000000000000..098af2f3a63e --- /dev/null +++ b/arch/arm/mach-omap2/vc.c | |||
@@ -0,0 +1,285 @@ | |||
1 | /* | ||
2 | * OMAP Voltage Controller (VC) interface | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments, Inc. | ||
5 | * | ||
6 | * This file is licensed under the terms of the GNU General Public | ||
7 | * License version 2. This program is licensed "as is" without any | ||
8 | * warranty of any kind, whether express or implied. | ||
9 | */ | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/delay.h> | ||
12 | #include <linux/init.h> | ||
13 | |||
14 | #include <plat/cpu.h> | ||
15 | |||
16 | #include "voltage.h" | ||
17 | #include "vc.h" | ||
18 | #include "prm-regbits-34xx.h" | ||
19 | #include "prm-regbits-44xx.h" | ||
20 | #include "prm44xx.h" | ||
21 | |||
22 | /* Voltage scale and accessory APIs */ | ||
23 | int omap_vc_pre_scale(struct voltagedomain *voltdm, | ||
24 | unsigned long target_volt, | ||
25 | u8 *target_vsel, u8 *current_vsel) | ||
26 | { | ||
27 | struct omap_vc_instance_data *vc = voltdm->vdd->vc_data; | ||
28 | struct omap_vdd_info *vdd = voltdm->vdd; | ||
29 | struct omap_volt_data *volt_data; | ||
30 | const struct omap_vc_common_data *vc_common; | ||
31 | const struct omap_vp_common_data *vp_common; | ||
32 | u32 vc_cmdval, vp_errgain_val; | ||
33 | |||
34 | vc_common = vc->vc_common; | ||
35 | vp_common = vdd->vp_data->vp_common; | ||
36 | |||
37 | /* Check if sufficient pmic info is available for this vdd */ | ||
38 | if (!vdd->pmic_info) { | ||
39 | pr_err("%s: Insufficient pmic info to scale the vdd_%s\n", | ||
40 | __func__, voltdm->name); | ||
41 | return -EINVAL; | ||
42 | } | ||
43 | |||
44 | if (!vdd->pmic_info->uv_to_vsel) { | ||
45 | pr_err("%s: PMIC function to convert voltage in uV to" | ||
46 | "vsel not registered. Hence unable to scale voltage" | ||
47 | "for vdd_%s\n", __func__, voltdm->name); | ||
48 | return -ENODATA; | ||
49 | } | ||
50 | |||
51 | if (!vdd->read_reg || !vdd->write_reg) { | ||
52 | pr_err("%s: No read/write API for accessing vdd_%s regs\n", | ||
53 | __func__, voltdm->name); | ||
54 | return -EINVAL; | ||
55 | } | ||
56 | |||
57 | /* Get volt_data corresponding to target_volt */ | ||
58 | volt_data = omap_voltage_get_voltdata(voltdm, target_volt); | ||
59 | if (IS_ERR(volt_data)) | ||
60 | volt_data = NULL; | ||
61 | |||
62 | *target_vsel = vdd->pmic_info->uv_to_vsel(target_volt); | ||
63 | *current_vsel = vdd->read_reg(vdd->vp_data->vp_common->prm_mod, vdd->vp_data->voltage); | ||
64 | |||
65 | /* Setting the ON voltage to the new target voltage */ | ||
66 | vc_cmdval = vdd->read_reg(vc->vc_common->prm_mod, vc->cmdval_reg); | ||
67 | vc_cmdval &= ~vc_common->cmd_on_mask; | ||
68 | vc_cmdval |= (*target_vsel << vc_common->cmd_on_shift); | ||
69 | vdd->write_reg(vc_cmdval, vc->vc_common->prm_mod, vc->cmdval_reg); | ||
70 | |||
71 | /* Setting vp errorgain based on the voltage */ | ||
72 | if (volt_data) { | ||
73 | vp_errgain_val = vdd->read_reg(vdd->vp_data->vp_common->prm_mod, | ||
74 | vdd->vp_data->vpconfig); | ||
75 | vdd->vp_rt_data.vpconfig_errorgain = volt_data->vp_errgain; | ||
76 | vp_errgain_val &= ~vp_common->vpconfig_errorgain_mask; | ||
77 | vp_errgain_val |= vdd->vp_rt_data.vpconfig_errorgain << | ||
78 | vp_common->vpconfig_errorgain_shift; | ||
79 | vdd->write_reg(vp_errgain_val, vdd->vp_data->vp_common->prm_mod, | ||
80 | vdd->vp_data->vpconfig); | ||
81 | } | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | void omap_vc_post_scale(struct voltagedomain *voltdm, | ||
87 | unsigned long target_volt, | ||
88 | u8 target_vsel, u8 current_vsel) | ||
89 | { | ||
90 | struct omap_vdd_info *vdd = voltdm->vdd; | ||
91 | u32 smps_steps = 0, smps_delay = 0; | ||
92 | |||
93 | smps_steps = abs(target_vsel - current_vsel); | ||
94 | /* SMPS slew rate / step size. 2us added as buffer. */ | ||
95 | smps_delay = ((smps_steps * vdd->pmic_info->step_size) / | ||
96 | vdd->pmic_info->slew_rate) + 2; | ||
97 | udelay(smps_delay); | ||
98 | |||
99 | vdd->curr_volt = target_volt; | ||
100 | } | ||
101 | |||
102 | /* vc_bypass_scale_voltage - VC bypass method of voltage scaling */ | ||
103 | int omap_vc_bypass_scale_voltage(struct voltagedomain *voltdm, | ||
104 | unsigned long target_volt) | ||
105 | { | ||
106 | struct omap_vc_instance_data *vc = voltdm->vdd->vc_data; | ||
107 | struct omap_vdd_info *vdd = voltdm->vdd; | ||
108 | u32 loop_cnt = 0, retries_cnt = 0; | ||
109 | u32 vc_valid, vc_bypass_val_reg, vc_bypass_value; | ||
110 | u8 target_vsel, current_vsel; | ||
111 | int ret; | ||
112 | |||
113 | ret = omap_vc_pre_scale(voltdm, target_volt, &target_vsel, ¤t_vsel); | ||
114 | if (ret) | ||
115 | return ret; | ||
116 | |||
117 | vc_valid = vc->vc_common->valid; | ||
118 | vc_bypass_val_reg = vc->vc_common->bypass_val_reg; | ||
119 | vc_bypass_value = (target_vsel << vc->vc_common->data_shift) | | ||
120 | (vdd->pmic_info->pmic_reg << | ||
121 | vc->vc_common->regaddr_shift) | | ||
122 | (vdd->pmic_info->i2c_slave_addr << | ||
123 | vc->vc_common->slaveaddr_shift); | ||
124 | |||
125 | vdd->write_reg(vc_bypass_value, vc->vc_common->prm_mod, vc_bypass_val_reg); | ||
126 | vdd->write_reg(vc_bypass_value | vc_valid, vc->vc_common->prm_mod, | ||
127 | vc_bypass_val_reg); | ||
128 | |||
129 | vc_bypass_value = vdd->read_reg(vc->vc_common->prm_mod, vc_bypass_val_reg); | ||
130 | /* | ||
131 | * Loop till the bypass command is acknowledged from the SMPS. | ||
132 | * NOTE: This is legacy code. The loop count and retry count needs | ||
133 | * to be revisited. | ||
134 | */ | ||
135 | while (!(vc_bypass_value & vc_valid)) { | ||
136 | loop_cnt++; | ||
137 | |||
138 | if (retries_cnt > 10) { | ||
139 | pr_warning("%s: Retry count exceeded\n", __func__); | ||
140 | return -ETIMEDOUT; | ||
141 | } | ||
142 | |||
143 | if (loop_cnt > 50) { | ||
144 | retries_cnt++; | ||
145 | loop_cnt = 0; | ||
146 | udelay(10); | ||
147 | } | ||
148 | vc_bypass_value = vdd->read_reg(vc->vc_common->prm_mod, | ||
149 | vc_bypass_val_reg); | ||
150 | } | ||
151 | |||
152 | omap_vc_post_scale(voltdm, target_volt, target_vsel, current_vsel); | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | static void __init omap3_vfsm_init(struct voltagedomain *voltdm) | ||
157 | { | ||
158 | struct omap_vc_instance_data *vc = voltdm->vdd->vc_data; | ||
159 | struct omap_vdd_info *vdd = voltdm->vdd; | ||
160 | |||
161 | /* | ||
162 | * Voltage Manager FSM parameters init | ||
163 | * XXX This data should be passed in from the board file | ||
164 | */ | ||
165 | vdd->write_reg(OMAP3_CLKSETUP, vc->vc_common->prm_mod, OMAP3_PRM_CLKSETUP_OFFSET); | ||
166 | vdd->write_reg(OMAP3_VOLTOFFSET, vc->vc_common->prm_mod, | ||
167 | OMAP3_PRM_VOLTOFFSET_OFFSET); | ||
168 | vdd->write_reg(OMAP3_VOLTSETUP2, vc->vc_common->prm_mod, | ||
169 | OMAP3_PRM_VOLTSETUP2_OFFSET); | ||
170 | } | ||
171 | |||
172 | static void __init omap3_vc_init_channel(struct voltagedomain *voltdm) | ||
173 | { | ||
174 | struct omap_vc_instance_data *vc = voltdm->vdd->vc_data; | ||
175 | struct omap_vdd_info *vdd = voltdm->vdd; | ||
176 | static bool is_initialized; | ||
177 | u8 on_vsel, onlp_vsel, ret_vsel, off_vsel; | ||
178 | u32 vc_val; | ||
179 | |||
180 | if (is_initialized) | ||
181 | return; | ||
182 | |||
183 | /* Set up the on, inactive, retention and off voltage */ | ||
184 | on_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->on_volt); | ||
185 | onlp_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->onlp_volt); | ||
186 | ret_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->ret_volt); | ||
187 | off_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->off_volt); | ||
188 | vc_val = ((on_vsel << vc->vc_common->cmd_on_shift) | | ||
189 | (onlp_vsel << vc->vc_common->cmd_onlp_shift) | | ||
190 | (ret_vsel << vc->vc_common->cmd_ret_shift) | | ||
191 | (off_vsel << vc->vc_common->cmd_off_shift)); | ||
192 | vdd->write_reg(vc_val, vc->vc_common->prm_mod, vc->cmdval_reg); | ||
193 | |||
194 | /* | ||
195 | * Generic VC parameters init | ||
196 | * XXX This data should be abstracted out | ||
197 | */ | ||
198 | vdd->write_reg(OMAP3430_CMD1_MASK | OMAP3430_RAV1_MASK, vc->vc_common->prm_mod, | ||
199 | OMAP3_PRM_VC_CH_CONF_OFFSET); | ||
200 | vdd->write_reg(OMAP3430_MCODE_SHIFT | OMAP3430_HSEN_MASK, vc->vc_common->prm_mod, | ||
201 | OMAP3_PRM_VC_I2C_CFG_OFFSET); | ||
202 | |||
203 | omap3_vfsm_init(voltdm); | ||
204 | |||
205 | is_initialized = true; | ||
206 | } | ||
207 | |||
208 | |||
209 | /* OMAP4 specific voltage init functions */ | ||
210 | static void __init omap4_vc_init_channel(struct voltagedomain *voltdm) | ||
211 | { | ||
212 | struct omap_vc_instance_data *vc = voltdm->vdd->vc_data; | ||
213 | struct omap_vdd_info *vdd = voltdm->vdd; | ||
214 | static bool is_initialized; | ||
215 | u32 vc_val; | ||
216 | |||
217 | if (is_initialized) | ||
218 | return; | ||
219 | |||
220 | /* TODO: Configure setup times and CMD_VAL values*/ | ||
221 | |||
222 | /* | ||
223 | * Generic VC parameters init | ||
224 | * XXX This data should be abstracted out | ||
225 | */ | ||
226 | vc_val = (OMAP4430_RAV_VDD_MPU_L_MASK | OMAP4430_CMD_VDD_MPU_L_MASK | | ||
227 | OMAP4430_RAV_VDD_IVA_L_MASK | OMAP4430_CMD_VDD_IVA_L_MASK | | ||
228 | OMAP4430_RAV_VDD_CORE_L_MASK | OMAP4430_CMD_VDD_CORE_L_MASK); | ||
229 | vdd->write_reg(vc_val, vc->vc_common->prm_mod, OMAP4_PRM_VC_CFG_CHANNEL_OFFSET); | ||
230 | |||
231 | /* XXX These are magic numbers and do not belong! */ | ||
232 | vc_val = (0x60 << OMAP4430_SCLL_SHIFT | 0x26 << OMAP4430_SCLH_SHIFT); | ||
233 | vdd->write_reg(vc_val, vc->vc_common->prm_mod, OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET); | ||
234 | |||
235 | is_initialized = true; | ||
236 | } | ||
237 | |||
238 | void __init omap_vc_init_channel(struct voltagedomain *voltdm) | ||
239 | { | ||
240 | struct omap_vc_instance_data *vc = voltdm->vdd->vc_data; | ||
241 | struct omap_vdd_info *vdd = voltdm->vdd; | ||
242 | u32 vc_val; | ||
243 | |||
244 | if (!vdd->pmic_info || !vdd->pmic_info->uv_to_vsel) { | ||
245 | pr_err("%s: PMIC info requried to configure vc for" | ||
246 | "vdd_%s not populated.Hence cannot initialize vc\n", | ||
247 | __func__, voltdm->name); | ||
248 | return; | ||
249 | } | ||
250 | |||
251 | if (!vdd->read_reg || !vdd->write_reg) { | ||
252 | pr_err("%s: No read/write API for accessing vdd_%s regs\n", | ||
253 | __func__, voltdm->name); | ||
254 | return; | ||
255 | } | ||
256 | |||
257 | /* Set up the SMPS_SA(i2c slave address in VC */ | ||
258 | vc_val = vdd->read_reg(vc->vc_common->prm_mod, | ||
259 | vc->vc_common->smps_sa_reg); | ||
260 | vc_val &= ~vc->smps_sa_mask; | ||
261 | vc_val |= vdd->pmic_info->i2c_slave_addr << vc->smps_sa_shift; | ||
262 | vdd->write_reg(vc_val, vc->vc_common->prm_mod, | ||
263 | vc->vc_common->smps_sa_reg); | ||
264 | |||
265 | /* Setup the VOLRA(pmic reg addr) in VC */ | ||
266 | vc_val = vdd->read_reg(vc->vc_common->prm_mod, | ||
267 | vc->vc_common->smps_volra_reg); | ||
268 | vc_val &= ~vc->smps_volra_mask; | ||
269 | vc_val |= vdd->pmic_info->pmic_reg << vc->smps_volra_shift; | ||
270 | vdd->write_reg(vc_val, vc->vc_common->prm_mod, | ||
271 | vc->vc_common->smps_volra_reg); | ||
272 | |||
273 | /* Configure the setup times */ | ||
274 | vc_val = vdd->read_reg(vc->vc_common->prm_mod, vdd->vfsm->voltsetup_reg); | ||
275 | vc_val &= ~vdd->vfsm->voltsetup_mask; | ||
276 | vc_val |= vdd->pmic_info->volt_setup_time << | ||
277 | vdd->vfsm->voltsetup_shift; | ||
278 | vdd->write_reg(vc_val, vc->vc_common->prm_mod, vdd->vfsm->voltsetup_reg); | ||
279 | |||
280 | if (cpu_is_omap34xx()) | ||
281 | omap3_vc_init_channel(voltdm); | ||
282 | else if (cpu_is_omap44xx()) | ||
283 | omap4_vc_init_channel(voltdm); | ||
284 | } | ||
285 | |||
diff --git a/arch/arm/mach-omap2/vc.h b/arch/arm/mach-omap2/vc.h index f7338af13d0b..d0bf34831c0b 100644 --- a/arch/arm/mach-omap2/vc.h +++ b/arch/arm/mach-omap2/vc.h | |||
@@ -19,6 +19,8 @@ | |||
19 | 19 | ||
20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
21 | 21 | ||
22 | struct voltagedomain; | ||
23 | |||
22 | /** | 24 | /** |
23 | * struct omap_vc_common_data - per-VC register/bitfield data | 25 | * struct omap_vc_common_data - per-VC register/bitfield data |
24 | * @cmd_on_mask: ON bitmask in PRM_VC_CMD_VAL* register | 26 | * @cmd_on_mask: ON bitmask in PRM_VC_CMD_VAL* register |
@@ -81,5 +83,15 @@ extern struct omap_vc_instance_data omap4_vc_mpu_data; | |||
81 | extern struct omap_vc_instance_data omap4_vc_iva_data; | 83 | extern struct omap_vc_instance_data omap4_vc_iva_data; |
82 | extern struct omap_vc_instance_data omap4_vc_core_data; | 84 | extern struct omap_vc_instance_data omap4_vc_core_data; |
83 | 85 | ||
86 | void omap_vc_init_channel(struct voltagedomain *voltdm); | ||
87 | int omap_vc_pre_scale(struct voltagedomain *voltdm, | ||
88 | unsigned long target_volt, | ||
89 | u8 *target_vsel, u8 *current_vsel); | ||
90 | void omap_vc_post_scale(struct voltagedomain *voltdm, | ||
91 | unsigned long target_volt, | ||
92 | u8 target_vsel, u8 current_vsel); | ||
93 | int omap_vc_bypass_scale_voltage(struct voltagedomain *voltdm, | ||
94 | unsigned long target_volt); | ||
95 | |||
84 | #endif | 96 | #endif |
85 | 97 | ||
diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c index 1e5c1225e2be..6ba6e493c757 100644 --- a/arch/arm/mach-omap2/voltage.c +++ b/arch/arm/mach-omap2/voltage.c | |||
@@ -293,136 +293,6 @@ static void __init vdd_debugfs_init(struct voltagedomain *voltdm) | |||
293 | &nom_volt_debug_fops); | 293 | &nom_volt_debug_fops); |
294 | } | 294 | } |
295 | 295 | ||
296 | /* Voltage scale and accessory APIs */ | ||
297 | static int _pre_volt_scale(struct voltagedomain *voltdm, | ||
298 | unsigned long target_volt, u8 *target_vsel, u8 *current_vsel) | ||
299 | { | ||
300 | struct omap_vdd_info *vdd = voltdm->vdd; | ||
301 | struct omap_volt_data *volt_data; | ||
302 | const struct omap_vc_common_data *vc_common; | ||
303 | const struct omap_vp_common_data *vp_common; | ||
304 | u32 vc_cmdval, vp_errgain_val; | ||
305 | |||
306 | vc_common = vdd->vc_data->vc_common; | ||
307 | vp_common = vdd->vp_data->vp_common; | ||
308 | |||
309 | /* Check if suffiecient pmic info is available for this vdd */ | ||
310 | if (!vdd->pmic_info) { | ||
311 | pr_err("%s: Insufficient pmic info to scale the vdd_%s\n", | ||
312 | __func__, voltdm->name); | ||
313 | return -EINVAL; | ||
314 | } | ||
315 | |||
316 | if (!vdd->pmic_info->uv_to_vsel) { | ||
317 | pr_err("%s: PMIC function to convert voltage in uV to" | ||
318 | "vsel not registered. Hence unable to scale voltage" | ||
319 | "for vdd_%s\n", __func__, voltdm->name); | ||
320 | return -ENODATA; | ||
321 | } | ||
322 | |||
323 | if (!vdd->read_reg || !vdd->write_reg) { | ||
324 | pr_err("%s: No read/write API for accessing vdd_%s regs\n", | ||
325 | __func__, voltdm->name); | ||
326 | return -EINVAL; | ||
327 | } | ||
328 | |||
329 | /* Get volt_data corresponding to target_volt */ | ||
330 | volt_data = omap_voltage_get_voltdata(voltdm, target_volt); | ||
331 | if (IS_ERR(volt_data)) | ||
332 | volt_data = NULL; | ||
333 | |||
334 | *target_vsel = vdd->pmic_info->uv_to_vsel(target_volt); | ||
335 | *current_vsel = vdd->read_reg(vdd->vp_data->vp_common->prm_mod, vdd->vp_data->voltage); | ||
336 | |||
337 | /* Setting the ON voltage to the new target voltage */ | ||
338 | vc_cmdval = vdd->read_reg(vdd->vc_data->vc_common->prm_mod, vdd->vc_data->cmdval_reg); | ||
339 | vc_cmdval &= ~vc_common->cmd_on_mask; | ||
340 | vc_cmdval |= (*target_vsel << vc_common->cmd_on_shift); | ||
341 | vdd->write_reg(vc_cmdval, vdd->vc_data->vc_common->prm_mod, vdd->vc_data->cmdval_reg); | ||
342 | |||
343 | /* Setting vp errorgain based on the voltage */ | ||
344 | if (volt_data) { | ||
345 | vp_errgain_val = vdd->read_reg(vdd->vp_data->vp_common->prm_mod, | ||
346 | vdd->vp_data->vpconfig); | ||
347 | vdd->vp_rt_data.vpconfig_errorgain = volt_data->vp_errgain; | ||
348 | vp_errgain_val &= ~vp_common->vpconfig_errorgain_mask; | ||
349 | vp_errgain_val |= vdd->vp_rt_data.vpconfig_errorgain << | ||
350 | vp_common->vpconfig_errorgain_shift; | ||
351 | vdd->write_reg(vp_errgain_val, vdd->vp_data->vp_common->prm_mod, | ||
352 | vdd->vp_data->vpconfig); | ||
353 | } | ||
354 | |||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | static void _post_volt_scale(struct voltagedomain *voltdm, | ||
359 | unsigned long target_volt, u8 target_vsel, u8 current_vsel) | ||
360 | { | ||
361 | struct omap_vdd_info *vdd = voltdm->vdd; | ||
362 | u32 smps_steps = 0, smps_delay = 0; | ||
363 | |||
364 | smps_steps = abs(target_vsel - current_vsel); | ||
365 | /* SMPS slew rate / step size. 2us added as buffer. */ | ||
366 | smps_delay = ((smps_steps * vdd->pmic_info->step_size) / | ||
367 | vdd->pmic_info->slew_rate) + 2; | ||
368 | udelay(smps_delay); | ||
369 | |||
370 | vdd->curr_volt = target_volt; | ||
371 | } | ||
372 | |||
373 | /* vc_bypass_scale_voltage - VC bypass method of voltage scaling */ | ||
374 | static int vc_bypass_scale_voltage(struct voltagedomain *voltdm, | ||
375 | unsigned long target_volt) | ||
376 | { | ||
377 | struct omap_vdd_info *vdd = voltdm->vdd; | ||
378 | u32 loop_cnt = 0, retries_cnt = 0; | ||
379 | u32 vc_valid, vc_bypass_val_reg, vc_bypass_value; | ||
380 | u8 target_vsel, current_vsel; | ||
381 | int ret; | ||
382 | |||
383 | ret = _pre_volt_scale(voltdm, target_volt, &target_vsel, ¤t_vsel); | ||
384 | if (ret) | ||
385 | return ret; | ||
386 | |||
387 | vc_valid = vdd->vc_data->vc_common->valid; | ||
388 | vc_bypass_val_reg = vdd->vc_data->vc_common->bypass_val_reg; | ||
389 | vc_bypass_value = (target_vsel << vdd->vc_data->vc_common->data_shift) | | ||
390 | (vdd->pmic_info->pmic_reg << | ||
391 | vdd->vc_data->vc_common->regaddr_shift) | | ||
392 | (vdd->pmic_info->i2c_slave_addr << | ||
393 | vdd->vc_data->vc_common->slaveaddr_shift); | ||
394 | |||
395 | vdd->write_reg(vc_bypass_value, vdd->vc_data->vc_common->prm_mod, vc_bypass_val_reg); | ||
396 | vdd->write_reg(vc_bypass_value | vc_valid, vdd->vc_data->vc_common->prm_mod, | ||
397 | vc_bypass_val_reg); | ||
398 | |||
399 | vc_bypass_value = vdd->read_reg(vdd->vc_data->vc_common->prm_mod, vc_bypass_val_reg); | ||
400 | /* | ||
401 | * Loop till the bypass command is acknowledged from the SMPS. | ||
402 | * NOTE: This is legacy code. The loop count and retry count needs | ||
403 | * to be revisited. | ||
404 | */ | ||
405 | while (!(vc_bypass_value & vc_valid)) { | ||
406 | loop_cnt++; | ||
407 | |||
408 | if (retries_cnt > 10) { | ||
409 | pr_warning("%s: Retry count exceeded\n", __func__); | ||
410 | return -ETIMEDOUT; | ||
411 | } | ||
412 | |||
413 | if (loop_cnt > 50) { | ||
414 | retries_cnt++; | ||
415 | loop_cnt = 0; | ||
416 | udelay(10); | ||
417 | } | ||
418 | vc_bypass_value = vdd->read_reg(vdd->vc_data->vc_common->prm_mod, | ||
419 | vc_bypass_val_reg); | ||
420 | } | ||
421 | |||
422 | _post_volt_scale(voltdm, target_volt, target_vsel, current_vsel); | ||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | /* VP force update method of voltage scaling */ | 296 | /* VP force update method of voltage scaling */ |
427 | static int vp_forceupdate_scale_voltage(struct voltagedomain *voltdm, | 297 | static int vp_forceupdate_scale_voltage(struct voltagedomain *voltdm, |
428 | unsigned long target_volt) | 298 | unsigned long target_volt) |
@@ -432,7 +302,7 @@ static int vp_forceupdate_scale_voltage(struct voltagedomain *voltdm, | |||
432 | u8 target_vsel, current_vsel; | 302 | u8 target_vsel, current_vsel; |
433 | int ret, timeout = 0; | 303 | int ret, timeout = 0; |
434 | 304 | ||
435 | ret = _pre_volt_scale(voltdm, target_volt, &target_vsel, ¤t_vsel); | 305 | ret = omap_vc_pre_scale(voltdm, target_volt, &target_vsel, ¤t_vsel); |
436 | if (ret) | 306 | if (ret) |
437 | return ret; | 307 | return ret; |
438 | 308 | ||
@@ -485,7 +355,7 @@ static int vp_forceupdate_scale_voltage(struct voltagedomain *voltdm, | |||
485 | "TRANXDONE never got set after the voltage update\n", | 355 | "TRANXDONE never got set after the voltage update\n", |
486 | __func__, voltdm->name); | 356 | __func__, voltdm->name); |
487 | 357 | ||
488 | _post_volt_scale(voltdm, target_volt, target_vsel, current_vsel); | 358 | omap_vc_post_scale(voltdm, target_volt, target_vsel, current_vsel); |
489 | 359 | ||
490 | /* | 360 | /* |
491 | * Disable TransactionDone interrupt , clear all status, clear | 361 | * Disable TransactionDone interrupt , clear all status, clear |
@@ -517,132 +387,6 @@ static int vp_forceupdate_scale_voltage(struct voltagedomain *voltdm, | |||
517 | return 0; | 387 | return 0; |
518 | } | 388 | } |
519 | 389 | ||
520 | static void __init omap3_vfsm_init(struct voltagedomain *voltdm) | ||
521 | { | ||
522 | struct omap_vdd_info *vdd = voltdm->vdd; | ||
523 | |||
524 | /* | ||
525 | * Voltage Manager FSM parameters init | ||
526 | * XXX This data should be passed in from the board file | ||
527 | */ | ||
528 | vdd->write_reg(OMAP3_CLKSETUP, vdd->vc_data->vc_common->prm_mod, OMAP3_PRM_CLKSETUP_OFFSET); | ||
529 | vdd->write_reg(OMAP3_VOLTOFFSET, vdd->vc_data->vc_common->prm_mod, | ||
530 | OMAP3_PRM_VOLTOFFSET_OFFSET); | ||
531 | vdd->write_reg(OMAP3_VOLTSETUP2, vdd->vc_data->vc_common->prm_mod, | ||
532 | OMAP3_PRM_VOLTSETUP2_OFFSET); | ||
533 | } | ||
534 | |||
535 | static void __init omap3_vc_init(struct voltagedomain *voltdm) | ||
536 | { | ||
537 | struct omap_vdd_info *vdd = voltdm->vdd; | ||
538 | static bool is_initialized; | ||
539 | u8 on_vsel, onlp_vsel, ret_vsel, off_vsel; | ||
540 | u32 vc_val; | ||
541 | |||
542 | if (is_initialized) | ||
543 | return; | ||
544 | |||
545 | /* Set up the on, inactive, retention and off voltage */ | ||
546 | on_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->on_volt); | ||
547 | onlp_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->onlp_volt); | ||
548 | ret_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->ret_volt); | ||
549 | off_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->off_volt); | ||
550 | vc_val = ((on_vsel << vdd->vc_data->vc_common->cmd_on_shift) | | ||
551 | (onlp_vsel << vdd->vc_data->vc_common->cmd_onlp_shift) | | ||
552 | (ret_vsel << vdd->vc_data->vc_common->cmd_ret_shift) | | ||
553 | (off_vsel << vdd->vc_data->vc_common->cmd_off_shift)); | ||
554 | vdd->write_reg(vc_val, vdd->vc_data->vc_common->prm_mod, vdd->vc_data->cmdval_reg); | ||
555 | |||
556 | /* | ||
557 | * Generic VC parameters init | ||
558 | * XXX This data should be abstracted out | ||
559 | */ | ||
560 | vdd->write_reg(OMAP3430_CMD1_MASK | OMAP3430_RAV1_MASK, vdd->vc_data->vc_common->prm_mod, | ||
561 | OMAP3_PRM_VC_CH_CONF_OFFSET); | ||
562 | vdd->write_reg(OMAP3430_MCODE_SHIFT | OMAP3430_HSEN_MASK, vdd->vc_data->vc_common->prm_mod, | ||
563 | OMAP3_PRM_VC_I2C_CFG_OFFSET); | ||
564 | |||
565 | omap3_vfsm_init(voltdm); | ||
566 | |||
567 | is_initialized = true; | ||
568 | } | ||
569 | |||
570 | |||
571 | /* OMAP4 specific voltage init functions */ | ||
572 | static void __init omap4_vc_init(struct voltagedomain *voltdm) | ||
573 | { | ||
574 | struct omap_vdd_info *vdd = voltdm->vdd; | ||
575 | static bool is_initialized; | ||
576 | u32 vc_val; | ||
577 | |||
578 | if (is_initialized) | ||
579 | return; | ||
580 | |||
581 | /* TODO: Configure setup times and CMD_VAL values*/ | ||
582 | |||
583 | /* | ||
584 | * Generic VC parameters init | ||
585 | * XXX This data should be abstracted out | ||
586 | */ | ||
587 | vc_val = (OMAP4430_RAV_VDD_MPU_L_MASK | OMAP4430_CMD_VDD_MPU_L_MASK | | ||
588 | OMAP4430_RAV_VDD_IVA_L_MASK | OMAP4430_CMD_VDD_IVA_L_MASK | | ||
589 | OMAP4430_RAV_VDD_CORE_L_MASK | OMAP4430_CMD_VDD_CORE_L_MASK); | ||
590 | vdd->write_reg(vc_val, vdd->vc_data->vc_common->prm_mod, OMAP4_PRM_VC_CFG_CHANNEL_OFFSET); | ||
591 | |||
592 | /* XXX These are magic numbers and do not belong! */ | ||
593 | vc_val = (0x60 << OMAP4430_SCLL_SHIFT | 0x26 << OMAP4430_SCLH_SHIFT); | ||
594 | vdd->write_reg(vc_val, vdd->vc_data->vc_common->prm_mod, OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET); | ||
595 | |||
596 | is_initialized = true; | ||
597 | } | ||
598 | |||
599 | static void __init omap_vc_init(struct voltagedomain *voltdm) | ||
600 | { | ||
601 | struct omap_vdd_info *vdd = voltdm->vdd; | ||
602 | u32 vc_val; | ||
603 | |||
604 | if (!vdd->pmic_info || !vdd->pmic_info->uv_to_vsel) { | ||
605 | pr_err("%s: PMIC info requried to configure vc for" | ||
606 | "vdd_%s not populated.Hence cannot initialize vc\n", | ||
607 | __func__, voltdm->name); | ||
608 | return; | ||
609 | } | ||
610 | |||
611 | if (!vdd->read_reg || !vdd->write_reg) { | ||
612 | pr_err("%s: No read/write API for accessing vdd_%s regs\n", | ||
613 | __func__, voltdm->name); | ||
614 | return; | ||
615 | } | ||
616 | |||
617 | /* Set up the SMPS_SA(i2c slave address in VC */ | ||
618 | vc_val = vdd->read_reg(vdd->vc_data->vc_common->prm_mod, | ||
619 | vdd->vc_data->vc_common->smps_sa_reg); | ||
620 | vc_val &= ~vdd->vc_data->smps_sa_mask; | ||
621 | vc_val |= vdd->pmic_info->i2c_slave_addr << vdd->vc_data->smps_sa_shift; | ||
622 | vdd->write_reg(vc_val, vdd->vc_data->vc_common->prm_mod, | ||
623 | vdd->vc_data->vc_common->smps_sa_reg); | ||
624 | |||
625 | /* Setup the VOLRA(pmic reg addr) in VC */ | ||
626 | vc_val = vdd->read_reg(vdd->vc_data->vc_common->prm_mod, | ||
627 | vdd->vc_data->vc_common->smps_volra_reg); | ||
628 | vc_val &= ~vdd->vc_data->smps_volra_mask; | ||
629 | vc_val |= vdd->pmic_info->pmic_reg << vdd->vc_data->smps_volra_shift; | ||
630 | vdd->write_reg(vc_val, vdd->vc_data->vc_common->prm_mod, | ||
631 | vdd->vc_data->vc_common->smps_volra_reg); | ||
632 | |||
633 | /* Configure the setup times */ | ||
634 | vc_val = vdd->read_reg(vdd->vc_data->vc_common->prm_mod, vdd->vfsm->voltsetup_reg); | ||
635 | vc_val &= ~vdd->vfsm->voltsetup_mask; | ||
636 | vc_val |= vdd->pmic_info->volt_setup_time << | ||
637 | vdd->vfsm->voltsetup_shift; | ||
638 | vdd->write_reg(vc_val, vdd->vc_data->vc_common->prm_mod, vdd->vfsm->voltsetup_reg); | ||
639 | |||
640 | if (cpu_is_omap34xx()) | ||
641 | omap3_vc_init(voltdm); | ||
642 | else if (cpu_is_omap44xx()) | ||
643 | omap4_vc_init(voltdm); | ||
644 | } | ||
645 | |||
646 | static int __init omap_vdd_data_configure(struct voltagedomain *voltdm) | 390 | static int __init omap_vdd_data_configure(struct voltagedomain *voltdm) |
647 | { | 391 | { |
648 | struct omap_vdd_info *vdd = voltdm->vdd; | 392 | struct omap_vdd_info *vdd = voltdm->vdd; |
@@ -1025,7 +769,7 @@ void omap_change_voltscale_method(struct voltagedomain *voltdm, | |||
1025 | vdd->volt_scale = vp_forceupdate_scale_voltage; | 769 | vdd->volt_scale = vp_forceupdate_scale_voltage; |
1026 | return; | 770 | return; |
1027 | case VOLTSCALE_VCBYPASS: | 771 | case VOLTSCALE_VCBYPASS: |
1028 | vdd->volt_scale = vc_bypass_scale_voltage; | 772 | vdd->volt_scale = omap_vc_bypass_scale_voltage; |
1029 | return; | 773 | return; |
1030 | default: | 774 | default: |
1031 | pr_warning("%s: Trying to change the method of voltage scaling" | 775 | pr_warning("%s: Trying to change the method of voltage scaling" |
@@ -1061,7 +805,7 @@ int __init omap_voltage_late_init(void) | |||
1061 | if (voltdm->vdd) { | 805 | if (voltdm->vdd) { |
1062 | if (omap_vdd_data_configure(voltdm)) | 806 | if (omap_vdd_data_configure(voltdm)) |
1063 | continue; | 807 | continue; |
1064 | omap_vc_init(voltdm); | 808 | omap_vc_init_channel(voltdm); |
1065 | vp_init(voltdm); | 809 | vp_init(voltdm); |
1066 | vdd_debugfs_init(voltdm); | 810 | vdd_debugfs_init(voltdm); |
1067 | } | 811 | } |