xref: /linux/arch/arm/mach-omap2/vp.c (revision f2ee442115c9b6219083c019939a9cc0c9abb2f8)
1 #include <linux/kernel.h>
2 #include <linux/init.h>
3 
4 #include <plat/common.h>
5 
6 #include "voltage.h"
7 #include "vp.h"
8 #include "prm-regbits-34xx.h"
9 #include "prm-regbits-44xx.h"
10 #include "prm44xx.h"
11 
12 static u32 _vp_set_init_voltage(struct voltagedomain *voltdm, u32 volt)
13 {
14 	struct omap_vp_instance *vp = voltdm->vp;
15 	u32 vpconfig;
16 	char vsel;
17 
18 	vsel = voltdm->pmic->uv_to_vsel(volt);
19 
20 	vpconfig = voltdm->read(vp->vpconfig);
21 	vpconfig &= ~(vp->common->vpconfig_initvoltage_mask |
22 		      vp->common->vpconfig_forceupdate |
23 		      vp->common->vpconfig_initvdd);
24 	vpconfig |= vsel << __ffs(vp->common->vpconfig_initvoltage_mask);
25 	voltdm->write(vpconfig, vp->vpconfig);
26 
27 	/* Trigger initVDD value copy to voltage processor */
28 	voltdm->write((vpconfig | vp->common->vpconfig_initvdd),
29 		       vp->vpconfig);
30 
31 	/* Clear initVDD copy trigger bit */
32 	voltdm->write(vpconfig, vp->vpconfig);
33 
34 	return vpconfig;
35 }
36 
37 /* Generic voltage init functions */
38 void __init omap_vp_init(struct voltagedomain *voltdm)
39 {
40 	struct omap_vp_instance *vp = voltdm->vp;
41 	u32 val, sys_clk_rate, timeout, waittime;
42 	u32 vddmin, vddmax, vstepmin, vstepmax;
43 
44 	if (!voltdm->read || !voltdm->write) {
45 		pr_err("%s: No read/write API for accessing vdd_%s regs\n",
46 			__func__, voltdm->name);
47 		return;
48 	}
49 
50 	vp->enabled = false;
51 
52 	/* Divide to avoid overflow */
53 	sys_clk_rate = voltdm->sys_clk.rate / 1000;
54 
55 	timeout = (sys_clk_rate * voltdm->pmic->vp_timeout_us) / 1000;
56 	vddmin = voltdm->pmic->vp_vddmin;
57 	vddmax = voltdm->pmic->vp_vddmax;
58 
59 	waittime = ((voltdm->pmic->step_size / voltdm->pmic->slew_rate) *
60 		    sys_clk_rate) / 1000;
61 	vstepmin = voltdm->pmic->vp_vstepmin;
62 	vstepmax = voltdm->pmic->vp_vstepmax;
63 
64 	/*
65 	 * VP_CONFIG: error gain is not set here, it will be updated
66 	 * on each scale, based on OPP.
67 	 */
68 	val = (voltdm->pmic->vp_erroroffset <<
69 	       __ffs(voltdm->vp->common->vpconfig_erroroffset_mask)) |
70 		vp->common->vpconfig_timeouten;
71 	voltdm->write(val, vp->vpconfig);
72 
73 	/* VSTEPMIN */
74 	val = (waittime << vp->common->vstepmin_smpswaittimemin_shift) |
75 		(vstepmin <<  vp->common->vstepmin_stepmin_shift);
76 	voltdm->write(val, vp->vstepmin);
77 
78 	/* VSTEPMAX */
79 	val = (vstepmax << vp->common->vstepmax_stepmax_shift) |
80 		(waittime << vp->common->vstepmax_smpswaittimemax_shift);
81 	voltdm->write(val, vp->vstepmax);
82 
83 	/* VLIMITTO */
84 	val = (vddmax << vp->common->vlimitto_vddmax_shift) |
85 		(vddmin << vp->common->vlimitto_vddmin_shift) |
86 		(timeout <<  vp->common->vlimitto_timeout_shift);
87 	voltdm->write(val, vp->vlimitto);
88 }
89 
90 int omap_vp_update_errorgain(struct voltagedomain *voltdm,
91 			     unsigned long target_volt)
92 {
93 	struct omap_volt_data *volt_data;
94 
95 	if (!voltdm->vp)
96 		return -EINVAL;
97 
98 	/* Get volt_data corresponding to target_volt */
99 	volt_data = omap_voltage_get_voltdata(voltdm, target_volt);
100 	if (IS_ERR(volt_data))
101 		return -EINVAL;
102 
103 	/* Setting vp errorgain based on the voltage */
104 	voltdm->rmw(voltdm->vp->common->vpconfig_errorgain_mask,
105 		    volt_data->vp_errgain <<
106 		    __ffs(voltdm->vp->common->vpconfig_errorgain_mask),
107 		    voltdm->vp->vpconfig);
108 
109 	return 0;
110 }
111 
112 /* VP force update method of voltage scaling */
113 int omap_vp_forceupdate_scale(struct voltagedomain *voltdm,
114 			      unsigned long target_volt)
115 {
116 	struct omap_vp_instance *vp = voltdm->vp;
117 	u32 vpconfig;
118 	u8 target_vsel, current_vsel;
119 	int ret, timeout = 0;
120 
121 	ret = omap_vc_pre_scale(voltdm, target_volt, &target_vsel, &current_vsel);
122 	if (ret)
123 		return ret;
124 
125 	/*
126 	 * Clear all pending TransactionDone interrupt/status. Typical latency
127 	 * is <3us
128 	 */
129 	while (timeout++ < VP_TRANXDONE_TIMEOUT) {
130 		vp->common->ops->clear_txdone(vp->id);
131 		if (!vp->common->ops->check_txdone(vp->id))
132 			break;
133 		udelay(1);
134 	}
135 	if (timeout >= VP_TRANXDONE_TIMEOUT) {
136 		pr_warning("%s: vdd_%s TRANXDONE timeout exceeded."
137 			"Voltage change aborted", __func__, voltdm->name);
138 		return -ETIMEDOUT;
139 	}
140 
141 	vpconfig = _vp_set_init_voltage(voltdm, target_volt);
142 
143 	/* Force update of voltage */
144 	voltdm->write(vpconfig | vp->common->vpconfig_forceupdate,
145 		      voltdm->vp->vpconfig);
146 
147 	/*
148 	 * Wait for TransactionDone. Typical latency is <200us.
149 	 * Depends on SMPSWAITTIMEMIN/MAX and voltage change
150 	 */
151 	timeout = 0;
152 	omap_test_timeout(vp->common->ops->check_txdone(vp->id),
153 			  VP_TRANXDONE_TIMEOUT, timeout);
154 	if (timeout >= VP_TRANXDONE_TIMEOUT)
155 		pr_err("%s: vdd_%s TRANXDONE timeout exceeded."
156 			"TRANXDONE never got set after the voltage update\n",
157 			__func__, voltdm->name);
158 
159 	omap_vc_post_scale(voltdm, target_volt, target_vsel, current_vsel);
160 
161 	/*
162 	 * Disable TransactionDone interrupt , clear all status, clear
163 	 * control registers
164 	 */
165 	timeout = 0;
166 	while (timeout++ < VP_TRANXDONE_TIMEOUT) {
167 		vp->common->ops->clear_txdone(vp->id);
168 		if (!vp->common->ops->check_txdone(vp->id))
169 			break;
170 		udelay(1);
171 	}
172 
173 	if (timeout >= VP_TRANXDONE_TIMEOUT)
174 		pr_warning("%s: vdd_%s TRANXDONE timeout exceeded while trying"
175 			"to clear the TRANXDONE status\n",
176 			__func__, voltdm->name);
177 
178 	/* Clear force bit */
179 	voltdm->write(vpconfig, vp->vpconfig);
180 
181 	return 0;
182 }
183 
184 /**
185  * omap_vp_enable() - API to enable a particular VP
186  * @voltdm:	pointer to the VDD whose VP is to be enabled.
187  *
188  * This API enables a particular voltage processor. Needed by the smartreflex
189  * class drivers.
190  */
191 void omap_vp_enable(struct voltagedomain *voltdm)
192 {
193 	struct omap_vp_instance *vp;
194 	u32 vpconfig, volt;
195 
196 	if (!voltdm || IS_ERR(voltdm)) {
197 		pr_warning("%s: VDD specified does not exist!\n", __func__);
198 		return;
199 	}
200 
201 	vp = voltdm->vp;
202 	if (!voltdm->read || !voltdm->write) {
203 		pr_err("%s: No read/write API for accessing vdd_%s regs\n",
204 			__func__, voltdm->name);
205 		return;
206 	}
207 
208 	/* If VP is already enabled, do nothing. Return */
209 	if (vp->enabled)
210 		return;
211 
212 	volt = voltdm_get_voltage(voltdm);
213 	if (!volt) {
214 		pr_warning("%s: unable to find current voltage for %s\n",
215 			   __func__, voltdm->name);
216 		return;
217 	}
218 
219 	vpconfig = _vp_set_init_voltage(voltdm, volt);
220 
221 	/* Enable VP */
222 	vpconfig |= vp->common->vpconfig_vpenable;
223 	voltdm->write(vpconfig, vp->vpconfig);
224 
225 	vp->enabled = true;
226 }
227 
228 /**
229  * omap_vp_disable() - API to disable a particular VP
230  * @voltdm:	pointer to the VDD whose VP is to be disabled.
231  *
232  * This API disables a particular voltage processor. Needed by the smartreflex
233  * class drivers.
234  */
235 void omap_vp_disable(struct voltagedomain *voltdm)
236 {
237 	struct omap_vp_instance *vp;
238 	u32 vpconfig;
239 	int timeout;
240 
241 	if (!voltdm || IS_ERR(voltdm)) {
242 		pr_warning("%s: VDD specified does not exist!\n", __func__);
243 		return;
244 	}
245 
246 	vp = voltdm->vp;
247 	if (!voltdm->read || !voltdm->write) {
248 		pr_err("%s: No read/write API for accessing vdd_%s regs\n",
249 			__func__, voltdm->name);
250 		return;
251 	}
252 
253 	/* If VP is already disabled, do nothing. Return */
254 	if (!vp->enabled) {
255 		pr_warning("%s: Trying to disable VP for vdd_%s when"
256 			"it is already disabled\n", __func__, voltdm->name);
257 		return;
258 	}
259 
260 	/* Disable VP */
261 	vpconfig = voltdm->read(vp->vpconfig);
262 	vpconfig &= ~vp->common->vpconfig_vpenable;
263 	voltdm->write(vpconfig, vp->vpconfig);
264 
265 	/*
266 	 * Wait for VP idle Typical latency is <2us. Maximum latency is ~100us
267 	 */
268 	omap_test_timeout((voltdm->read(vp->vstatus)),
269 			  VP_IDLE_TIMEOUT, timeout);
270 
271 	if (timeout >= VP_IDLE_TIMEOUT)
272 		pr_warning("%s: vdd_%s idle timedout\n",
273 			__func__, voltdm->name);
274 
275 	vp->enabled = false;
276 
277 	return;
278 }
279