9321464149cbb027ecb014185db83c4e4c3cb9aa
[openembedded.git] /
1 From d3c60c04fac19bde2dd3b930fd659426557d9cae Mon Sep 17 00:00:00 2001
2 From: Thara Gopinath <thara@ti.com>
3 Date: Wed, 18 Aug 2010 16:22:32 +0530
4 Subject: [PATCH 14/19] OMAP3: Introduce custom set rate and get rate APIs for scalable devices
5
6 This patch also introduces omap3_mpu_set_rate, omap3_iva_set_rate,
7 omap3_l3_set_rate, omap3_mpu_get_rate, omap3_iva_get_rate,
8 omap3_l3_get_rate as device specific set rate and get rate
9 APIs for OMAP3 mpu, iva and l3_main devices. This patch also
10 calls into omap_device_populate_rate_fns during system init to register
11 various set_rate and get_rate APIs with the omap device layer
12
13 Signed-off-by: Thara Gopinath <thara@ti.com>
14 ---
15  arch/arm/mach-omap2/pm.c |  110 ++++++++++++++++++++++++++++++++++++++++++++++
16  1 files changed, 110 insertions(+), 0 deletions(-)
17
18 diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
19 index d5a102c..94ab0dd 100644
20 --- a/arch/arm/mach-omap2/pm.c
21 +++ b/arch/arm/mach-omap2/pm.c
22 @@ -14,6 +14,7 @@
23  #include <linux/io.h>
24  #include <linux/err.h>
25  #include <linux/opp.h>
26 +#include <linux/delay.h>
27  
28  #include <plat/omap-pm.h>
29  #include <plat/omap_device.h>
30 @@ -22,6 +23,8 @@
31  
32  #include "powerdomain.h"
33  #include "clockdomain.h"
34 +#include "cm-regbits-34xx.h"
35 +#include "cm2xxx_3xxx.h"
36  #include "pm.h"
37  
38  static struct omap_device_pm_latency *pm_lats;
39 @@ -31,6 +34,8 @@ static struct device *iva_dev;
40  static struct device *l3_dev;
41  static struct device *dsp_dev;
42  
43 +static struct clk *dpll1_clk, *dpll2_clk, *dpll3_clk;
44 +
45  struct device *omap2_get_mpuss_device(void)
46  {
47         WARN_ON_ONCE(!mpu_dev);
48 @@ -56,6 +61,26 @@ struct device *omap4_get_dsp_device(void)
49  }
50  EXPORT_SYMBOL(omap4_get_dsp_device);
51  
52 +static unsigned long compute_lpj(unsigned long ref, u_int div, u_int mult)
53 +{
54 +       unsigned long new_jiffy_l, new_jiffy_h;
55 +
56 +       /*
57 +        * Recalculate loops_per_jiffy.  We do it this way to
58 +        * avoid math overflow on 32-bit machines.  Maybe we
59 +        * should make this architecture dependent?  If you have
60 +        * a better way of doing this, please replace!
61 +        *
62 +        *    new = old * mult / div
63 +        */
64 +       new_jiffy_h = ref / div;
65 +       new_jiffy_l = (ref % div) / 100;
66 +       new_jiffy_h *= mult;
67 +       new_jiffy_l = new_jiffy_l * mult / div;
68 +
69 +       return new_jiffy_h + new_jiffy_l * 100;
70 +}
71 +
72  /* static int _init_omap_device(struct omap_hwmod *oh, void *user) */
73  static int _init_omap_device(char *name, struct device **new_dev)
74  {
75 @@ -77,6 +102,74 @@ static int _init_omap_device(char *name, struct device **new_dev)
76         return 0;
77  }
78  
79 +static unsigned long omap3_mpu_get_rate(struct device *dev)
80 +{
81 +       return dpll1_clk->rate;
82 +}
83 +
84 +static int omap3_mpu_set_rate(struct device *dev, unsigned long rate)
85 +{
86 +       unsigned long cur_rate = omap3_mpu_get_rate(dev);
87 +       int ret;
88 +
89 +#ifdef CONFIG_CPU_FREQ
90 +       struct cpufreq_freqs freqs_notify;
91 +
92 +       freqs_notify.old = cur_rate / 1000;
93 +       freqs_notify.new = rate / 1000;
94 +       freqs_notify.cpu = 0;
95 +       /* Send pre notification to CPUFreq */
96 +       cpufreq_notify_transition(&freqs_notify, CPUFREQ_PRECHANGE);
97 +#endif
98 +       ret = clk_set_rate(dpll1_clk, rate);
99 +       if (ret) {
100 +               dev_warn(dev, "%s: Unable to set rate to %ld\n",
101 +                       __func__, rate);
102 +               return ret;
103 +       }
104 +
105 +#ifdef CONFIG_CPU_FREQ
106 +       /* Send a post notification to CPUFreq */
107 +       cpufreq_notify_transition(&freqs_notify, CPUFREQ_POSTCHANGE);
108 +#endif
109 +
110 +#ifndef CONFIG_CPU_FREQ
111 +       /*Update loops_per_jiffy if processor speed is being changed*/
112 +       loops_per_jiffy = compute_lpj(loops_per_jiffy,
113 +                       cur_rate / 1000, rate / 1000);
114 +#endif
115 +       return 0;
116 +}
117 +
118 +static int omap3_iva_set_rate(struct device *dev, unsigned long rate)
119 +{
120 +       return clk_set_rate(dpll2_clk, rate);
121 +}
122 +
123 +static unsigned long omap3_iva_get_rate(struct device *dev)
124 +{
125 +       return dpll2_clk->rate;
126 +}
127 +
128 +static int omap3_l3_set_rate(struct device *dev, unsigned long rate)
129 +{
130 +       int l3_div;
131 +
132 +       l3_div = omap2_cm_read_mod_reg(CORE_MOD, CM_CLKSEL) &
133 +                       OMAP3430_CLKSEL_L3_MASK;
134 +
135 +       return clk_set_rate(dpll3_clk, rate * l3_div);
136 +}
137 +
138 +static unsigned long omap3_l3_get_rate(struct device *dev)
139 +{
140 +       int l3_div;
141 +
142 +       l3_div = omap2_cm_read_mod_reg(CORE_MOD, CM_CLKSEL) &
143 +                       OMAP3430_CLKSEL_L3_MASK;
144 +       return dpll3_clk->rate / l3_div;
145 +}
146 +
147  /*
148   * Build omap_devices for processors and bus.
149   */
150 @@ -90,6 +183,23 @@ static void omap2_init_processor_devices(void)
151         } else {
152                 _init_omap_device("l3_main", &l3_dev);
153         }
154 +
155 +       if (cpu_is_omap34xx()) {
156 +               dpll1_clk = clk_get(NULL, "dpll1_ck");
157 +               dpll2_clk = clk_get(NULL, "dpll2_ck");
158 +               dpll3_clk = clk_get(NULL, "dpll3_m2_ck");
159 +
160 +               if (mpu_dev)
161 +                       omap_device_populate_rate_fns(mpu_dev,
162 +                               omap3_mpu_set_rate, omap3_mpu_get_rate);
163 +               if (iva_dev)
164 +                       omap_device_populate_rate_fns(iva_dev,
165 +                               omap3_iva_set_rate, omap3_iva_get_rate);
166 +               if (l3_dev)
167 +                       omap_device_populate_rate_fns(l3_dev,
168 +                               omap3_l3_set_rate, omap3_l3_get_rate);
169 +
170 +       }
171  }
172  
173  /* Types of sleep_switch used in omap_set_pwrdm_state */
174 -- 
175 1.6.6.1
176