summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-mx6/cpu_regulator-mx6.c70
-rw-r--r--arch/arm/mach-mx6/crm_regs.h6
-rw-r--r--arch/arm/mach-mx6/mx6_anatop_regulator.c70
-rwxr-xr-xarch/arm/plat-mxc/cpufreq.c3
4 files changed, 118 insertions, 31 deletions
diff --git a/arch/arm/mach-mx6/cpu_regulator-mx6.c b/arch/arm/mach-mx6/cpu_regulator-mx6.c
index d905132e98b1..59bc3832d00f 100644
--- a/arch/arm/mach-mx6/cpu_regulator-mx6.c
+++ b/arch/arm/mach-mx6/cpu_regulator-mx6.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -97,12 +97,32 @@ void mx6_cpu_regulator_init(void)
} else {
curr_cpu = clk_get_rate(cpu_clk);
cpu_op_tbl = get_cpu_op(&cpu_op_nr);
- /* Set the core to max frequency requested. */
+
+ soc_regulator = regulator_get(NULL, soc_reg_id);
+ if (IS_ERR(soc_regulator))
+ printk(KERN_ERR "%s: failed to get soc regulator\n",
+ __func__);
+ else
+ /* set soc to highest setpoint voltage. */
+ regulator_set_voltage(soc_regulator,
+ cpu_op_tbl[0].soc_voltage,
+ cpu_op_tbl[0].soc_voltage);
+
+ pu_regulator = regulator_get(NULL, pu_reg_id);
+ if (IS_ERR(pu_regulator))
+ printk(KERN_ERR "%s: failed to get pu regulator\n",
+ __func__);
+ else
+ /* set pu to higheset setpoint voltage. */
+ regulator_set_voltage(pu_regulator,
+ cpu_op_tbl[0].pu_voltage,
+ cpu_op_tbl[0].pu_voltage);
+ /* set the core to higheset setpoint voltage. */
regulator_set_voltage(cpu_regulator,
cpu_op_tbl[0].cpu_voltage,
cpu_op_tbl[0].cpu_voltage);
if (enable_ldo_mode == LDO_MODE_BYPASSED) {
- /*digital bypass VDDPU/VDDSOC/VDDARM*/
+ /* digital bypass VDDPU/VDDSOC/VDDARM */
reg = __raw_readl(ANADIG_REG_CORE);
reg &= ~BM_ANADIG_REG_CORE_REG0_TRG;
reg |= BF_ANADIG_REG_CORE_REG0_TRG(0x1f);
@@ -111,14 +131,15 @@ void mx6_cpu_regulator_init(void)
reg &= ~BM_ANADIG_REG_CORE_REG2_TRG;
reg |= BF_ANADIG_REG_CORE_REG2_TRG(0x1f);
__raw_writel(reg, ANADIG_REG_CORE);
- /* Mask the ANATOP brown out interrupt in the GPC. */
+ /* mask the ANATOP brown out irq in the GPC. */
reg = __raw_readl(gpc_base + 0x14);
reg |= 0x80000000;
__raw_writel(reg, gpc_base + 0x14);
}
+
clk_set_rate(cpu_clk, cpu_op_tbl[0].cpu_rate);
- /*Fix loops-per-jiffy */
+ /* fix loops-per-jiffy */
#ifdef CONFIG_SMP
for_each_online_cpu(cpu)
per_cpu(cpu_data, cpu).loops_per_jiffy =
@@ -141,27 +162,24 @@ void mx6_cpu_regulator_init(void)
#endif
}
}
- soc_regulator = regulator_get(NULL, soc_reg_id);
- if (IS_ERR(soc_regulator))
- printk(KERN_ERR "%s: failed to get soc regulator\n", __func__);
- pu_regulator = regulator_get(NULL, pu_reg_id);
- if (IS_ERR(pu_regulator))
- printk(KERN_ERR "%s: failed to get pu regulator\n", __func__);
- /*If use ldo bypass and VDDPU_IN is single supplied
- *by external pmic, it means VDDPU_IN can be turned off if GPU/VPU driver
- *not running.In this case we should set external_pureg which can be used
- *in pu_enable/pu_disable of arch/arm/mach-mx6/mx6_anatop_regulator.c to
- *enable or disable external VDDPU regulator from pmic. But for FSL
- *reference boards, VDDSOC_IN connect with VDDPU_IN, so we didn't set
- *pu_reg_id to the external pmic regulator supply name in the board file.
- *In this case external_pureg should be 0 and can't turn off extern pmic
- *regulator, but can turn off VDDPU by internal anatop power gate.
- *
- *If enable internal ldo , external_pureg will be 0, and
- *VDDPU can be turned off by internal anatop anatop power gate.
- *
- */
- else if (!IS_ERR(pu_regulator) && strcmp(pu_reg_id, "cpu_vddgpu"))
+ /*
+ * if use ldo bypass and VDDPU_IN is single supplied
+ * by external pmic, it means VDDPU_IN can be turned off
+ * if GPU/VPU driver not running.In this case we should set
+ * external_pureg which can be used in pu_enable/pu_disable of
+ * arch/arm/mach-mx6/mx6_anatop_regulator.c to
+ * enable or disable external VDDPU regulator from pmic. But for FSL
+ * reference boards, VDDSOC_IN connect with VDDPU_IN, so we didn't set
+ * pu_reg_id to the external pmic regulator supply name in the board
+ * file. In this case external_pureg should be 0 and can't turn off
+ * extern pmic regulator, but can turn off VDDPU by internal anatop
+ * power gate.
+ *
+ * if enable internal ldo , external_pureg will be 0, and
+ * VDDPU can be turned off by internal anatop anatop power gate.
+ *
+ */
+ if (!IS_ERR(pu_regulator) && strcmp(pu_reg_id, "cpu_vddgpu"))
external_pureg = 1;
}
diff --git a/arch/arm/mach-mx6/crm_regs.h b/arch/arm/mach-mx6/crm_regs.h
index 5e03312b7fce..43fcb4d0d466 100644
--- a/arch/arm/mach-mx6/crm_regs.h
+++ b/arch/arm/mach-mx6/crm_regs.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2013 Freescale Semiconductor, Inc. All Rights Reserved.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
@@ -55,6 +55,7 @@
#define PFD_528_BASE_ADDR (MXC_PLL_BASE + 0x100)
#define ANADIG_REG_CORE (MXC_PLL_BASE + 0x140)
#define ANADIG_MISC1_REG (MXC_PLL_BASE + 0x160)
+#define ANADIG_MISC2_REG (MXC_PLL_BASE + 0x170)
#define ANATOP_LVDS_CLK1_SRC_SATA 0xB
#define ANATOP_LVDS_CLK1_OBEN_MASK 0x400
#define ANATOP_LVDS_CLK1_IBEN_MASK 0x1000
@@ -154,6 +155,9 @@
#define ANADIG_ANA_MISC2_REG1_BO_EN (1 << 13)
#define ANADIG_ANA_MISC2_CONTROL3_MASK 0xC0000000
#define ANADIG_ANA_MISC2_CONTROL3_OFFSET 30
+#define ANADIG_ANA_MISC2_REG0_STEP_TIME_MASK 0x30000000
+#define ANADIG_ANA_MISC2_REG1_STEP_TIME_MASK 0xC000000
+#define ANADIG_ANA_MISC2_REG2_STEP_TIME_MASK 0x3000000
#define MXC_CCM_BASE MX6_IO_ADDRESS(CCM_BASE_ADDR)
/* CCM Register Offsets. */
diff --git a/arch/arm/mach-mx6/mx6_anatop_regulator.c b/arch/arm/mach-mx6/mx6_anatop_regulator.c
index 02ee982964ed..83bd363dc3e3 100644
--- a/arch/arm/mach-mx6/mx6_anatop_regulator.c
+++ b/arch/arm/mach-mx6/mx6_anatop_regulator.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -42,6 +42,9 @@
#define GPC_PGC_GPU_PGCR_OFFSET 0x260
#define GPC_CNTR_OFFSET 0x0
+#define LDO_RAMP_UP_UNIT_IN_CYCLES 64 /* 64 cycles per step */
+#define LDO_RAMP_UP_FREQ_IN_MHZ 24 /* time base on 24M OSC */
+
extern struct platform_device sgtl5000_vdda_reg_devices;
extern struct platform_device sgtl5000_vddio_reg_devices;
extern struct platform_device sgtl5000_vddd_reg_devices;
@@ -79,6 +82,7 @@ static int get_voltage(struct anatop_regulator *sreg)
static int set_voltage(struct anatop_regulator *sreg, int uv)
{
u32 val, reg;
+ u32 delay, steps, old_val;
pr_debug("%s: uv %d, min %d, max %d\n", __func__,
uv, sreg->rdata->min_voltage, sreg->rdata->max_voltage);
@@ -94,8 +98,56 @@ static int set_voltage(struct anatop_regulator *sreg, int uv)
~(sreg->rdata->vol_bit_mask <<
sreg->rdata->vol_bit_shift));
pr_debug("%s: calculated val %d\n", __func__, val);
+
+ old_val = (__raw_readl(sreg->rdata->control_reg) >>
+ sreg->rdata->vol_bit_shift) & sreg->rdata->vol_bit_mask;
+
__raw_writel((val << sreg->rdata->vol_bit_shift) | reg,
sreg->rdata->control_reg);
+
+ if (sreg->rdata->control_reg == (unsigned int)(MXC_PLL_BASE +
+ HW_ANADIG_REG_CORE)) {
+ /* calculate how many steps to ramp up */
+ steps = (val > old_val) ? val - old_val : 0;
+ if (steps) {
+ switch (sreg->rdata->vol_bit_shift) {
+ case BP_ANADIG_REG_CORE_REG0_TRG:
+ reg = (__raw_readl(MXC_PLL_BASE +
+ HW_ANADIG_ANA_MISC2) &
+ BM_ANADIG_ANA_MISC2_REG0_STEP_TIME) >>
+ BP_ANADIG_ANA_MISC2_REG0_STEP_TIME;
+ break;
+ case BP_ANADIG_REG_CORE_REG1_TRG:
+ reg = (__raw_readl(MXC_PLL_BASE +
+ HW_ANADIG_ANA_MISC2) &
+ BM_ANADIG_ANA_MISC2_REG1_STEP_TIME) >>
+ BP_ANADIG_ANA_MISC2_REG1_STEP_TIME;
+ break;
+ case BP_ANADIG_REG_CORE_REG2_TRG:
+ reg = (__raw_readl(MXC_PLL_BASE +
+ HW_ANADIG_ANA_MISC2) &
+ BM_ANADIG_ANA_MISC2_REG2_STEP_TIME) >>
+ BP_ANADIG_ANA_MISC2_REG2_STEP_TIME;
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * the delay time for LDO ramp up time is
+ * based on the register setting, we need
+ * to calculate how many steps LDO need to
+ * ramp up, and how much delay needs. (us)
+ */
+ delay = steps * ((LDO_RAMP_UP_UNIT_IN_CYCLES <<
+ reg) / LDO_RAMP_UP_FREQ_IN_MHZ + 1);
+ udelay(delay);
+ pr_debug("%s: %s: delay %d, steps %d, uv %d\n",
+ __func__, sreg->rdata->name, delay,
+ steps, uv);
+ }
+ }
+
return 0;
} else {
pr_debug("Regulator not supported.\n");
@@ -532,6 +584,8 @@ static struct anatop_regulator vdd3p0_reg = {
static int __init regulators_init(void)
{
+ unsigned int reg;
+
anatop_register_regulator(&vddpu_reg, ANATOP_VDDPU, &vddpu_init);
anatop_register_regulator(&vddcore_reg, ANATOP_VDDCORE, &vddcore_init);
anatop_register_regulator(&vddsoc_reg, ANATOP_VDDSOC, &vddsoc_init);
@@ -539,7 +593,19 @@ static int __init regulators_init(void)
anatop_register_regulator(&vdd1p1_reg, ANATOP_VDD1P1, &vdd1p1_init);
anatop_register_regulator(&vdd3p0_reg, ANATOP_VDD3P0, &vdd3p0_init);
- /* clear flag in boot*/
+ /* Set the REGx step time back to reset value,
+ * as ROM may modify it according to fuse setting,
+ * so we need to set it back, otherwise, the delay
+ * time in cpu freq change will be impacted, the reset
+ * value is 0'b00, 64 cycles of 24M clock.
+ */
+ reg = __raw_readl(ANADIG_MISC2_REG);
+ reg &= ~ANADIG_ANA_MISC2_REG0_STEP_TIME_MASK;
+ reg &= ~ANADIG_ANA_MISC2_REG1_STEP_TIME_MASK;
+ reg &= ~ANADIG_ANA_MISC2_REG2_STEP_TIME_MASK;
+ __raw_writel(reg, ANADIG_MISC2_REG);
+
+ /* clear flag in boot */
pu_is_enabled = 0;
get_clk = 0;
return 0;
diff --git a/arch/arm/plat-mxc/cpufreq.c b/arch/arm/plat-mxc/cpufreq.c
index 4cdc8377e972..47a70d96b24c 100755
--- a/arch/arm/plat-mxc/cpufreq.c
+++ b/arch/arm/plat-mxc/cpufreq.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -112,7 +112,6 @@ int set_cpu_freq(int freq)
printk(KERN_ERR "COULD NOT SET GP VOLTAGE!!!!\n");
goto err3;
}
- udelay(50);
}
ret = clk_set_rate(cpu_clk, freq);
if (ret != 0) {