davinci: am18x/da850/omap-l138: add support for higher speed grades
authorSekhar Nori <nsekhar@ti.com>
Mon, 20 Dec 2010 16:01:33 +0000 (21:31 +0530)
committerKevin Hilman <khilman@deeprootsystems.com>
Wed, 22 Dec 2010 19:45:29 +0000 (11:45 -0800)
AM18x/DA850/OMAP-L138 SoCs have variants that can operate
at a maximum of 456 MHz at 1.3V operating point. Also the
1.2V operating point has a variant that can support a maximum
of 375 MHz.

This patch adds three new OPPs (456 MHz, 408 MHz and 372 MHz)
to the list of DA850 OPPs.

Not all silicon is qualified to run at higher speeds and
unfortunately the maximum speed the chip can support can only
be determined from the label on the package (not software
readable).

Because of this, we depend on the maximum speed grade information
to be provided to us in some board specific way. The board informs
the maximum speed grade information by setting the da850_max_speed
variable.

Signed-off-by: Sekhar Nori <nsekhar@ti.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
arch/arm/mach-davinci/da850.c
arch/arm/mach-davinci/include/mach/da8xx.h

index 63916b90276042f01750bf5a41f79d7b64c2fd3a..78b5ae29ae403688c9ed82077f460bdb9c4647ac 100644 (file)
@@ -830,8 +830,7 @@ static void da850_set_async3_src(int pllnum)
  * According to the TRM, minimum PLLM results in maximum power savings.
  * The OPP definitions below should keep the PLLM as low as possible.
  *
- * The output of the PLLM must be between 400 to 600 MHz.
- * This rules out prediv of anything but divide-by-one for 24Mhz OSC input.
+ * The output of the PLLM must be between 300 to 600 MHz.
  */
 struct da850_opp {
        unsigned int    freq;   /* in KHz */
@@ -842,6 +841,33 @@ struct da850_opp {
        unsigned int    cvdd_max; /* in uV */
 };
 
+static const struct da850_opp da850_opp_456 = {
+       .freq           = 456000,
+       .prediv         = 1,
+       .mult           = 19,
+       .postdiv        = 1,
+       .cvdd_min       = 1300000,
+       .cvdd_max       = 1350000,
+};
+
+static const struct da850_opp da850_opp_408 = {
+       .freq           = 408000,
+       .prediv         = 1,
+       .mult           = 17,
+       .postdiv        = 1,
+       .cvdd_min       = 1300000,
+       .cvdd_max       = 1350000,
+};
+
+static const struct da850_opp da850_opp_372 = {
+       .freq           = 372000,
+       .prediv         = 2,
+       .mult           = 31,
+       .postdiv        = 1,
+       .cvdd_min       = 1200000,
+       .cvdd_max       = 1320000,
+};
+
 static const struct da850_opp da850_opp_300 = {
        .freq           = 300000,
        .prediv         = 1,
@@ -876,6 +902,9 @@ static const struct da850_opp da850_opp_96 = {
        }
 
 static struct cpufreq_frequency_table da850_freq_table[] = {
+       OPP(456),
+       OPP(408),
+       OPP(372),
        OPP(300),
        OPP(200),
        OPP(96),
@@ -885,6 +914,19 @@ static struct cpufreq_frequency_table da850_freq_table[] = {
        },
 };
 
+#ifdef CONFIG_REGULATOR
+static int da850_set_voltage(unsigned int index);
+static int da850_regulator_init(void);
+#endif
+
+static struct davinci_cpufreq_config cpufreq_info = {
+       .freq_table = da850_freq_table,
+#ifdef CONFIG_REGULATOR
+       .init = da850_regulator_init,
+       .set_voltage = da850_set_voltage,
+#endif
+};
+
 #ifdef CONFIG_REGULATOR
 static struct regulator *cvdd;
 
@@ -895,7 +937,7 @@ static int da850_set_voltage(unsigned int index)
        if (!cvdd)
                return -ENODEV;
 
-       opp = (struct da850_opp *) da850_freq_table[index].index;
+       opp = (struct da850_opp *) cpufreq_info.freq_table[index].index;
 
        return regulator_set_voltage(cvdd, opp->cvdd_min, opp->cvdd_max);
 }
@@ -912,14 +954,6 @@ static int da850_regulator_init(void)
 }
 #endif
 
-static struct davinci_cpufreq_config cpufreq_info = {
-       .freq_table = &da850_freq_table[0],
-#ifdef CONFIG_REGULATOR
-       .init = da850_regulator_init,
-       .set_voltage = da850_set_voltage,
-#endif
-};
-
 static struct platform_device da850_cpufreq_device = {
        .name                   = "cpufreq-davinci",
        .dev = {
@@ -928,12 +962,22 @@ static struct platform_device da850_cpufreq_device = {
        .id = -1,
 };
 
+unsigned int da850_max_speed = 300000;
+
 int __init da850_register_cpufreq(char *async_clk)
 {
+       int i;
+
        /* cpufreq driver can help keep an "async" clock constant */
        if (async_clk)
                clk_add_alias("async", da850_cpufreq_device.name,
                                                        async_clk, NULL);
+       for (i = 0; i < ARRAY_SIZE(da850_freq_table); i++) {
+               if (da850_freq_table[i].frequency <= da850_max_speed) {
+                       cpufreq_info.freq_table = &da850_freq_table[i];
+                       break;
+               }
+       }
 
        return platform_device_register(&da850_cpufreq_device);
 }
@@ -942,17 +986,18 @@ static int da850_round_armrate(struct clk *clk, unsigned long rate)
 {
        int i, ret = 0, diff;
        unsigned int best = (unsigned int) -1;
+       struct cpufreq_frequency_table *table = cpufreq_info.freq_table;
 
        rate /= 1000; /* convert to kHz */
 
-       for (i = 0; da850_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
-               diff = da850_freq_table[i].frequency - rate;
+       for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
+               diff = table[i].frequency - rate;
                if (diff < 0)
                        diff = -diff;
 
                if (diff < best) {
                        best = diff;
-                       ret = da850_freq_table[i].frequency;
+                       ret = table[i].frequency;
                }
        }
 
@@ -973,7 +1018,7 @@ static int da850_set_pll0rate(struct clk *clk, unsigned long index)
        struct pll_data *pll = clk->pll_data;
        int ret;
 
-       opp = (struct da850_opp *) da850_freq_table[index].index;
+       opp = (struct da850_opp *) cpufreq_info.freq_table[index].index;
        prediv = opp->prediv;
        mult = opp->mult;
        postdiv = opp->postdiv;
index 4247b3f53b338f596b37fc1664becc3c82df727e..e7f95206652763b1aabf85644a78a1f3c52f8395 100644 (file)
 extern void __iomem *da8xx_syscfg0_base;
 extern void __iomem *da8xx_syscfg1_base;
 
+/*
+ * If the DA850/OMAP-L138/AM18x SoC on board is of a higher speed grade
+ * (than the regular 300Mhz variant), the board code should set this up
+ * with the supported speed before calling da850_register_cpufreq().
+ */
+extern unsigned int da850_max_speed;
+
 /*
  * The cp_intc interrupt controller for the da8xx isn't in the same
  * chunk of physical memory space as the other registers (like it is