rk29: clock: default codec pll rate set to 297MHz
author黄涛 <huangtao@rock-chips.com>
Fri, 29 Jul 2011 08:22:28 +0000 (16:22 +0800)
committer黄涛 <huangtao@rock-chips.com>
Fri, 29 Jul 2011 08:23:14 +0000 (16:23 +0800)
arch/arm/mach-rk29/clock.c
arch/arm/mach-rk29/include/mach/board.h

index 2a8838a3f459f48bcb04ce8cd660a12ef42ddc7f..6f78ea504875a1881eecb29bc89f2bd3b58caf4a 100755 (executable)
@@ -135,13 +135,17 @@ static int clksel_set_rate_div(struct clk *clk, unsigned long rate)
        return -ENOENT;
 }
 
-static long clksel_round_rate_div(struct clk *clk, unsigned long rate)
+static long clksel_round_rate_div_by_parent(struct clk *clk, unsigned long rate, struct clk *parent, unsigned long max_rate)
 {
        u32 div;
        unsigned long prev = ULONG_MAX, actual;
 
+       if (max_rate < rate)
+               max_rate = rate;
        for (div = 0; div <= clk->clksel_mask; div++) {
-               actual = clk->parent->rate / (div + 1);
+               actual = parent->rate / (div + 1);
+               if (actual > max_rate)
+                       continue;
                if (actual > rate)
                        prev = actual;
                if (actual && actual <= rate) {
@@ -154,11 +158,18 @@ static long clksel_round_rate_div(struct clk *clk, unsigned long rate)
        }
        if (div > clk->clksel_mask)
                div = clk->clksel_mask;
-       pr_debug("clock %s, target rate %ld, rounded rate %ld (div %d)\n", clk->name, rate, actual, div + 1);
+       pr_debug("clock %s, target rate %ld, max rate %ld, rounded rate %ld (div %d)\n", clk->name, rate, max_rate, actual, div + 1);
 
        return actual;
 }
 
+#if 0
+static long clksel_round_rate_div(struct clk *clk, unsigned long rate)
+{
+       return clksel_round_rate_div_by_parent(clk, rate, clk->parent, ULONG_MAX);
+}
+#endif
+
 static int clksel_set_rate_shift(struct clk *clk, unsigned long rate)
 {
        u32 shift;
@@ -589,9 +600,11 @@ static const struct codec_pll_set codec_pll[] = {
        //        rate parent band NR  NF NO
        CODEC_PLL(108000, 24,  LOW, 1, 18, 4),  // for TV
        CODEC_PLL(648000, 24, HIGH, 1, 27, 1),
-       CODEC_PLL(297000, 27,  LOW, 1, 22, 2),  // for HDMI
+       CODEC_PLL(148500, 27,  LOW, 1, 22, 4),  // for HDMI
+       CODEC_PLL(297000, 27,  LOW, 1, 22, 2),
        CODEC_PLL(445500, 27,  LOW, 2, 33, 1),
        CODEC_PLL(594000, 27, HIGH, 1, 22, 1),
+       CODEC_PLL(891000, 27, HIGH, 1, 33, 1),
        CODEC_PLL(300000, 24,  LOW, 1, 25, 2),  // for GPU
        CODEC_PLL(360000, 24,  LOW, 1, 15, 1),
        CODEC_PLL(408000, 24,  LOW, 1, 17, 1),
@@ -1708,12 +1721,31 @@ static struct clk hclk_vdpu = {
 
 static int clk_gpu_set_rate(struct clk *clk, unsigned long rate)
 {
-       if (clk->parent == &codec_pll_clk && rate != codec_pll_clk.rate && rate == general_pll_clk.rate) {
-               clk_set_parent_nolock(clk, &general_pll_clk);
-       } else if (clk->parent == &general_pll_clk && rate != general_pll_clk.rate) {
-               clk_set_parent_nolock(clk, &codec_pll_clk);
+       unsigned long max_rate = rate / 100 * 105;      /* +5% */
+       struct clk *parents[] = { &general_pll_clk, &codec_pll_clk, &ddr_pll_clk };
+       int i;
+       unsigned long best_rate = 0;
+       struct clk *best_parent = clk->parent;
+
+       for (i = 0; i < ARRAY_SIZE(parents); i++) {
+               unsigned long new_rate = clksel_round_rate_div_by_parent(clk, rate, parents[i], max_rate);
+               if (new_rate == rate) {
+                       best_rate = new_rate;
+                       best_parent = parents[i];
+                       break;
+               }
+               if (new_rate > max_rate)
+                       continue;
+               if (new_rate > best_rate) {
+                       best_rate = new_rate;
+                       best_parent = parents[i];
+               }
        }
-       return clksel_set_rate_div(clk, clksel_round_rate_div(clk, rate));
+       if (!best_rate)
+               return -ENOENT;
+       if (best_parent != clk->parent)
+               clk_set_parent_nolock(clk, best_parent);
+       return clksel_set_rate_div(clk, best_rate);
 }
 
 static struct clk clk_gpu = {
@@ -2645,14 +2677,14 @@ void __init rk29_clock_init2(enum periph_pll ppll_rate, enum codec_pll cpll_rate
        printk(KERN_INFO "Clocking rate (apll/dpll/cpll/gpll/core/aclk_cpu/hclk_cpu/pclk_cpu/aclk_periph/hclk_periph/pclk_periph): %ld/%ld/%ld/%ld/%ld/%ld/%ld/%ld/%ld/%ld/%ld MHz",
               arm_pll_clk.rate / MHZ, ddr_pll_clk.rate / MHZ, codec_pll_clk.rate / MHZ, general_pll_clk.rate / MHZ, clk_core.rate / MHZ,
               aclk_cpu.rate / MHZ, hclk_cpu.rate / MHZ, pclk_cpu.rate / MHZ, aclk_periph.rate / MHZ, hclk_periph.rate / MHZ, pclk_periph.rate / MHZ);
-       printk(KERN_CONT " (20110725)\n");
+       printk(KERN_CONT " (20110729)\n");
 
        preset_lpj = loops_per_jiffy;
 }
 
 void __init rk29_clock_init(enum periph_pll ppll_rate)
 {
-       rk29_clock_init2(ppll_rate, codec_pll_445mhz, true);
+       rk29_clock_init2(ppll_rate, codec_pll_297mhz, true);
 }
 
 #ifdef CONFIG_PROC_FS
index 2e3dcfdc6230eeffb85132b1d1ce87c548b06cfb..2ec4d4c853a502cf6a84f979d61e968b63cf1b49 100755 (executable)
@@ -329,14 +329,13 @@ enum periph_pll {
 enum codec_pll {
        codec_pll_297mhz = 297000000, /* for HDMI */
        codec_pll_300mhz = 300000000,
-       codec_pll_445mhz = 445500000, /* for HDMI */
        codec_pll_504mhz = 504000000,
        codec_pll_552mhz = 552000000,
        codec_pll_594mhz = 594000000, /* for HDMI */
        codec_pll_600mhz = 600000000,
 };
 
-void __init rk29_clock_init(enum periph_pll ppll_rate); /* codec pll is 445.5MHz, has xin27m */
+void __init rk29_clock_init(enum periph_pll ppll_rate); /* codec pll is 297MHz, has xin27m */
 void __init rk29_clock_init2(enum periph_pll ppll_rate, enum codec_pll cpll_rate, bool has_xin27m);
 
 /* for USB detection */