Merge branch develop-3.10 into develop-3.10-next
authorHuang, Tao <huangtao@rock-chips.com>
Fri, 12 Dec 2014 06:12:56 +0000 (14:12 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Fri, 12 Dec 2014 06:12:56 +0000 (14:12 +0800)
1  2 
arch/arm/mach-rockchip/common.c
drivers/clk/rockchip/clk-pll.c

index 82b574275fc922739d4f0a319ef54f48e0a20c49,e2fa463f8c56a1ce065b94ac8dbd93ba5f8a5c22..a3d129a0a2728c9be80a85ce4a28e2d14ab37fea
  #include <linux/of_platform.h>
  #include <linux/of_fdt.h>
  #include <asm/cputype.h>
 +#ifdef CONFIG_CACHE_L2X0
  #include <asm/hardware/cache-l2x0.h>
 +#endif
  #include <linux/rockchip/common.h>
  #include <linux/rockchip/pmu.h>
+ #include <linux/memblock.h>
  #include "cpu_axi.h"
  #include "loader.h"
  #include "sram.h"
@@@ -104,7 -103,7 +105,7 @@@ static int __init rockchip_cpu_axi_init
                                iounmap(base);
                }
        }
 -      dsb();
 +      dsb(sy);
  
  #undef MAP
  
  }
  early_initcall(rockchip_cpu_axi_init);
  
 +#ifdef CONFIG_CACHE_L2X0
  static int __init rockchip_pl330_l2_cache_init(void)
  {
        struct device_node *np;
        return 0;
  }
  early_initcall(rockchip_pl330_l2_cache_init);
 +#endif
  
  struct gen_pool *rockchip_sram_pool = NULL;
  struct pie_chunk *rockchip_pie_chunk = NULL;
@@@ -298,3 -295,62 +299,62 @@@ static int __init rockchip_jtag_enable(
        return 1;
  }
  __setup("rockchip_jtag", rockchip_jtag_enable);
+ phys_addr_t uboot_logo_base=0;
+ phys_addr_t uboot_logo_size=0;
+ phys_addr_t uboot_logo_offset=0;
+ void __init rockchip_uboot_mem_reserve(void)
+ {
+       if (uboot_logo_size) {
+               if (!memblock_is_region_reserved(uboot_logo_base, uboot_logo_size)
+                       && !memblock_reserve(uboot_logo_base, uboot_logo_size)){
+                       pr_info("%s: reserve %zx@%zx for uboot logo\n", __func__,
+                               uboot_logo_size, uboot_logo_base);
+               } else {
+                       pr_err("%s: reserve of %zx@%zx failed\n", __func__,
+                              uboot_logo_size, uboot_logo_base);
+               }
+       }
+ }
+ static int __init rockchip_uboot_logo_setup(char *p)
+ {
+       char *endp;
+       uboot_logo_size = memparse(p, &endp);
+       if (*endp == '@') {
+               uboot_logo_base = memparse(endp + 1, &endp);
+               if (*endp == ':') {
+                       uboot_logo_offset = memparse(endp + 1, NULL);
+               }
+       }
+       pr_info("%s: mem: %zx@%zx, offset:%zx\n", __func__,
+               uboot_logo_size, uboot_logo_base, uboot_logo_offset);
+       return 0;
+ }
+ early_param("uboot_logo", rockchip_uboot_logo_setup);
+ static int __init rockchip_uboot_mem_late_init(void)
+ {
+       phys_addr_t addr = 0;
+       phys_addr_t end = 0;
+       if (uboot_logo_size) {
+               addr = PAGE_ALIGN(uboot_logo_base);
+               end = (uboot_logo_base+uboot_logo_size)&PAGE_MASK;
+               pr_info("%s: Freeing uboot logo memory: %zx@%zx\n", __func__,
+                       uboot_logo_size, uboot_logo_base);
+               memblock_free(uboot_logo_base, uboot_logo_size);
+               for (; addr < end; addr += PAGE_SIZE)
+                       free_reserved_page(pfn_to_page(addr >> PAGE_SHIFT));
+       }
+       return 0;
+ }
+ late_initcall(rockchip_uboot_mem_late_init);
index 760b54aca9750b19eb0a20166940cbd59df15d53,cdba78589c4cc686e25d0e117a78d1644c5b2682..776445b1b232aebed5b3db7220e47e9a4bd49f1a
@@@ -31,10 -31,8 +31,10 @@@ static const struct pll_clk_set rk3188p
        _RK3188PLUS_PLL_SET_CLKS(891000,        8,      594,    2),
        _RK3188PLUS_PLL_SET_CLKS(768000,        1,      64,     2),
        _RK3188PLUS_PLL_SET_CLKS(594000,        2,      198,    4),
 +      _RK3188PLUS_PLL_SET_CLKS(576000,        1,      48,     2),
        _RK3188PLUS_PLL_SET_CLKS(500000,        3,      250,    4),
        _RK3188PLUS_PLL_SET_CLKS(408000,        1,      68,     4),
 +      _RK3188PLUS_PLL_SET_CLKS(400000,        3,      200,    4),
        _RK3188PLUS_PLL_SET_CLKS(396000,        1,      66,     4),
        _RK3188PLUS_PLL_SET_CLKS(384000,        2,      128,    4),
        _RK3188PLUS_PLL_SET_CLKS(360000,        1,      60,     4),
