1 From d247a112a9ffbad1057a2c8bede5727940ac2045 Mon Sep 17 00:00:00 2001
2 From: Ranjith Lohithakshan <ranjithl@ti.com>
3 Date: Fri, 28 May 2010 15:20:32 +0530
4 Subject: [PATCH 2/9] omap3: Fix voltage and frequency scaling order when changing OPP via mpurate
6 When lowering an OPP via mpurate from what is being set by bootloader,
7 the frequency need to be lowered before voltage is ramped down. The
8 current code was not taking this into consideration and was always
9 adjusting the voltage before the frequency adjustments.
11 This was leading to crashes on 3730 when mpurate was set to 300MHz
12 because the voltage was lowered before the frequency.
14 This patch fixes these issues by tracking the direction of OPP change
15 and doing the voltage and frequency change in the right order.
17 Signed-off-by: Ranjith Lohithakshan <ranjithl@ti.com>
19 arch/arm/mach-omap2/clock34xx.c | 51 +++++++++++++++++++++++-------------
20 arch/arm/mach-omap2/smartreflex.c | 11 +++++---
21 2 files changed, 39 insertions(+), 23 deletions(-)
23 diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c
24 index 2bb7182..dd408eb 100644
25 --- a/arch/arm/mach-omap2/clock34xx.c
26 +++ b/arch/arm/mach-omap2/clock34xx.c
27 @@ -65,6 +65,7 @@ struct clk *sdrc_ick_p, *arm_fck_p;
29 unsigned int vdd1_opp = 0;
30 unsigned int vdd2_opp = 0;
31 +bool vdd_scale_down = false;
34 * omap3430es2_clk_ssi_find_idlest - return CM_IDLEST info for SSI
35 @@ -429,6 +430,24 @@ static void __init omap2_clk_iva_init_to_idle(void)
39 +static u16 get_opp(struct omap_opp *opp_freq_table,
42 + struct omap_opp *prcm_config;
44 + prcm_config = opp_freq_table;
46 + if (prcm_config->rate <= freq)
47 + return prcm_config->opp_id; /* Return the Highest OPP */
48 + for (; prcm_config->rate; prcm_config--)
49 + if (prcm_config->rate < freq)
50 + return (prcm_config+1)->opp_id;
51 + else if (prcm_config->rate == freq)
52 + return prcm_config->opp_id;
53 + /* Return the least OPP */
54 + return (prcm_config+1)->opp_id;
57 /* REVISIT: Move this init stuff out into clock.c */
60 @@ -444,8 +463,10 @@ static void __init omap2_clk_iva_init_to_idle(void)
62 static int __init omap2_clk_arch_init(void)
64 - struct omap_opp *opp_table;
65 - short valid=0, err=0, i;
67 + u16 current_vdd1_opp;
68 + struct clk *arm_fck;
69 + unsigned long current_mpu_rate;
73 @@ -463,6 +484,10 @@ static int __init omap2_clk_arch_init(void)
74 if (WARN((!l3_opps), "OPP table not defined for L3\n"))
77 + arm_fck = clk_get(NULL, "arm_fck");
78 + if (WARN(IS_ERR(arm_fck), "Failed to get arm_fck.\n"))
84 @@ -475,24 +500,12 @@ static int __init omap2_clk_arch_init(void)
85 pr_err("This silicon doesn't support 720MHz\n");
89 - * Select VDD1 OPP corresponding to mpurate
91 - opp_table = mpu_opps;
93 - for (i = 1; opp_table[i].opp_id <= get_max_vdd1(); i++) {
94 - if (opp_table[i].rate == mpurate) {
99 + current_mpu_rate = clk_get_rate(arm_fck);
100 + current_vdd1_opp = get_opp(mpu_opps + get_max_vdd1(), current_mpu_rate);
101 + vdd1_opp = get_opp(mpu_opps + get_max_vdd1(), mpurate);
104 - vdd1_opp = opp_table[i].opp_id;
106 - pr_err("Invalid MPU rate (%u)\n", mpurate);
109 + if (vdd1_opp < current_vdd1_opp)
110 + vdd_scale_down = true;
113 * Match lowest OPP setting for VDD1 with lowest OPP for VDD2 as well.
114 diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
115 index 3b6ddf8..fd34af2 100644
116 --- a/arch/arm/mach-omap2/smartreflex.c
117 +++ b/arch/arm/mach-omap2/smartreflex.c
120 extern unsigned int vdd1_opp;
121 extern unsigned int vdd2_opp;
122 +extern bool vdd_scale_down;
124 extern int __init omap2_clk_set_freq(void);
126 @@ -1082,6 +1083,10 @@ static int __init omap3_sr_init(void)
127 sr_set_clk_length(&sr1);
128 sr_set_clk_length(&sr2);
130 + /* For OPP scale down, scale down frequency before voltage */
131 + if (cpu_is_omap34xx() && vdd_scale_down)
132 + omap2_clk_set_freq();
134 /* Call the VPConfig, VCConfig, set N Values. */
135 sr_set_nvalues(&sr1);
136 sr_configure_vp(SR1);
137 @@ -1089,10 +1094,8 @@ static int __init omap3_sr_init(void)
138 sr_set_nvalues(&sr2);
139 sr_configure_vp(SR2);
142 - * With voltages matching target OPP, set corresponding frequency.
144 - if (cpu_is_omap34xx())
145 + /* For OPP scale up, scale up the frequency after voltage */
146 + if (cpu_is_omap34xx() && !vdd_scale_down)
147 omap2_clk_set_freq();
149 ret = sysfs_create_file(power_kobj, &sr_vdd1_autocomp.attr);