aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/vc.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-06-02 19:15:12 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-06-02 19:15:12 -0400
commit825f4e0271b0de3f7f31d963dcdaa0056fe9b73a (patch)
treeaef1f198da011a96fefbe9851137ca17afd929a4 /arch/arm/mach-omap2/vc.c
parent0a58471541cc823ef8056d23945c39fec154481c (diff)
parentb5b9324a6296bd0176fe1f8e06a1220207bd1bd3 (diff)
Merge tag 'soc-for-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc into next
Pull part one of ARM SoC updates from Olof Johansson: "A quite large set of SoC updates this cycle. In no particular order: - Multi-cluster power management for Samsung Exynos, adding support for big.LITTLE CPU switching on EXYNOS5 - SMP support for Marvell Armada 375 and 38x - SMP rework on Allwinner A31 - Xilinx Zynq support for SOC_BUS, big endian - Marvell orion5x platform cleanup, modernizing the implementation and moving to DT. - _Finally_ moving Samsung Exynos over to support MULTIPLATFORM, so that their platform can be enabled in the same kernel binary as most of the other v7 platforms in the tree. \o/ The work isn't quite complete, there's some driver fixes still needed, but the basics now work. New SoC support added: - Freescale i.MX6SX - LSI Axxia AXM55xx SoCs - Samsung EXYNOS 3250, 5260, 5410, 5420 and 5800 - STi STIH407 plus a large set of various smaller updates for different platforms. I'm probably missing some important one here" * tag 'soc-for-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (281 commits) ARM: exynos: don't run exynos4 l2x0 setup on other platforms ARM: exynos: Fix "allmodconfig" build errors in mcpm and hotplug ARM: EXYNOS: mcpm rename the power_down_finish ARM: EXYNOS: Enable mcpm for dual-cluster exynos5800 SoC ARM: EXYNOS: Enable multi-platform build support ARM: EXYNOS: Consolidate Kconfig entries ARM: EXYNOS: Add support for EXYNOS5410 SoC ARM: EXYNOS: Support secondary CPU boot of Exynos3250 ARM: EXYNOS: Add Exynos3250 SoC ID ARM: EXYNOS: Add 5800 SoC support ARM: EXYNOS: initial board support for exynos5260 SoC clk: exynos5410: register clocks using common clock framework ARM: debug: qcom: add UART addresses to Kconfig help for APQ8084 ARM: sunxi: allow building without reset controller Documentation: devicetree: arm: sort enable-method entries ARM: rockchip: convert smp bringup to CPU_METHOD_OF_DECLARE clk: exynos5250: Add missing sysmmu clocks for DISP and ISP blocks ARM: dts: axxia: Add reset controller power: reset: Add Axxia system reset driver ARM: axxia: Adding defconfig for AXM55xx ...
Diffstat (limited to 'arch/arm/mach-omap2/vc.c')
-rw-r--r--arch/arm/mach-omap2/vc.c232
1 files changed, 156 insertions, 76 deletions
diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c
index 267f204559c3..a4628a9e760c 100644
--- a/arch/arm/mach-omap2/vc.c
+++ b/arch/arm/mach-omap2/vc.c
@@ -220,10 +220,126 @@ static inline u32 omap_usec_to_32k(u32 usec)
220 return DIV_ROUND_UP_ULL(32768ULL * (u64)usec, 1000000ULL); 220 return DIV_ROUND_UP_ULL(32768ULL * (u64)usec, 1000000ULL);
221} 221}
222 222
223/* Set oscillator setup time for omap3 */ 223struct omap3_vc_timings {
224static void omap3_set_clksetup(u32 usec, struct voltagedomain *voltdm) 224 u32 voltsetup1;
225 u32 voltsetup2;
226};
227
228struct omap3_vc {
229 struct voltagedomain *vd;
230 u32 voltctrl;
231 u32 voltsetup1;
232 u32 voltsetup2;
233 struct omap3_vc_timings timings[2];
234};
235static struct omap3_vc vc;
236
237void omap3_vc_set_pmic_signaling(int core_next_state)
238{
239 struct voltagedomain *vd = vc.vd;
240 struct omap3_vc_timings *c = vc.timings;
241 u32 voltctrl, voltsetup1, voltsetup2;
242
243 voltctrl = vc.voltctrl;
244 voltsetup1 = vc.voltsetup1;
245 voltsetup2 = vc.voltsetup2;
246
247 switch (core_next_state) {
248 case PWRDM_POWER_OFF:
249 voltctrl &= ~(OMAP3430_PRM_VOLTCTRL_AUTO_RET |
250 OMAP3430_PRM_VOLTCTRL_AUTO_SLEEP);
251 voltctrl |= OMAP3430_PRM_VOLTCTRL_AUTO_OFF;
252 if (voltctrl & OMAP3430_PRM_VOLTCTRL_SEL_OFF)
253 voltsetup2 = c->voltsetup2;
254 else
255 voltsetup1 = c->voltsetup1;
256 break;
257 case PWRDM_POWER_RET:
258 default:
259 c++;
260 voltctrl &= ~(OMAP3430_PRM_VOLTCTRL_AUTO_OFF |
261 OMAP3430_PRM_VOLTCTRL_AUTO_SLEEP);
262 voltctrl |= OMAP3430_PRM_VOLTCTRL_AUTO_RET;
263 voltsetup1 = c->voltsetup1;
264 break;
265 }
266
267 if (voltctrl != vc.voltctrl) {
268 vd->write(voltctrl, OMAP3_PRM_VOLTCTRL_OFFSET);
269 vc.voltctrl = voltctrl;
270 }
271 if (voltsetup1 != vc.voltsetup1) {
272 vd->write(c->voltsetup1,
273 OMAP3_PRM_VOLTSETUP1_OFFSET);
274 vc.voltsetup1 = voltsetup1;
275 }
276 if (voltsetup2 != vc.voltsetup2) {
277 vd->write(c->voltsetup2,
278 OMAP3_PRM_VOLTSETUP2_OFFSET);
279 vc.voltsetup2 = voltsetup2;
280 }
281}
282
283#define PRM_POLCTRL_TWL_MASK (OMAP3430_PRM_POLCTRL_CLKREQ_POL | \
284 OMAP3430_PRM_POLCTRL_CLKREQ_POL)
285#define PRM_POLCTRL_TWL_VAL OMAP3430_PRM_POLCTRL_CLKREQ_POL
286
287/*
288 * Configure signal polarity for sys_clkreq and sys_off_mode pins
289 * as the default values are wrong and can cause the system to hang
290 * if any twl4030 scripts are loaded.
291 */
292static void __init omap3_vc_init_pmic_signaling(struct voltagedomain *voltdm)
293{
294 u32 val;
295
296 if (vc.vd)
297 return;
298
299 vc.vd = voltdm;
300
301 val = voltdm->read(OMAP3_PRM_POLCTRL_OFFSET);
302 if (!(val & OMAP3430_PRM_POLCTRL_CLKREQ_POL) ||
303 (val & OMAP3430_PRM_POLCTRL_CLKREQ_POL)) {
304 val |= OMAP3430_PRM_POLCTRL_CLKREQ_POL;
305 val &= ~OMAP3430_PRM_POLCTRL_OFFMODE_POL;
306 pr_debug("PM: fixing sys_clkreq and sys_off_mode polarity to 0x%x\n",
307 val);
308 voltdm->write(val, OMAP3_PRM_POLCTRL_OFFSET);
309 }
310
311 /*
312 * By default let's use I2C4 signaling for retention idle
313 * and sys_off_mode pin signaling for off idle. This way we
314 * have sys_clk_req pin go down for retention and both
315 * sys_clk_req and sys_off_mode pins will go down for off
316 * idle. And we can also scale voltages to zero for off-idle.
317 * Note that no actual voltage scaling during off-idle will
318 * happen unless the board specific twl4030 PMIC scripts are
319 * loaded.
320 */
321 val = voltdm->read(OMAP3_PRM_VOLTCTRL_OFFSET);
322 if (!(val & OMAP3430_PRM_VOLTCTRL_SEL_OFF)) {
323 val |= OMAP3430_PRM_VOLTCTRL_SEL_OFF;
324 pr_debug("PM: setting voltctrl sys_off_mode signaling to 0x%x\n",
325 val);
326 voltdm->write(val, OMAP3_PRM_VOLTCTRL_OFFSET);
327 }
328 vc.voltctrl = val;
329
330 omap3_vc_set_pmic_signaling(PWRDM_POWER_ON);
331}
332
333static void omap3_init_voltsetup1(struct voltagedomain *voltdm,
334 struct omap3_vc_timings *c, u32 idle)
225{ 335{
226 voltdm->write(omap_usec_to_32k(usec), OMAP3_PRM_CLKSETUP_OFFSET); 336 unsigned long val;
337
338 val = (voltdm->vc_param->on - idle) / voltdm->pmic->slew_rate;
339 val *= voltdm->sys_clk.rate / 8 / 1000000 + 1;
340 val <<= __ffs(voltdm->vfsm->voltsetup_mask);
341 c->voltsetup1 &= ~voltdm->vfsm->voltsetup_mask;
342 c->voltsetup1 |= val;
227} 343}
228 344
229/** 345/**
@@ -236,37 +352,21 @@ static void omap3_set_clksetup(u32 usec, struct voltagedomain *voltdm)
236 * or retention. Off mode has additionally an option to use sys_off_mode 352 * or retention. Off mode has additionally an option to use sys_off_mode
237 * pad, which uses a global signal to program the whole power IC to 353 * pad, which uses a global signal to program the whole power IC to
238 * off-mode. 354 * off-mode.
355 *
356 * Note that pmic is not controlling the voltage scaling during
357 * retention signaled over I2C4, so we can keep voltsetup2 as 0.
358 * And the oscillator is not shut off over I2C4, so no need to
359 * set clksetup.
239 */ 360 */
240static void omap3_set_i2c_timings(struct voltagedomain *voltdm, bool off_mode) 361static void omap3_set_i2c_timings(struct voltagedomain *voltdm)
241{ 362{
242 unsigned long voltsetup1; 363 struct omap3_vc_timings *c = vc.timings;
243 u32 tgt_volt;
244
245 /*
246 * Oscillator is shut down only if we are using sys_off_mode pad,
247 * thus we set a minimal setup time here
248 */
249 omap3_set_clksetup(1, voltdm);
250 364
251 if (off_mode) 365 /* Configure PRWDM_POWER_OFF over I2C4 */
252 tgt_volt = voltdm->vc_param->off; 366 omap3_init_voltsetup1(voltdm, c, voltdm->vc_param->off);
253 else 367 c++;
254 tgt_volt = voltdm->vc_param->ret; 368 /* Configure PRWDM_POWER_RET over I2C4 */
255 369 omap3_init_voltsetup1(voltdm, c, voltdm->vc_param->ret);
256 voltsetup1 = (voltdm->vc_param->on - tgt_volt) /
257 voltdm->pmic->slew_rate;
258
259 voltsetup1 = voltsetup1 * voltdm->sys_clk.rate / 8 / 1000000 + 1;
260
261 voltdm->rmw(voltdm->vfsm->voltsetup_mask,
262 voltsetup1 << __ffs(voltdm->vfsm->voltsetup_mask),
263 voltdm->vfsm->voltsetup_reg);
264
265 /*
266 * pmic is not controlling the voltage scaling during retention,
267 * thus set voltsetup2 to 0
268 */
269 voltdm->write(0, OMAP3_PRM_VOLTSETUP2_OFFSET);
270} 370}
271 371
272/** 372/**
@@ -275,69 +375,49 @@ static void omap3_set_i2c_timings(struct voltagedomain *voltdm, bool off_mode)
275 * 375 *
276 * Calculates and sets up off-mode timings for a channel. Off-mode 376 * Calculates and sets up off-mode timings for a channel. Off-mode
277 * can use either I2C based voltage scaling, or alternatively 377 * can use either I2C based voltage scaling, or alternatively
278 * sys_off_mode pad can be used to send a global command to power IC. 378 * sys_off_mode pad can be used to send a global command to power IC.n,
279 * This function first checks which mode is being used, and calls
280 * omap3_set_i2c_timings() if the system is using I2C control mode.
281 * sys_off_mode has the additional benefit that voltages can be 379 * sys_off_mode has the additional benefit that voltages can be
282 * scaled to zero volt level with TWL4030 / TWL5030, I2C can only 380 * scaled to zero volt level with TWL4030 / TWL5030, I2C can only
283 * scale to 600mV. 381 * scale to 600mV.
382 *
383 * Note that omap is not controlling the voltage scaling during
384 * off idle signaled by sys_off_mode, so we can keep voltsetup1
385 * as 0.
284 */ 386 */
285static void omap3_set_off_timings(struct voltagedomain *voltdm) 387static void omap3_set_off_timings(struct voltagedomain *voltdm)
286{ 388{
287 unsigned long clksetup; 389 struct omap3_vc_timings *c = vc.timings;
288 unsigned long voltsetup2; 390 u32 tstart, tshut, clksetup, voltoffset;
289 unsigned long voltsetup2_old;
290 u32 val;
291 u32 tstart, tshut;
292 391
293 /* check if sys_off_mode is used to control off-mode voltages */ 392 if (c->voltsetup2)
294 val = voltdm->read(OMAP3_PRM_VOLTCTRL_OFFSET);
295 if (!(val & OMAP3430_SEL_OFF_MASK)) {
296 /* No, omap is controlling them over I2C */
297 omap3_set_i2c_timings(voltdm, true);
298 return; 393 return;
299 }
300 394
301 omap_pm_get_oscillator(&tstart, &tshut); 395 omap_pm_get_oscillator(&tstart, &tshut);
302 omap3_set_clksetup(tstart, voltdm); 396 if (tstart == ULONG_MAX) {
303 397 pr_debug("PM: oscillator start-up time not initialized, using 10ms\n");
304 clksetup = voltdm->read(OMAP3_PRM_CLKSETUP_OFFSET); 398 clksetup = omap_usec_to_32k(10000);
305 399 } else {
306 /* voltsetup 2 in us */ 400 clksetup = omap_usec_to_32k(tstart);
307 voltsetup2 = voltdm->vc_param->on / voltdm->pmic->slew_rate; 401 }
308
309 /* convert to 32k clk cycles */
310 voltsetup2 = DIV_ROUND_UP(voltsetup2 * 32768, 1000000);
311
312 voltsetup2_old = voltdm->read(OMAP3_PRM_VOLTSETUP2_OFFSET);
313
314 /*
315 * Update voltsetup2 if higher than current value (needed because
316 * we have multiple channels with different ramp times), also
317 * update voltoffset always to value recommended by TRM
318 */
319 if (voltsetup2 > voltsetup2_old) {
320 voltdm->write(voltsetup2, OMAP3_PRM_VOLTSETUP2_OFFSET);
321 voltdm->write(clksetup - voltsetup2,
322 OMAP3_PRM_VOLTOFFSET_OFFSET);
323 } else
324 voltdm->write(clksetup - voltsetup2_old,
325 OMAP3_PRM_VOLTOFFSET_OFFSET);
326 402
327 /* 403 /*
328 * omap is not controlling voltage scaling during off-mode, 404 * For twl4030 errata 27, we need to allow minimum ~488.32 us wait to
329 * thus set voltsetup1 to 0 405 * switch from HFCLKIN to internal oscillator. That means timings
406 * have voltoffset fixed to 0xa in rounded up 32 KiHz cycles. And
407 * that means we can calculate the value based on the oscillator
408 * start-up time since voltoffset2 = clksetup - voltoffset.
330 */ 409 */
331 voltdm->rmw(voltdm->vfsm->voltsetup_mask, 0, 410 voltoffset = omap_usec_to_32k(488);
332 voltdm->vfsm->voltsetup_reg); 411 c->voltsetup2 = clksetup - voltoffset;
333 412 voltdm->write(clksetup, OMAP3_PRM_CLKSETUP_OFFSET);
334 /* voltoffset must be clksetup minus voltsetup2 according to TRM */ 413 voltdm->write(voltoffset, OMAP3_PRM_VOLTOFFSET_OFFSET);
335 voltdm->write(clksetup - voltsetup2, OMAP3_PRM_VOLTOFFSET_OFFSET);
336} 414}
337 415
338static void __init omap3_vc_init_channel(struct voltagedomain *voltdm) 416static void __init omap3_vc_init_channel(struct voltagedomain *voltdm)
339{ 417{
418 omap3_vc_init_pmic_signaling(voltdm);
340 omap3_set_off_timings(voltdm); 419 omap3_set_off_timings(voltdm);
420 omap3_set_i2c_timings(voltdm);
341} 421}
342 422
343/** 423/**