@@@ -237,103 -235,12 +237,103 @@@ static const struct pll_clk_set rk312xp
        _RK3036_PLL_SET_CLKS(400000, 6, 400, 2, 2, 1, 0),
  };
  
 +static const struct apll_clk_set rk3368_apllb_table[] = {
 +                      /*(_mhz,        nr,     nf,     no,     aclkm,  atclk,  pclk_dbg)*/
 +      _RK3368_APLL_SET_CLKS(1608,     1,      67,     1,      2,      6,      6),
 +      _RK3368_APLL_SET_CLKS(1560,     1,      65,     1,      2,      6,      6),
 +      _RK3368_APLL_SET_CLKS(1512,     1,      63,     1,      2,      6,      6),
 +      _RK3368_APLL_SET_CLKS(1488,     1,      62,     1,      2,      5,      5),
 +      _RK3368_APLL_SET_CLKS(1464,     1,      61,     1,      2,      5,      5),
 +      _RK3368_APLL_SET_CLKS(1440,     1,      60,     1,      2,      5,      5),
 +      _RK3368_APLL_SET_CLKS(1416,     1,      59,     1,      2,      5,      5),
 +      _RK3368_APLL_SET_CLKS(1392,     1,      58,     1,      2,      5,      5),
 +      _RK3368_APLL_SET_CLKS(1368,     1,      57,     1,      2,      5,      5),
 +      _RK3368_APLL_SET_CLKS(1344,     1,      56,     1,      2,      5,      5),
 +      _RK3368_APLL_SET_CLKS(1320,     1,      55,     1,      2,      5,      5),
 +      _RK3368_APLL_SET_CLKS(1296,     1,      54,     1,      2,      5,      5),
 +      _RK3368_APLL_SET_CLKS(1272,     1,      53,     1,      2,      5,      5),
 +      _RK3368_APLL_SET_CLKS(1248,     1,      52,     1,      2,      5,      5),
 +      _RK3368_APLL_SET_CLKS(1224,     1,      51,     1,      2,      5,      5),
 +      _RK3368_APLL_SET_CLKS(1200,     1,      50,     1,      2,      4,      4),
 +      _RK3368_APLL_SET_CLKS(1176,     1,      49,     1,      2,      4,      4),
 +      _RK3368_APLL_SET_CLKS(1128,     1,      47,     1,      2,      4,      4),
 +      _RK3368_APLL_SET_CLKS(1104,     1,      46,     1,      2,      4,      4),
 +      _RK3368_APLL_SET_CLKS(1008,     1,      84,     2,      2,      4,      4),
 +      _RK3368_APLL_SET_CLKS(912,      1,      76,     2,      2,      4,      4),
 +      _RK3368_APLL_SET_CLKS(888,      1,      74,     2,      2,      3,      3),
 +      _RK3368_APLL_SET_CLKS(816,      1,      68,     2,      2,      3,      3),
 +      _RK3368_APLL_SET_CLKS(792,      1,      66,     2,      2,      3,      3),
 +      _RK3368_APLL_SET_CLKS(696,      1,      58,     2,      2,      3,      3),
 +      _RK3368_APLL_SET_CLKS(672,      1,      56,     2,      2,      3,      3),
 +      _RK3368_APLL_SET_CLKS(648,      1,      54,     2,      2,      3,      3),
 +      _RK3368_APLL_SET_CLKS(624,      1,      52,     2,      2,      3,      3),
 +      _RK3368_APLL_SET_CLKS(600,      1,      50,     2,      2,      2,      2),
 +      _RK3368_APLL_SET_CLKS(576,      1,      48,     2,      2,      2,      2),
 +      _RK3368_APLL_SET_CLKS(552,      1,      92,     4,      2,      2,      2),
 +      _RK3368_APLL_SET_CLKS(528,      1,      88,     4,      2,      2,      2),
 +      _RK3368_APLL_SET_CLKS(504,      1,      84,     4,      2,      2,      2),
 +      _RK3368_APLL_SET_CLKS(480,      1,      80,     4,      2,      2,      2),
 +      _RK3368_APLL_SET_CLKS(456,      1,      76,     4,      2,      2,      2),
 +      _RK3368_APLL_SET_CLKS(408,      1,      68,     4,      2,      2,      2),
 +      _RK3368_APLL_SET_CLKS(312,      1,      52,     4,      2,      2,      2),
 +      _RK3368_APLL_SET_CLKS(252,      1,      84,     8,      2,      1,      1),
 +      _RK3368_APLL_SET_CLKS(216,      1,      72,     8,      2,      1,      1),
 +      _RK3368_APLL_SET_CLKS(126,      2,      84,     8,      2,      1,      1),
 +      _RK3368_APLL_SET_CLKS(48,       2,      32,     8,      2,      1,      1),
 +      _RK3368_APLL_SET_CLKS(0,        1,      32,     16,     2,      1,      1),
 +};
 +
 +static const struct apll_clk_set rk3368_aplll_table[] = {
 +                      /*(_mhz,        nr,     nf,     no,     aclkm,  atclk,  pclk_dbg)*/
 +      _RK3368_APLL_SET_CLKS(1608,     1,      67,     1,      2,      7,      7),
 +      _RK3368_APLL_SET_CLKS(1560,     1,      65,     1,      2,      7,      7),
 +      _RK3368_APLL_SET_CLKS(1512,     1,      63,     1,      2,      7,      7),
 +      _RK3368_APLL_SET_CLKS(1488,     1,      62,     1,      2,      6,      6),
 +      _RK3368_APLL_SET_CLKS(1464,     1,      61,     1,      2,      6,      6),
 +      _RK3368_APLL_SET_CLKS(1440,     1,      60,     1,      2,      6,      6),
 +      _RK3368_APLL_SET_CLKS(1416,     1,      59,     1,      2,      6,      6),
 +      _RK3368_APLL_SET_CLKS(1392,     1,      58,     1,      2,      6,      6),
 +      _RK3368_APLL_SET_CLKS(1368,     1,      57,     1,      2,      6,      6),
 +      _RK3368_APLL_SET_CLKS(1344,     1,      56,     1,      2,      6,      6),
 +      _RK3368_APLL_SET_CLKS(1320,     1,      55,     1,      2,      6,      6),
 +      _RK3368_APLL_SET_CLKS(1296,     1,      54,     1,      2,      6,      6),
 +      _RK3368_APLL_SET_CLKS(1272,     1,      53,     1,      2,      6,      6),
 +      _RK3368_APLL_SET_CLKS(1248,     1,      52,     1,      2,      5,      5),
 +      _RK3368_APLL_SET_CLKS(1224,     1,      51,     1,      2,      5,      5),
 +      _RK3368_APLL_SET_CLKS(1200,     1,      50,     1,      2,      5,      5),
 +      _RK3368_APLL_SET_CLKS(1176,     1,      49,     1,      2,      5,      5),
 +      _RK3368_APLL_SET_CLKS(1128,     1,      47,     1,      2,      5,      5),
 +      _RK3368_APLL_SET_CLKS(1104,     1,      46,     1,      2,      5,      5),
 +      _RK3368_APLL_SET_CLKS(1008,     1,      84,     2,      2,      5,      5),
 +      _RK3368_APLL_SET_CLKS(912,      1,      76,     2,      2,      4,      4),
 +      _RK3368_APLL_SET_CLKS(888,      1,      74,     2,      2,      4,      4),
 +      _RK3368_APLL_SET_CLKS(816,      1,      68,     2,      2,      4,      4),
 +      _RK3368_APLL_SET_CLKS(792,      1,      66,     2,      2,      4,      4),
 +      _RK3368_APLL_SET_CLKS(696,      1,      58,     2,      2,      3,      3),
 +      _RK3368_APLL_SET_CLKS(672,      1,      56,     2,      2,      3,      3),
 +      _RK3368_APLL_SET_CLKS(648,      1,      54,     2,      2,      3,      3),
 +      _RK3368_APLL_SET_CLKS(624,      1,      52,     2,      2,      3,      3),
 +      _RK3368_APLL_SET_CLKS(600,      1,      50,     2,      2,      3,      3),
 +      _RK3368_APLL_SET_CLKS(576,      1,      48,     2,      2,      3,      3),
 +      _RK3368_APLL_SET_CLKS(552,      1,      92,     4,      2,      3,      3),
 +      _RK3368_APLL_SET_CLKS(528,      1,      88,     4,      2,      3,      3),
 +      _RK3368_APLL_SET_CLKS(504,      1,      84,     4,      2,      3,      3),
 +      _RK3368_APLL_SET_CLKS(480,      1,      80,     4,      2,      2,      2),
 +      _RK3368_APLL_SET_CLKS(456,      1,      76,     4,      2,      2,      2),
 +      _RK3368_APLL_SET_CLKS(408,      1,      68,     4,      2,      2,      2),
 +      _RK3368_APLL_SET_CLKS(312,      1,      52,     4,      2,      2,      2),
 +      _RK3368_APLL_SET_CLKS(252,      1,      84,     8,      2,      2,      2),
 +      _RK3368_APLL_SET_CLKS(216,      1,      72,     8,      2,      1,      1),
 +      _RK3368_APLL_SET_CLKS(126,      2,      84,     8,      2,      1,      1),
 +      _RK3368_APLL_SET_CLKS(48,       2,      32,     8,      2,      1,      1),
 +      _RK3368_APLL_SET_CLKS(0,        1,      32,     16,     2,      1,      1),
 +};
 +
  static void pll_wait_lock(struct clk_hw *hw)
  {
        struct clk_pll *pll = to_clk_pll(hw);
        int delay = 24000000;
  
 -
        while (delay > 0) {
                if (grf_readl(pll->status_offset) & (1 << pll->status_shift))
                        break;
@@@ -487,12 -394,12 +487,12 @@@ static int _pll_clk_set_rate_3188(struc
        cru_writel(_RK3188_PLL_MODE_SLOW_SET(pll->mode_shift), pll->mode_offset);
        //pll power down
        cru_writel((0x1 << (16+1)) | (0x1<<1), pll->reg + RK3188_PLL_CON(3));
 -      dsb();
 -      dsb();
 -      dsb();
 -      dsb();
 -      dsb();
 -      dsb();
 +      dsb(sy);
 +      dsb(sy);
 +      dsb(sy);
 +      dsb(sy);
 +      dsb(sy);
 +      dsb(sy);
        cru_writel(clk_set->pllcon0, pll->reg + RK3188_PLL_CON(0));
        cru_writel(clk_set->pllcon1, pll->reg + RK3188_PLL_CON(1));
  
@@@ -697,12 -604,12 +697,12 @@@ CHANGE_APLL
  
        /* PLL power down */
        cru_writel((0x1 << (16+1)) | (0x1<<1), pll->reg + RK3188_PLL_CON(3));
 -      dsb();
 -      dsb();
 -      dsb();
 -      dsb();
 -      dsb();
 -      dsb();
 +      dsb(sy);
 +      dsb(sy);
 +      dsb(sy);
 +      dsb(sy);
 +      dsb(sy);
 +      dsb(sy);
        cru_writel(ps->pllcon0, pll->reg + RK3188_PLL_CON(0));
        cru_writel(ps->pllcon1, pll->reg + RK3188_PLL_CON(1));
  
@@@ -1038,100 -945,89 +1038,89 @@@ static const struct clk_ops clk_pll_ops
  
  static u32 clk_gcd(u32 numerator, u32 denominator)
  {
-         u32 a, b;
-         if (!numerator || !denominator)
-                 return 0;
-         if (numerator > denominator) {
-                 a = numerator;
-                 b = denominator;
-         } else {
-                 a = denominator;
-                 b = numerator;
-         }
-         while (b != 0) {
-                 int r = b;
-                 b = a % b;
-                 a = r;
-         }
-         return a;
+       u32 a, b;
+       if (!numerator || !denominator)
+               return 0;
+       if (numerator > denominator) {
+               a = numerator;
+               b = denominator;
+       } else {
+               a = denominator;
+               b = numerator;
+       }
+       while (b != 0) {
+               int r = b;
+               b = a % b;
+               a = r;
+       }
+       return a;
  }
  
- /* FIXME: calc using u64 */
  static int pll_clk_get_best_set(unsigned long fin_hz, unsigned long fout_hz,
                                u32 *best_nr, u32 *best_nf, u32 *best_no)
  {
-         u32 nr, nf, no, nonr;
-         u32 nr_out, nf_out, no_out;
-         u32 n;
-         u32 YFfenzi;
-         u32 YFfenmu;
-         u64 fref, fvco, fout;
-         u32 gcd_val = 0;
-         nr_out = PLL_NR_MAX + 1;
-         no_out = 0;
- //    printk("pll_clk_get_set fin=%lu,fout=%lu\n", fin_hz, fout_hz);
-         if(!fin_hz || !fout_hz || fout_hz == fin_hz)
-                 return -EINVAL;
-         gcd_val = clk_gcd(fin_hz, fout_hz);
- //      printk("gcd_val = %d\n",gcd_val);
-         YFfenzi = fout_hz / gcd_val;
-         YFfenmu = fin_hz / gcd_val;
- //      printk("YFfenzi = %d, YFfenmu = %d\n",YFfenzi,YFfenmu);
-       for(n = 1;; n++) {
-              nf = YFfenzi * n;
-              nonr = YFfenmu * n;
-              if(nf > PLL_NF_MAX || nonr > (PLL_NO_MAX * PLL_NR_MAX))
-                      break;
-              for(no = 1; no <= PLL_NO_MAX; no++) {
-                      if(!(no == 1 || !(no % 2)))
-                              continue;
-                      if(nonr % no)
-                              continue;
-                      nr = nonr / no;
-                      if(nr > PLL_NR_MAX) //PLL_NR_MAX
-                              continue;
-                      fref = fin_hz / nr;
-                      if(fref < PLL_FREF_MIN || fref > PLL_FREF_MAX)
-                              continue;
-                      fvco = fref * nf;
-                      if(fvco < PLL_FVCO_MIN || fvco > PLL_FVCO_MAX)
-                              continue;
-                      fout = fvco / no;
-                      if(fout < PLL_FOUT_MIN || fout > PLL_FOUT_MAX)
-                              continue;
-                      /* output all available PLL settings */
-                      //printk("nr=%d,\tnf=%d,\tno=%d\n",nr,nf,no);
-                      //printk("_PLL_SET_CLKS(%lu,\t%d,\t%d,\t%d),\n",fout_hz/KHZ,nr,nf,no);
-                      /* select the best from all available PLL settings */
-                      if((nr < nr_out) || ((nr == nr_out)&&(no > no_out)))
-                      {
-                              nr_out = nr;
-                              nf_out = nf;
-                              no_out = no;
-                      }
-              }
-        }
-         /* output the best PLL setting */
-         if((nr_out <= PLL_NR_MAX) && (no_out > 0)){
-                 //printk("_PLL_SET_CLKS(%lu,\t%d,\t%d,\t%d),\n",fout_hz/KHZ,nr_out,nf_out,no_out);
-               if(best_nr && best_nf && best_no){
+       u32 nr, nf, no, nonr;
+       u32 nr_out, nf_out, no_out;
+       u32 n;
+       u32 YFfenzi;
+       u32 YFfenmu;
+       u64 fref, fvco, fout;
+       u32 gcd_val = 0;
+       nr_out = PLL_NR_MAX + 1;
+       no_out = 0;
+       if (!fin_hz || !fout_hz || fout_hz == fin_hz)
+               return -EINVAL;
+       gcd_val = clk_gcd(fin_hz, fout_hz);
+       YFfenzi = fout_hz / gcd_val;
+       YFfenmu = fin_hz / gcd_val;
+       for (n = 1;; n++) {
+               nf = YFfenzi * n;
+               nonr = YFfenmu * n;
+               if (nf > PLL_NF_MAX || nonr > (PLL_NO_MAX * PLL_NR_MAX))
+                       break;
+               for (no = 1; no <= PLL_NO_MAX; no++) {
+                       if (!(no == 1 || !(no % 2)))
+                               continue;
+                       if (nonr % no)
+                               continue;
+                       nr = nonr / no;
+                       if (nr > PLL_NR_MAX)
+                               continue;
+                       fref = fin_hz / nr;
+                       if (fref < PLL_FREF_MIN || fref > PLL_FREF_MAX)
+                               continue;
+                       fvco = fref * nf;
+                       if (fvco < PLL_FVCO_MIN || fvco > PLL_FVCO_MAX)
+                               continue;
+                       fout = fvco / no;
+                       if (fout < PLL_FOUT_MIN || fout > PLL_FOUT_MAX)
+                               continue;
+                       /* select the best from all available PLL settings */
+                       if ((no > no_out) || ((no == no_out) && (nr < nr_out))) {
+                               nr_out = nr;
+                               nf_out = nf;
+                               no_out = no;
+                       }
+               }
+       }
+       /* output the best PLL setting */
+       if ((nr_out <= PLL_NR_MAX) && (no_out > 0)) {
+               if (best_nr && best_nf && best_no) {
                        *best_nr = nr_out;
                        *best_nf = nf_out;
                        *best_no = no_out;
@@@ -1570,7 -1466,7 +1559,7 @@@ CHANGE_APLL
        /* reparent to apll, and set div to 1 */
        if (sel_gpll) {
                if (temp_div == 1) {
 -                      /* when rate/2 < (old_rate-arm_gpll_rate),
 +                      /* when rate/2 < (rate-arm_gpll_rate),
                           we can set div to make rate change more gently */
                        if (rate > (2*arm_gpll_rate)) {
                                cru_writel(RK3288_CORE_CLK_DIV(2), RK3288_CRU_CLKSELS_CON(0));
@@@ -1999,464 -1895,6 +1988,464 @@@ static const struct clk_ops clk_pll_ops
        .set_rate = clk_cpll_set_rate_312xplus,
  };
  
 +static long clk_pll_round_rate_3368_apllb(struct clk_hw *hw, unsigned long rate,
 +                                        unsigned long *prate)
 +{
 +      struct clk *parent = __clk_get_parent(hw->clk);
 +
 +      if (parent && (rate == __clk_get_rate(parent))) {
 +              clk_debug("pll %s round rate=%lu equal to parent rate\n",
 +                        __clk_get_name(hw->clk), rate);
 +              return rate;
 +      }
 +
 +      return (apll_get_best_set(rate, rk3368_apllb_table)->rate);
 +}
 +
 +/* 1: use, 0: no use */
 +#define RK3368_APLLB_USE_GPLL 1
 +
 +/* when define 1, we will set div to make rate change gently, but it will cost
 + more time */
 +#define RK3368_APLLB_DIV_MORE 1
 +
 +static int clk_pll_set_rate_3368_apllb(struct clk_hw *hw, unsigned long rate,
 +                                     unsigned long parent_rate)
 +{
 +      struct clk_pll *pll = to_clk_pll(hw);
 +      struct clk *clk = hw->clk;
 +      struct clk *arm_gpll = __clk_lookup("clk_gpll");
 +      unsigned long arm_gpll_rate, temp_rate, old_rate;
 +      const struct apll_clk_set *ps;
 +      u32 temp_div;
 +      unsigned long flags;
 +      int sel_gpll = 0;
 +
 +      ps = apll_get_best_set(rate, rk3368_apllb_table);
 +      clk_debug("apllb will set rate %lu\n", ps->rate);
 +      clk_debug("table con:%08x,%08x,%08x, sel:%08x,%08x\n",
 +                ps->pllcon0, ps->pllcon1, ps->pllcon2,
 +                ps->clksel0, ps->clksel1);
 +
 +#if !RK3368_APLLB_USE_GPLL
 +      goto CHANGE_APLL;
 +#endif
 +
 +      /* prepare arm_gpll before reparent clk_core to it */
 +      if (!arm_gpll) {
 +              clk_err("clk arm_gpll is NULL!\n");
 +              goto CHANGE_APLL;
 +      }
 +
 +      arm_gpll_rate = __clk_get_rate(arm_gpll);
 +      old_rate = __clk_get_rate(clk);
 +
 +      temp_rate = (old_rate > rate) ? old_rate : rate;
 +      temp_div = DIV_ROUND_UP(arm_gpll_rate, temp_rate);
 +
 +      if (temp_div > RK3368_CORE_CLK_MAX_DIV) {
 +              clk_debug("temp_div %d > max_div %d\n", temp_div,
 +                        RK3368_CORE_CLK_MAX_DIV);
 +              clk_debug("can't get rate %lu from arm_gpll rate %lu\n",
 +                        __clk_get_rate(clk), arm_gpll_rate);
 +              goto CHANGE_APLL;
 +      }
 +
 +#if 0
 +      if (clk_prepare(arm_gpll)) {
 +              clk_err("fail to prepare arm_gpll path\n");
 +              clk_unprepare(arm_gpll);
 +              goto CHANGE_APLL;
 +      }
 +
 +      if (clk_enable(arm_gpll)) {
 +              clk_err("fail to enable arm_gpll path\n");
 +              clk_disable(arm_gpll);
 +              clk_unprepare(arm_gpll);
 +              goto CHANGE_APLL;
 +      }
 +#endif
 +
 +      local_irq_save(flags);
 +
 +      if (rate >= old_rate) {
 +              cru_writel(ps->clksel0, RK3368_CRU_CLKSELS_CON(0));
 +              cru_writel(ps->clksel1, RK3368_CRU_CLKSELS_CON(1));
 +      }
 +
 +      /* select gpll */
 +#if RK3368_APLLB_DIV_MORE
 +      if (temp_div == 1) {
 +              /* when old_rate/2 < (old_rate-arm_gpll_rate),
 +                 we can set div to make rate change more gently */
 +              if (old_rate > (2*arm_gpll_rate)) {
 +                      cru_writel(RK3368_CORE_CLK_DIV(2), RK3368_CRU_CLKSELS_CON(0));
 +                      udelay(10);
 +                      cru_writel(RK3368_CORE_CLK_DIV(3), RK3368_CRU_CLKSELS_CON(0));
 +                      udelay(10);
 +                      cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_GPLL,
 +                                 RK3368_CRU_CLKSELS_CON(0));
 +                      udelay(10);
 +                      cru_writel(RK3368_CORE_CLK_DIV(2), RK3368_CRU_CLKSELS_CON(0));
 +                      udelay(10);
 +                      cru_writel(RK3368_CORE_CLK_DIV(1), RK3368_CRU_CLKSELS_CON(0));
 +              } else {
 +                      cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_GPLL,
 +                                 RK3368_CRU_CLKSELS_CON(0));
 +              }
 +      } else {
 +              cru_writel(RK3368_CORE_CLK_DIV(temp_div), RK3368_CRU_CLKSELS_CON(0));
 +              cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_GPLL,
 +                         RK3368_CRU_CLKSELS_CON(0));
 +      }
 +#else
 +      cru_writel(RK3368_CORE_CLK_DIV(temp_div), RK3368_CRU_CLKSELS_CON(0));
 +      cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_GPLL,
 +                 RK3368_CRU_CLKSELS_CON(0));
 +#endif
 +
 +      sel_gpll = 1;
 +
 +      smp_wmb();
 +
 +      local_irq_restore(flags);
 +
 +      clk_debug("temp select arm_gpll path, get rate %lu\n",
 +                arm_gpll_rate/temp_div);
 +      clk_debug("from arm_gpll rate %lu, temp_div %d\n", arm_gpll_rate,
 +                temp_div);
 +
 +CHANGE_APLL:
 +      local_irq_save(flags);
 +
 +      /* If core src don't select gpll, apll need to enter slow mode
 +       * before reset
 +       */
 +      if (!sel_gpll)
 +              cru_writel(_RK3188_PLL_MODE_SLOW_SET(pll->mode_shift),
 +                         pll->mode_offset);
 +
 +      /* PLL enter reset */
 +      cru_writel(_RK3188PLUS_PLL_RESET_SET(1), pll->reg + RK3188_PLL_CON(3));
 +
 +      cru_writel(ps->pllcon0, pll->reg + RK3188_PLL_CON(0));
 +      cru_writel(ps->pllcon1, pll->reg + RK3188_PLL_CON(1));
 +      cru_writel(ps->pllcon2, pll->reg + RK3188_PLL_CON(2));
 +
 +      udelay(5);
 +
 +      /* return from rest */
 +      cru_writel(_RK3188PLUS_PLL_RESET_SET(0), pll->reg + RK3188_PLL_CON(3));
 +
 +      /* wating lock state */
 +      udelay(ps->rst_dly);
 +      pll_wait_lock(hw);
 +
 +      /* PLL return from slow mode */
 +      if (!sel_gpll) {
 +              if (rate >= old_rate) {
 +                      cru_writel(ps->clksel0, RK3368_CRU_CLKSELS_CON(0));
 +                      cru_writel(ps->clksel1, RK3368_CRU_CLKSELS_CON(1));
 +              }
 +              cru_writel(_RK3188_PLL_MODE_NORM_SET(pll->mode_shift),
 +                         pll->mode_offset);
 +      }
 +
 +      /* reparent to apll, and set div to 1 */
 +      if (sel_gpll) {
 +#if RK3368_APLLB_DIV_MORE
 +              if (temp_div == 1) {
 +                      /* when rate/2 < (rate-arm_gpll_rate),
 +                       we can set div to make rate change more gently */
 +                      if (rate > (2*arm_gpll_rate)) {
 +                              cru_writel(RK3368_CORE_CLK_DIV(2), RK3368_CRU_CLKSELS_CON(0));
 +                              udelay(10);
 +                              cru_writel(RK3368_CORE_CLK_DIV(3), RK3368_CRU_CLKSELS_CON(0));
 +                              udelay(10);
 +                              cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_APLL,
 +                                         RK3368_CRU_CLKSELS_CON(0));
 +                              udelay(10);
 +                              cru_writel(RK3368_CORE_CLK_DIV(2), RK3368_CRU_CLKSELS_CON(0));
 +                              udelay(10);
 +                              cru_writel(RK3368_CORE_CLK_DIV(1), RK3368_CRU_CLKSELS_CON(0));
 +                      } else {
 +                              cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_APLL,
 +                                         RK3368_CRU_CLKSELS_CON(0));
 +                      }
 +              } else {
 +                      cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_APLL,
 +                                 RK3368_CRU_CLKSELS_CON(0));
 +                      cru_writel(RK3368_CORE_CLK_DIV(1), RK3368_CRU_CLKSELS_CON(0));
 +              }
 +#else
 +              cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_APLL,
 +                         RK3368_CRU_CLKSELS_CON(0));
 +              cru_writel(RK3368_CORE_CLK_DIV(1), RK3368_CRU_CLKSELS_CON(0));
 +#endif
 +      }
 +
 +      if (rate < old_rate) {
 +              cru_writel(ps->clksel0, RK3368_CRU_CLKSELS_CON(0));
 +              cru_writel(ps->clksel1, RK3368_CRU_CLKSELS_CON(1));
 +      }
 +
 +      smp_wmb();
 +
 +      local_irq_restore(flags);
 +
 +      if (sel_gpll) {
 +              sel_gpll = 0;
 +              /* clk_disable(arm_gpll);
 +              clk_unprepare(arm_gpll); */
 +      }
 +
 +      clk_debug("apll set rate %lu, con(%x,%x,%x,%x), sel(%x,%x)\n",
 +                ps->rate,
 +                cru_readl(pll->reg + RK3188_PLL_CON(0)),
 +                cru_readl(pll->reg + RK3188_PLL_CON(1)),
 +                cru_readl(pll->reg + RK3188_PLL_CON(2)),
 +                cru_readl(pll->reg + RK3188_PLL_CON(3)),
 +                cru_readl(RK3368_CRU_CLKSELS_CON(0)),
 +                cru_readl(RK3368_CRU_CLKSELS_CON(1)));
 +
 +      return 0;
 +}
 +
 +static const struct clk_ops clk_pll_ops_3368_apllb = {
 +      .recalc_rate = clk_pll_recalc_rate_3188plus,
 +      .round_rate = clk_pll_round_rate_3368_apllb,
 +      .set_rate = clk_pll_set_rate_3368_apllb,
 +};
 +
 +static long clk_pll_round_rate_3368_aplll(struct clk_hw *hw, unsigned long rate,
 +                                        unsigned long *prate)
 +{
 +      struct clk *parent = __clk_get_parent(hw->clk);
 +
 +      if (parent && (rate == __clk_get_rate(parent))) {
 +              clk_debug("pll %s round rate=%lu equal to parent rate\n",
 +                        __clk_get_name(hw->clk), rate);
 +              return rate;
 +      }
 +
 +      return (apll_get_best_set(rate, rk3368_aplll_table)->rate);
 +}
 +
 +/* 1: use, 0: no use */
 +#define RK3368_APLLL_USE_GPLL 1
 +
 +/* when define 1, we will set div to make rate change gently, but it will cost
 + more time */
 +#define RK3368_APLLL_DIV_MORE 1
 +
 +static int clk_pll_set_rate_3368_aplll(struct clk_hw *hw, unsigned long rate,
 +                                     unsigned long parent_rate)
 +{
 +      struct clk_pll *pll = to_clk_pll(hw);
 +      struct clk *clk = hw->clk;
 +      struct clk *arm_gpll = __clk_lookup("clk_gpll");
 +      unsigned long arm_gpll_rate, temp_rate, old_rate;
 +      const struct apll_clk_set *ps;
 +      u32 temp_div;
 +      unsigned long flags;
 +      int sel_gpll = 0;
 +
 +      ps = apll_get_best_set(rate, rk3368_aplll_table);
 +      clk_debug("aplll will set rate %lu\n", ps->rate);
 +      clk_debug("table con:%08x,%08x,%08x, sel:%08x,%08x\n",
 +                ps->pllcon0, ps->pllcon1, ps->pllcon2,
 +                ps->clksel0, ps->clksel1);
 +
 +#if !RK3368_APLLL_USE_GPLL
 +      goto CHANGE_APLL;
 +#endif
 +
 +      /* prepare arm_gpll before reparent clk_core to it */
 +      if (!arm_gpll) {
 +              clk_err("clk arm_gpll is NULL!\n");
 +              goto CHANGE_APLL;
 +      }
 +
 +      arm_gpll_rate = __clk_get_rate(arm_gpll);
 +      old_rate = __clk_get_rate(clk);
 +
 +      temp_rate = (old_rate > rate) ? old_rate : rate;
 +      temp_div = DIV_ROUND_UP(arm_gpll_rate, temp_rate);
 +
 +      if (temp_div > RK3368_CORE_CLK_MAX_DIV) {
 +              clk_debug("temp_div %d > max_div %d\n", temp_div,
 +                        RK3368_CORE_CLK_MAX_DIV);
 +              clk_debug("can't get rate %lu from arm_gpll rate %lu\n",
 +                        __clk_get_rate(clk), arm_gpll_rate);
 +              goto CHANGE_APLL;
 +      }
 +
 +#if 0
 +      if (clk_prepare(arm_gpll)) {
 +              clk_err("fail to prepare arm_gpll path\n");
 +              clk_unprepare(arm_gpll);
 +              goto CHANGE_APLL;
 +      }
 +
 +      if (clk_enable(arm_gpll)) {
 +              clk_err("fail to enable arm_gpll path\n");
 +              clk_disable(arm_gpll);
 +              clk_unprepare(arm_gpll);
 +              goto CHANGE_APLL;
 +      }
 +#endif
 +
 +      local_irq_save(flags);
 +
 +      if (rate >= old_rate) {
 +              cru_writel(ps->clksel0, RK3368_CRU_CLKSELS_CON(2));
 +              cru_writel(ps->clksel1, RK3368_CRU_CLKSELS_CON(3));
 +      }
 +
 +      /* select gpll */
 +#if RK3368_APLLL_DIV_MORE
 +      if (temp_div == 1) {
 +              /* when old_rate/2 < (old_rate-arm_gpll_rate),
 +                 we can set div to make rate change more gently */
 +              if (old_rate > (2*arm_gpll_rate)) {
 +                      cru_writel(RK3368_CORE_CLK_DIV(2), RK3368_CRU_CLKSELS_CON(2));
 +                      udelay(10);
 +                      cru_writel(RK3368_CORE_CLK_DIV(3), RK3368_CRU_CLKSELS_CON(2));
 +                      udelay(10);
 +                      cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_GPLL,
 +                                 RK3368_CRU_CLKSELS_CON(2));
 +                      udelay(10);
 +                      cru_writel(RK3368_CORE_CLK_DIV(2), RK3368_CRU_CLKSELS_CON(2));
 +                      udelay(10);
 +                      cru_writel(RK3368_CORE_CLK_DIV(1), RK3368_CRU_CLKSELS_CON(2));
 +              } else {
 +                      cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_GPLL,
 +                                 RK3368_CRU_CLKSELS_CON(2));
 +              }
 +      } else {
 +              cru_writel(RK3368_CORE_CLK_DIV(temp_div), RK3368_CRU_CLKSELS_CON(2));
 +              cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_GPLL,
 +                         RK3368_CRU_CLKSELS_CON(2));
 +      }
 +#else
 +              cru_writel(RK3368_CORE_CLK_DIV(temp_div), RK3368_CRU_CLKSELS_CON(2));
 +              cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_GPLL,
 +                         RK3368_CRU_CLKSELS_CON(2));
 +#endif
 +
 +      sel_gpll = 1;
 +
 +      smp_wmb();
 +
 +      local_irq_restore(flags);
 +
 +      clk_debug("temp select arm_gpll path, get rate %lu\n",
 +                arm_gpll_rate/temp_div);
 +      clk_debug("from arm_gpll rate %lu, temp_div %d\n", arm_gpll_rate,
 +                temp_div);
 +
 +CHANGE_APLL:
 +      local_irq_save(flags);
 +
 +      /* If core src don't select gpll, apll need to enter slow mode
 +       * before reset
 +       */
 +      if (!sel_gpll)
 +              cru_writel(_RK3188_PLL_MODE_SLOW_SET(pll->mode_shift),
 +                         pll->mode_offset);
 +
 +      /* PLL enter reset */
 +      cru_writel(_RK3188PLUS_PLL_RESET_SET(1), pll->reg + RK3188_PLL_CON(3));
 +
 +      cru_writel(ps->pllcon0, pll->reg + RK3188_PLL_CON(0));
 +      cru_writel(ps->pllcon1, pll->reg + RK3188_PLL_CON(1));
 +      cru_writel(ps->pllcon2, pll->reg + RK3188_PLL_CON(2));
 +
 +      udelay(5);
 +
 +      /* return from rest */
 +      cru_writel(_RK3188PLUS_PLL_RESET_SET(0), pll->reg + RK3188_PLL_CON(3));
 +
 +      /* wating lock state */
 +      udelay(ps->rst_dly);
 +      pll_wait_lock(hw);
 +
 +      /* PLL return from slow mode */
 +      if (!sel_gpll) {
 +              if (rate >= old_rate) {
 +                      cru_writel(ps->clksel0, RK3368_CRU_CLKSELS_CON(2));
 +                      cru_writel(ps->clksel1, RK3368_CRU_CLKSELS_CON(3));
 +              }
 +              cru_writel(_RK3188_PLL_MODE_NORM_SET(pll->mode_shift),
 +                         pll->mode_offset);
 +      }
 +
 +      /* reparent to apll, and set div to 1 */
 +      if (sel_gpll) {
 +#if RK3368_APLLL_DIV_MORE
 +              if (temp_div == 1) {
 +                      /* when rate/2 < (rate-arm_gpll_rate),
 +                       we can set div to make rate change more gently */
 +                      if (rate > (2*arm_gpll_rate)) {
 +                              cru_writel(RK3368_CORE_CLK_DIV(2), RK3368_CRU_CLKSELS_CON(2));
 +                              udelay(10);
 +                              cru_writel(RK3368_CORE_CLK_DIV(3), RK3368_CRU_CLKSELS_CON(2));
 +                              udelay(10);
 +                              cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_APLL,
 +                                         RK3368_CRU_CLKSELS_CON(2));
 +                              udelay(10);
 +                              cru_writel(RK3368_CORE_CLK_DIV(2), RK3368_CRU_CLKSELS_CON(2));
 +                              udelay(10);
 +                              cru_writel(RK3368_CORE_CLK_DIV(1), RK3368_CRU_CLKSELS_CON(2));
 +                      } else {
 +                              cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_APLL,
 +                                         RK3368_CRU_CLKSELS_CON(2));
 +                      }
 +              } else {
 +                      cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_APLL,
 +                                 RK3368_CRU_CLKSELS_CON(2));
 +                      cru_writel(RK3368_CORE_CLK_DIV(1), RK3368_CRU_CLKSELS_CON(2));
 +              }
 +#else
 +              cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_APLL,
 +                         RK3368_CRU_CLKSELS_CON(2));
 +              cru_writel(RK3368_CORE_CLK_DIV(1), RK3368_CRU_CLKSELS_CON(2));
 +#endif
 +      }
 +
 +      if (rate < old_rate) {
 +              cru_writel(ps->clksel0, RK3368_CRU_CLKSELS_CON(2));
 +              cru_writel(ps->clksel1, RK3368_CRU_CLKSELS_CON(3));
 +      }
 +
 +      smp_wmb();
 +
 +      local_irq_restore(flags);
 +
 +      if (sel_gpll) {
 +              sel_gpll = 0;
 +              /* clk_disable(arm_gpll);
 +              clk_unprepare(arm_gpll); */
 +      }
 +
 +      clk_debug("apll set rate %lu, con(%x,%x,%x,%x), sel(%x,%x)\n",
 +                ps->rate,
 +                cru_readl(pll->reg + RK3188_PLL_CON(0)),
 +                cru_readl(pll->reg + RK3188_PLL_CON(1)),
 +                cru_readl(pll->reg + RK3188_PLL_CON(2)),
 +                cru_readl(pll->reg + RK3188_PLL_CON(3)),
 +                cru_readl(RK3368_CRU_CLKSELS_CON(2)),
 +                cru_readl(RK3368_CRU_CLKSELS_CON(3)));
 +
 +      return 0;
 +}
 +
 +static const struct clk_ops clk_pll_ops_3368_aplll = {
 +      .recalc_rate = clk_pll_recalc_rate_3188plus,
 +      .round_rate = clk_pll_round_rate_3368_aplll,
 +      .set_rate = clk_pll_set_rate_3368_aplll,
 +};
 +
  const struct clk_ops *rk_get_pll_ops(u32 pll_flags)
  {
        switch (pll_flags) {
                case CLK_PLL_312XPLUS:
                        return &clk_pll_ops_312xplus;
  
 +              case CLK_PLL_3368_APLLB:
 +                      return &clk_pll_ops_3368_apllb;
 +
 +              case CLK_PLL_3368_APLLL:
 +                      return &clk_pll_ops_3368_aplll;
 +
                default:
                        clk_err("%s: unknown pll_flags!\n", __func__);
                        return NULL;