linux-omap3: Add supported kernel recipe for am37x-evm and am3517-evm
[glsdk/meta-ti-glsdk.git] / recipes-kernel / linux / linux-omap3-2.6.37-psp04.02.00.07 / omap3 / 0001-am37x-Adding-ABB-Support-for-1GHz-OPP.patch
1 From 0192a1d0731d3e8959b817bbc458c21e1c51408f Mon Sep 17 00:00:00 2001
2 From: Greg Guyotte <gguyotte@ti.com>
3 Date: Tue, 5 Jun 2012 16:54:26 -0500
4 Subject: [PATCH] am37x: Adding ABB Support for 1GHz OPP
6 This patch adds ABB support for the AM37x 1GHz OPP.  When 1GHz
7 operation occurs, the ABB LDO will be enabled, effectively
8 boosting MPU voltage.  At any time that we are not operating
9 at 1GHz, the ABB LDO will be bypassed.  This change is
10 required for operation at 1GHz on the AM37x device.
12 This patch only affects AM37x.  In the course of booting,
13 it boosts the MPU rate to 1GHz and turns on the ABB LDO.  It
14 is expected that the system will be operating at 800MHz
15 prior to this time, as set by Uboot.  Also note that after
16 MPU rate is changed, the loops_per_jiffy global is updated,
17 which is required in order to get the proper readout from
18 BogoMIPS.
20 Upstream-Status: Not Appropriate
21     * This patch is a quick fix based on an old kernel.
22     * This will be reworked for the Linux mainline kernel.
24 Signed-off-by: Greg Guyotte <gguyotte@ti.com>
25 ---
26  arch/arm/mach-omap2/pm.c               |   30 +++++++-
27  arch/arm/mach-omap2/prm-regbits-34xx.h |   20 +++++
28  arch/arm/mach-omap2/prm2xxx_3xxx.h     |    5 ++
29  arch/arm/mach-omap2/voltage.c          |  123 ++++++++++++++++++++++++++++++++
30  4 files changed, 176 insertions(+), 2 deletions(-)
32 diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
33 index f7e4d1b..678877c 100644
34 --- a/arch/arm/mach-omap2/pm.c
35 +++ b/arch/arm/mach-omap2/pm.c
36 @@ -27,6 +27,8 @@
37  #include "cm2xxx_3xxx.h"
38  #include "pm.h"
39  
40 +#define RATE_1GHZ 1000000000
41 +
42  static struct omap_device_pm_latency *pm_lats;
43  
44  static struct device *mpu_dev;
45 @@ -61,7 +63,6 @@ struct device *omap4_get_dsp_device(void)
46  }
47  EXPORT_SYMBOL(omap4_get_dsp_device);
48  
49 -#ifndef CONFIG_CPU_FREQ
50  static unsigned long compute_lpj(unsigned long ref, u_int div, u_int mult)
51  {
52         unsigned long new_jiffy_l, new_jiffy_h;
53 @@ -81,7 +82,6 @@ static unsigned long compute_lpj(unsigned long ref, u_int div, u_int mult)
54  
55         return new_jiffy_h + new_jiffy_l * 100;
56  }
57 -#endif
58  
59  /* static int _init_omap_device(struct omap_hwmod *oh, void *user) */
60  static int _init_omap_device(char *name, struct device **new_dev)
61 @@ -289,6 +289,7 @@ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name,
62         struct clk *clk;
63         struct opp *opp;
64         unsigned long freq, bootup_volt;
65 +       int ret;
66  
67         if (!vdd_name || !clk_name || !dev) {
68                 printk(KERN_ERR "%s: Invalid parameters!\n", __func__);
69 @@ -311,6 +312,11 @@ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name,
70  
71         freq = clk->rate;
72         clk_put(clk);
73 +       
74 +       /* set up for a voltage to support 1GHz */
75 +       if (cpu_is_omap3630())
76 +               if (!strcmp(vdd_name, "mpu"))
77 +                       freq = RATE_1GHZ;
78  
79         opp = opp_find_freq_ceil(dev, &freq);
80         if (IS_ERR(opp)) {
81 @@ -327,6 +333,26 @@ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name,
82         }
83  
84         omap_voltage_scale_vdd(voltdm, bootup_volt);
85 +
86 +       /* once voltage is changed, we can scale freq to max */
87 +       if (cpu_is_omap3630()) {
88 +               if (!strcmp(vdd_name, "mpu")) {
89 +                       unsigned long cur_rate;
90 +                       cur_rate = clk->rate;
91 +
92 +                       ret = clk_set_rate(clk, RATE_1GHZ);
93 +                       if (ret) {
94 +                               dev_warn(dev, "%s: Unable to set rate to %d\n",
95 +                                        __func__, RATE_1GHZ);
96 +                               return ret;
97 +                       }
98 +                       /* Update loops_per_jiffy because processor speed is 
99 +                          being changed.  Necessary to keep BogoMIPS happy. */
100 +                       loops_per_jiffy = compute_lpj(loops_per_jiffy,
101 +                                                     cur_rate / 1000000, 
102 +                                                     RATE_1GHZ / 1000000);
103 +               }
104 +       }
105         return 0;
106  
107  exit:
108 diff --git a/arch/arm/mach-omap2/prm-regbits-34xx.h b/arch/arm/mach-omap2/prm-regbits-34xx.h
109 index 64c087a..2758fa3 100644
110 --- a/arch/arm/mach-omap2/prm-regbits-34xx.h
111 +++ b/arch/arm/mach-omap2/prm-regbits-34xx.h
112 @@ -89,6 +89,7 @@
113  #define OMAP3430_LASTPOWERSTATEENTERED_MASK            (0x3 << 0)
114  
115  /* PRM_IRQSTATUS_IVA2, PRM_IRQSTATUS_MPU shared bits */
116 +#define OMAP3630_ABB_LDO_TRANXDONE_ST                   (1 << 26)
117  #define OMAP3430_WKUP_ST_MASK                          (1 << 0)
118  
119  /* PRM_IRQENABLE_IVA2, PRM_IRQENABLE_MPU shared bits */
120 @@ -216,6 +217,9 @@
121  /* PRM_SYSCONFIG specific bits */
122  
123  /* PRM_IRQSTATUS_MPU specific bits */
124 +#define OMAP3630_VC_BYPASS_ACK_EN                       (1 << 28)
125 +#define OMAP3630_VC_VP1_ACK_EN                          (1 << 27)
126 +#define OMAP3630_VC_ABB_LDO_TRANXDONE_EN                (1 << 26)
127  #define OMAP3430ES2_SND_PERIPH_DPLL_ST_SHIFT           25
128  #define OMAP3430ES2_SND_PERIPH_DPLL_ST_MASK            (1 << 25)
129  #define OMAP3430_VC_TIMEOUTERR_ST_MASK                 (1 << 24)
130 @@ -587,6 +591,22 @@
131  
132  /* PRM_VP2_STATUS specific bits */
133  
134 +/* PRM_LDO_ABB_SETUP */
135 +#define OMAP3630_SR2_IN_TRANSITION                     (1 << 6)
136 +#define OMAP3630_SR2_STATUS_SHIFT                      3
137 +#define OMAP3630_SR2_STATUS_MASK                       (0x3 << 3)
138 +#define OMAP3630_OPP_CHANGE                            (1 << 2)
139 +#define OMAP3630_OPP_SEL_SHIFT                         0
140 +#define OMAP3630_OPP_SEL_MASK                          (0x3 << 0)
142 +/* PRM_LDO_ABB_CTRL */
143 +#define OMAP3630_SR2_WTCNT_VALUE_SHIFT                 8
144 +#define OMAP3630_SR2_WTCNT_VALUE_MASK                  (0xff << 8)
145 +#define OMAP3630_SLEEP_RBB_SEL                         (1 << 3)
146 +#define OMAP3630_ACTIVE_FBB_SEL                        (1 << 2)
147 +#define OMAP3630_ACTIVE_RBB_SEL                        (1 << 1)
148 +#define OMAP3630_SR2EN                                 (1 << 0)
150  /* RM_RSTST_NEON specific bits */
151  
152  /* PM_WKDEP_NEON specific bits */
153 diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h
154 index 613f83c..79c9ad5 100644
155 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.h
156 +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h
157 @@ -171,6 +171,11 @@
158  #define OMAP3_PRM_VP2_STATUS_OFFSET    0x00e4
159  #define OMAP3430_PRM_VP2_STATUS                OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e4)
160  
161 +#define OMAP3_PRM_LDO_ABB_SETUP_OFFSET  0x00f0
162 +#define OMAP3430_PRM_LDO_ABB_SETUP     OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00f0)
163 +#define OMAP3_PRM_LDO_ABB_CTRL_OFFSET  0x00f4
164 +#define OMAP3430_PRM_LDO_ABB_CTRL      OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00f4)
166  #define OMAP3_PRM_CLKSEL_OFFSET        0x0040
167  #define OMAP3430_PRM_CLKSEL            OMAP34XX_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0040)
168  #define OMAP3_PRM_CLKOUT_CTRL_OFFSET   0x0070
169 diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
170 index 2e015a7..32944d0 100644
171 --- a/arch/arm/mach-omap2/voltage.c
172 +++ b/arch/arm/mach-omap2/voltage.c
173 @@ -45,6 +45,10 @@
174  #define VP_TRANXDONE_TIMEOUT   300
175  #define VOLTAGE_DIR_SIZE       16
176  
177 +#define ABB_TRANXDONE_TIMEOUT   100
178 +#define ABB_FAST_OPP            1
179 +#define ABB_NOMINAL_OPP         2
181  /* Voltage processor register offsets */
182  struct vp_reg_offs {
183         u8 vpconfig;
184 @@ -764,6 +768,112 @@ static int vc_bypass_scale_voltage(struct omap_vdd_info *vdd,
185         return 0;
186  }
187  
188 +/**
189 + * omap3630_abb_change_active_opp - handle OPP changes with Adaptive Body-Bias
190 + * @target_opp_no: ABB_FAST_OPP or ABB_NOMINAL_OPP
191 + *
192 + * Adaptive Body-Bias is a 3630-specific technique to boost voltage in high
193 + * OPPs for silicon with weak characteristics as well as lower voltage in low
194 + * OPPs for silicon with strong characteristics.
195 + *
196 + * Only Foward Body-Bias for operating at high OPPs is implemented below.
197 + * Reverse Body-Bias for saving power in active cases and sleep cases is not
198 + * yet implemented.
199 + */
200 +static int omap3630_abb_change_active_opp(u32 target_opp_no)
201 +{
202 +       u32 sr2en_enabled;
203 +       int timeout;
205 +       /* has SR2EN been enabled previously? */
206 +       sr2en_enabled = (omap2_prm_read_mod_reg(OMAP3430_GR_MOD,
207 +                               OMAP3_PRM_LDO_ABB_CTRL_OFFSET) &
208 +                       OMAP3630_SR2EN);
210 +       /* select OPP */
211 +       /* FIXME: shouldn't be hardcoded OPP here */
212 +       if (target_opp_no == ABB_FAST_OPP) {
213 +               /* program for fast opp - enable fbb */
214 +               omap2_prm_rmw_mod_reg_bits(OMAP3630_OPP_SEL_MASK,
215 +                               (ABB_FAST_OPP << OMAP3630_OPP_SEL_SHIFT),
216 +                               OMAP3430_GR_MOD,
217 +                               OMAP3_PRM_LDO_ABB_SETUP_OFFSET);
219 +               /* enable the ABB ldo if not done already */
220 +               if (!sr2en_enabled)
221 +                       omap2_prm_set_mod_reg_bits(OMAP3630_SR2EN,
222 +                                       OMAP3430_GR_MOD,
223 +                                       OMAP3_PRM_LDO_ABB_CTRL_OFFSET);
224 +              pr_debug("ABB: ABB LDO Enabled\n");
225 +       } else if (sr2en_enabled) {
226 +               /* program for nominal opp - bypass abb ldo */
227 +               omap2_prm_rmw_mod_reg_bits(OMAP3630_OPP_SEL_MASK,
228 +                               (ABB_NOMINAL_OPP << OMAP3630_OPP_SEL_SHIFT),
229 +                               OMAP3430_GR_MOD,
230 +                               OMAP3_PRM_LDO_ABB_SETUP_OFFSET);
231 +              pr_debug("ABB: ABB LDO Bypassed\n");
232 +       } else {
233 +               /* nothing to do here */
234 +               return 0;
235 +       }
237 +       /* set ACTIVE_FBB_SEL for all 3630 silicon */
238 +       omap2_prm_set_mod_reg_bits(OMAP3630_ACTIVE_FBB_SEL,
239 +                       OMAP3430_GR_MOD,
240 +                       OMAP3_PRM_LDO_ABB_CTRL_OFFSET);
242 +       /* program settling time of 30us for ABB ldo transition */
243 +       omap2_prm_rmw_mod_reg_bits(OMAP3630_SR2_WTCNT_VALUE_MASK,
244 +                       (0x62 << OMAP3630_SR2_WTCNT_VALUE_SHIFT),
245 +                       OMAP3430_GR_MOD,
246 +                       OMAP3_PRM_LDO_ABB_CTRL_OFFSET);
248 +       /* clear ABB ldo interrupt status */
249 +       omap2_prm_write_mod_reg(OMAP3630_ABB_LDO_TRANXDONE_ST,
250 +                       OCP_MOD,
251 +                       OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
253 +       /* enable ABB LDO OPP change */
254 +       omap2_prm_set_mod_reg_bits(OMAP3630_OPP_CHANGE,
255 +                       OMAP3430_GR_MOD,
256 +                       OMAP3_PRM_LDO_ABB_SETUP_OFFSET);
258 +       timeout = 0;
260 +       /* wait until OPP change completes */
261 +       while ((timeout < ABB_TRANXDONE_TIMEOUT ) &&
262 +                       (!(omap2_prm_read_mod_reg(OCP_MOD,
263 +                                           OMAP3_PRM_IRQSTATUS_MPU_OFFSET) &
264 +                          OMAP3630_ABB_LDO_TRANXDONE_ST))) {
265 +               udelay(1);
266 +               timeout++;
267 +       }
269 +       if (timeout == ABB_TRANXDONE_TIMEOUT)
270 +               pr_warning("ABB: TRANXDONE timed out waiting for OPP change\n");
272 +       timeout = 0;
274 +       /* Clear all pending TRANXDONE interrupts/status */
275 +       while (timeout < ABB_TRANXDONE_TIMEOUT) {
276 +               omap2_prm_write_mod_reg(OMAP3630_ABB_LDO_TRANXDONE_ST,
277 +                               OCP_MOD,
278 +                               OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
279 +               if (!(omap2_prm_read_mod_reg(OCP_MOD,
280 +                                       OMAP3_PRM_IRQSTATUS_MPU_OFFSET)
281 +                                       & OMAP3630_ABB_LDO_TRANXDONE_ST))
282 +                       break;
284 +               udelay(1);
285 +               timeout++;
286 +       }
288 +       if (timeout == ABB_TRANXDONE_TIMEOUT)
289 +               pr_warning("ABB: TRANXDONE timed out trying to clear status\n");
291 +       return 0;
292 +}
294  /* VP force update method of voltage scaling */
295  static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
296                 unsigned long target_volt)
297 @@ -858,6 +968,19 @@ static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
298         vpconfig &= ~vdd->vp_reg.vpconfig_forceupdate;
299         vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
300  
301 +       if (cpu_is_omap3630() && !strcmp(vdd->voltdm.name, "mpu")) {
302 +               if (vdd->curr_volt == OMAP3630_VDD_MPU_OPP1G_UV) {
303 +                       pr_debug("%s: vdd_%s: Attempting ABB enable\n",
304 +                                  __func__, vdd->voltdm.name);
305 +                       omap3630_abb_change_active_opp(ABB_FAST_OPP);
306 +               }
307 +               else {
308 +                       pr_debug("%s: vdd_%s: Attempting ABB disable\n", 
309 +                                  __func__, vdd->voltdm.name);
310 +                       omap3630_abb_change_active_opp(ABB_NOMINAL_OPP);
311 +               }
312 +       }
314         return 0;
315  }
316  
317 -- 
318 1.7.0.4