rk3036:clk:support set pll clks and init clocks
author张晴 <zhangqing@rock-chips.com>
Mon, 7 Jul 2014 06:06:37 +0000 (14:06 +0800)
committer张晴 <zhangqing@rock-chips.com>
Mon, 7 Jul 2014 06:06:37 +0000 (14:06 +0800)
arch/arm/boot/dts/rk3036-clocks.dtsi [changed mode: 0644->0755]
arch/arm/boot/dts/rk3036.dtsi
drivers/clk/rockchip/clk-pll.c [changed mode: 0644->0755]
drivers/clk/rockchip/clk-pll.h [changed mode: 0644->0755]

old mode 100644 (file)
new mode 100755 (executable)
index 6464739..8e98257
                                #clock-cells = <0>;
                        };
 
+                       jtag_tck: jtag_tck {
+                               compatible = "rockchip,rk-fixed-clock";
+                               clock-output-names = "jtag_tck";
+                               clock-frequency = <0>;
+                               #clock-cells = <0>;
+                       };
+
                        dummy: dummy {
                                compatible = "rockchip,rk-fixed-clock";
                                clock-output-names = "dummy";
                                        aclk_cpu_pre: aclk_cpu_pre_mux {
                                                compatible = "rockchip,rk3188-mux-con";
                                                rockchip,bits = <14 2>;
-                                               clocks = <&clk_apll>, <&clk_gates10 8>,<&clk_gates0 1>;
+                                               clocks = <&clk_apll>, <&clk_dpll>,<&clk_gpll>;
                                                clock-output-names = "aclk_cpu_pre";
                                                #clock-cells = <0>;
                                                #clock-init-cells = <1>;
                                                clocks = <&clk_apll>,<&clk_dpll>, <&clk_gpll>, <&usb_480m>;
                                                clock-output-names = "clk_uart_pll";
                                                #clock-cells = <0>;
+                                               #clock-init-cells = <1>;
                                        };
 
                                        /* reg[15:12]: reserved */
                                                clocks = <&clk_apll>, <&clk_dpll>, <&clk_gpll>;
                                                clock-output-names = "clk_hevc_core";
                                                #clock-cells = <0>;
+                                               #clock-init-cells = <1>;
                                        };
 
                                        clk_hevc_core_div: clk_hevc_core_div {
                                                clock-output-names = "clk_mac";
                                                rockchip,div-type = <CLK_DIVIDER_PLUS_ONE>;
                                                #clock-cells = <0>;
+                                               #clock-init-cells = <1>;
                                        };
 
                                        /* reg[15:14]: reserved */
                                                clocks = <&clk_apll>, <&clk_dpll>, <&clk_gpll>;
                                                clock-output-names = "dclk_lcdc1";
                                                #clock-cells = <0>;
+                                               #clock-init-cells = <1>;
                                        };
 
                                        /* reg[7:2]: reserved */
                                                rockchip,div-type = <CLK_DIVIDER_PLUS_ONE>;
                                                #clock-cells = <0>;
                                                rockchip,clkops-idx =
-                                                       <CLKOPS_RATE_RK3288_DCLK_LCDC0>;
-                                               rockchip,flags = <CLK_SET_RATE_PARENT>;
+                                                       <CLKOPS_RATE_MUX_DIV>;
+                                               rockchip,flags = <CLK_SET_RATE_NO_REPARENT>;
                                        };
                                };
 
                                        clk_gpu_pre: clk_gpu_pre_mux {
                                                compatible = "rockchip,rk3188-mux-con";
                                                rockchip,bits = <8 2>;
-                                               clocks = <&clk_apll>, <&clk_dpll>, <&clk_gpll>;
+                                               clocks = <&dummy>, <&clk_dpll>, <&clk_gpll>;
                                                clock-output-names = "clk_gpu_pre";
                                                #clock-cells = <0>;
                                                #clock-init-cells = <1>;
                                                <&clk_i2s>,             <&dummy>;
 
                                        clock-output-names =
-                                               "clk_core_pre",                 "reserved",      /* do not use bit1 = "cpu_gpll" */
+                                               "pclk_dbg",                     "reserved",      /* do not use bit1 = "cpu_gpll" */
                                                "reserved",             "aclk_cpu_pre",
 
                                                "hclk_cpu_pre",         "pclk_cpu_pre",
                                        reg = <0x00d4 0x4>;
                                        clocks =
                                                <&clk_timer0>,          <&clk_timer1>,
-                                               <&dummy>,               <&dummy>,
+                                               <&dummy>,               <&jtag_tck>,
 
                                                <&aclk_vio_pre>,                <&xin12m>,
                                                <&dummy>,               <&dummy>,
                                                "reserved",             "reserved",
 
                                                "reserved",             "g_hclk_usb_peri",
-                                               "g_hclk_peri_arbi",             "g_aclk_peri_niu";
+                                               "g_hclk_pe_arbi",               "g_aclk_peri_niu";
 
                                        rockchip,suspend-clkgating-setting=<0x0 0x0>;
 
 
                                        clock-output-names =
                                                "g_clk_pvtm_core",              "g_clk_pvtm_gpu",
-                                               "g_clk_pvtm_video",             "reserved",
+                                               "g_pvtm_video",         "reserved",
 
                                                "clk_nandc",            "clk_sfc",
                                                "clk_hevc_core",                "reserved",
index fcc04c0584a1e7157807a6401fcd87e428b3b379..b7ddf761a0f114d809cbc244e7f63eb72863db19 100755 (executable)
                status = "disabled";
        };
 
+       clocks-init{
+               compatible = "rockchip,clocks-init";
+               rockchip,clocks-init-parent =
+                       <&clk_core_pre &clk_apll>, <&aclk_cpu_pre &clk_gpll>,
+                       <&aclk_peri_pre &clk_gpll>, <&clk_uart_pll &clk_gpll>,  
+                       <&clk_i2s_pll &clk_gpll>, <&clk_spdif_pll &clk_gpll>;
+               rockchip,clocks-init-rate =
+                       <&clk_core_pre 1464000000>, <&clk_gpll 297000000>,
+                       <&aclk_cpu_pre 300000000>, <&hclk_cpu_pre 150000000>,   
+                       <&pclk_cpu_pre 75000000>,        <&aclk_peri_pre 300000000>,
+                       <&hclk_peri_pre 150000000>, <&pclk_peri_pre 75000000>,
+                       <&clk_gpu_pre 200000000>,        <&aclk_vio_pre 300000000>,
+                       <&hclk_vio_pre 150000000>,       <&aclk_vcodec_pre 400000000>,
+                       <&clk_hevc_core 300000000>,  <&clk_mac_ref_div 125000000>;
+       /*      rockchip,clocks-uboot-has-init =
+                       <&aclk_vio1>;*/
+       };
+
+       clocks-enable {
+               compatible = "rockchip,clocks-enable";
+               clocks =
+                               /*PD_CORE*/
+                               <&clk_gates0 0>, <&clk_gates0 7>,
+
+                               /*PD_CPU*/
+                               <&clk_gates0 3>, <&clk_gates0 4>,
+                               <&clk_gates0 5>,
+
+                               /*TIMER*/
+                               <&clk_gates1 0>, <&clk_gates1 1>,
+                               <&clk_gates2 4>, <&clk_gates2 5>,
+
+                               /*PD_PERI*/
+                               <&clk_gates2 0>, <&hclk_peri_pre>,
+                               <&pclk_peri_pre>, <&clk_gates2 1>,
+
+                               /*aclk_cpu_pre*/
+                               <&clk_gates4 12>,/*aclk_intmem*/
+                               <&clk_gates4 10>,/*aclk_strc_sys*/
+                       
+                               /*hclk_cpu_pre*/
+                               <&clk_gates5 6>,/*hclk_rom*/
+
+                               /*pclk_cpu_pre*/
+                               <&clk_gates5 4>,/*pclk_grf*/
+                               <&clk_gates5 7>,/*pclk_ddrupctl*/
+                               <&clk_gates5 14>,/*pclk_acodec*/
+                               <&clk_gates3 8>,/*pclk_hdmi*/
+
+                               /*aclk_peri_pre*/
+                               <&clk_gates4 3>,/*aclk_peri_axi_matrix*/
+                               <&clk_gates5 1>,/*aclk_dmac2*/
+                               <&clk_gates9 15>,/*aclk_peri_niu*/
+                               <&clk_gates4 2>,/*aclk_cpu_peri*/
+                               
+                               /*hclk_peri_pre*/
+                               <&clk_gates4 0>,/*hclk_peri_matrix*/
+                               <&clk_gates9 13>,/*hclk_usb_peri*/
+                               <&clk_gates9 14>,/*hclk_peri_arbi*/     
+
+                               /*pclk_peri_pre*/
+                               <&clk_gates4 1>,/*pclk_peri_axi_matrix*/
+
+                               /*hclk_vio_pre*/
+                               <&clk_gates6 12>,/*hclk_vio_bus*/
+                               <&clk_gates9 5>,/*hclk_lcdc*/
+
+                               /*aclk_vio_pre*/
+                               <&clk_gates6 13>,/*aclk_vio*/
+                               <&clk_gates9 6>,/*aclk_lcdc*/
+
+                               /*UART*/
+                               <&clk_gates1 12>,
+                               <&clk_gates1 13>,
+                               <&clk_gates8 2>,/*pclk_uart2*/
+
+                               /*jtag*/
+                               <&clk_gates1 3>;/*clk_jtag*/
+       };
+
        i2c0: i2c@20072000 {
                compatible = "rockchip,rk30-i2c";
                reg = <0x20072000 0x1000>;
old mode 100644 (file)
new mode 100755 (executable)
index 2f54724..d1dcfa2
@@ -170,6 +170,50 @@ static const struct apll_clk_set rk3288_apll_table[] = {
        _RK3288_APLL_SET_CLKS(0,        1,      32,     16,     2,      2,      4,      4,      4),
 };
 
+static const struct apll_clk_set rk3036_apll_table[] = {
+       _RK3036_APLL_SET_CLKS(1608, 1, 67, 1, 1, 1, 0, 81, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(1584, 1, 66, 1, 1, 1, 0, 81, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(1560, 1, 65, 1, 1, 1, 0, 81, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(1536, 1, 64, 1, 1, 1, 0, 81, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(1512, 1, 63, 1, 1, 1, 0, 81, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(1488, 1, 62, 1, 1, 1, 0, 81, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(1464, 1, 61, 1, 1, 1, 0, 81, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(1440, 1, 60, 1, 1, 1, 0, 41, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(1416, 1, 59, 1, 1, 1, 0, 41, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(1392, 1, 58, 1, 1, 1, 0, 41, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(1368, 1, 57, 1, 1, 1, 0, 41, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(1344, 1, 56, 1, 1, 1, 0, 41, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(1320, 1, 55, 1, 1, 1, 0, 41, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(1296, 1, 54, 1, 1, 1, 0, 41, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(1272, 1, 53, 1, 1, 1, 0, 41, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(1248, 1, 52, 1, 1, 1, 0, 41, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(1200, 1, 50, 1, 1, 1, 0, 41, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(1104, 1, 46, 1, 1, 1, 0, 41, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(1008, 1, 84, 2, 1, 1, 0, 41, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(984, 1, 82, 2, 1, 1, 0, 41, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(960, 1, 80, 2, 1, 1, 0, 41, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(936, 1, 78, 2, 1, 1, 0, 41, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(912, 1, 76, 2, 1, 1, 0, 41, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(888, 1, 74, 2, 1, 1, 0, 41, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(864, 1, 72, 2, 1, 1, 0, 41, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(840, 1, 70, 2, 1, 1, 0, 41, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(816, 1, 68, 2, 1, 1, 0, 41, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(696, 1, 58, 2, 1, 1, 0, 41, 41, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(600, 1, 75, 3, 1, 1, 0, 41, 21, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(504, 1, 63, 3, 1, 1, 0, 41, 21, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(408, 1, 68, 2, 2, 1, 0, 41, 21, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(312, 1, 52, 2, 2, 1, 0, 41, 21, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(216, 1, 72, 4, 2, 1, 0, 41, 21, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(96, 1, 64, 4, 4, 1, 0, 21, 21, 41, 21, 21),
+       _RK3036_APLL_SET_CLKS(0, 1, 0, 1, 1, 1, 0, 21, 21, 41, 21, 21),
+};
+
+static const struct pll_clk_set rk3036plus_pll_com_table[] = {
+       _RK3036_PLL_SET_CLKS(297000, 2, 99, 4, 1, 1, 0),
+       _RK3036_PLL_SET_CLKS(768000, 1, 32, 1, 1, 1, 0),
+
+};
+
 static void pll_wait_lock(struct clk_hw *hw)
 {
        struct clk_pll *pll = to_clk_pll(hw);
@@ -197,6 +241,33 @@ static void pll_wait_lock(struct clk_hw *hw)
        }
 }
 
+static void rk3036_pll_wait_lock(struct clk_hw *hw)
+{
+       struct clk_pll *pll = to_clk_pll(hw);
+       int delay = 24000000;
+
+
+       while (delay > 0) {
+               if (cru_readl(pll->status_offset) & (1 << pll->status_shift))
+                       break;
+               delay--;
+       }
+
+       if (delay == 0) {
+               clk_err("pll %s: can't lock! status_shift=%u\n"
+                               "pll_con0=%08x\npll_con1=%08x\n"
+                               "pll_con2=%08x\n",
+                               __clk_get_name(hw->clk),
+                               pll->status_shift,
+                               cru_readl(pll->reg + RK3188_PLL_CON(0)),
+                               cru_readl(pll->reg + RK3188_PLL_CON(1)),
+                               cru_readl(pll->reg + RK3188_PLL_CON(2)));
+               while (1);
+
+       }
+}
+
+
 /* get rate that is most close to target */
 static const struct apll_clk_set *apll_get_best_set(unsigned long rate,
                const struct apll_clk_set *table)
@@ -1340,7 +1411,292 @@ static const struct clk_ops clk_pll_ops_3288_apll = {
        .set_rate = clk_pll_set_rate_3288_apll,
 };
 
+/* CLK_PLL_3036_APLL type ops */
+#define FRAC_MODE      0
+static unsigned long rk3036_pll_clk_recalc(struct clk_hw *hw,
+unsigned long parent_rate)
+{
+       struct clk_pll *pll = to_clk_pll(hw);
+       unsigned long rate;
+       unsigned int dsmp = 0;
+       u64 rate64 = 0, frac_rate64 = 0;
+
+       dsmp = RK3036_PLL_GET_DSMPD(cru_readl(pll->reg + RK3188_PLL_CON(1)));
+
+       if (_RK3188_PLL_MODE_IS_NORM(pll->mode_offset, pll->mode_shift)) {
+               u32 pll_con0 = cru_readl(pll->reg + RK3188_PLL_CON(0));
+               u32 pll_con1 = cru_readl(pll->reg + RK3188_PLL_CON(1));
+               u32 pll_con2 = cru_readl(pll->reg + RK3188_PLL_CON(2));
+               /*integer mode*/
+               rate64 = (u64)parent_rate * RK3036_PLL_GET_FBDIV(pll_con0);
+               do_div(rate64, RK3036_PLL_GET_REFDIV(pll_con1));
+
+               if (FRAC_MODE == dsmp) {
+                       /*fractional mode*/
+                       frac_rate64 = (u64)parent_rate
+                       * RK3036_PLL_GET_FRAC(pll_con2);
+                       do_div(frac_rate64, RK3036_PLL_GET_REFDIV(pll_con1));
+                       rate64 += frac_rate64 >> 24;
+                       clk_debug("%s frac_rate=%llu(%08x/2^24) by pass mode\n",
+                                       __func__, frac_rate64 >> 24,
+                                       RK3036_PLL_GET_FRAC(pll_con2));
+               }
+               do_div(rate64, RK3036_PLL_GET_POSTDIV1(pll_con0));
+               do_div(rate64, RK3036_PLL_GET_POSTDIV2(pll_con1));
+
+               rate = rate64;
+               } else {
+               rate = parent_rate;
+               clk_debug("pll_clk_recalc rate=%lu by pass mode\n", rate);
+       }
+       return rate;
+}
+
+static unsigned long clk_pll_recalc_rate_3036_apll(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       return rk3036_pll_clk_recalc(hw, parent_rate);
+}
+
+static long clk_pll_round_rate_3036_apll(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, rk3036_apll_table)->rate);
+}
+
+static  int rk3036_pll_clk_set_rate(struct pll_clk_set *clk_set,
+       struct clk_hw *hw)
+{
+       struct clk_pll *pll = to_clk_pll(hw);
+
+       /*enter slowmode*/
+       cru_writel(_RK3188_PLL_MODE_SLOW_SET(pll->mode_shift),
+       pll->mode_offset);
+
+       cru_writel(clk_set->pllcon0,  pll->reg + RK3188_PLL_CON(0));
+       cru_writel(clk_set->pllcon1,  pll->reg + RK3188_PLL_CON(1));
+       cru_writel(clk_set->pllcon2,  pll->reg + RK3188_PLL_CON(2));
+
+       clk_debug("pllcon0%08x\n", cru_readl(pll->reg + RK3188_PLL_CON(0)));
+       clk_debug("pllcon1%08x\n", cru_readl(pll->reg + RK3188_PLL_CON(1)));
+       clk_debug("pllcon2%08x\n", cru_readl(pll->reg + RK3188_PLL_CON(2)));
+       /*wating lock state*/
+       udelay(clk_set->rst_dly);
+       rk3036_pll_wait_lock(hw);
+
+       /*return form slow*/
+       cru_writel(_RK3188_PLL_MODE_NORM_SET(pll->mode_shift),
+       pll->mode_offset);
+
+       return 0;
+}
+
+#define MIN_FOUTVCO_FREQ       (400 * 1000 * 1000)
+#define MAX_FOUTVCO_FREQ       (1600 * 1000 * 1000)
+static int rk3036_pll_clk_set_postdiv(unsigned long fout_hz,
+u32 *postdiv1, u32 *postdiv2, u32 *foutvco)
+{
+       if (fout_hz < MIN_FOUTVCO_FREQ) {
+               for (*postdiv1 = 1; *postdiv1 <= 7; (*postdiv1)++)
+                       for (*postdiv2 = 1; *postdiv2 <= 7; (*postdiv2)++) {
+                               if (fout_hz * (*postdiv1) * (*postdiv2)
+                                       >= MIN_FOUTVCO_FREQ && fout_hz
+                                       * (*postdiv1) * (*postdiv2)
+                                       <= MAX_FOUTVCO_FREQ) {
+                                       *foutvco = fout_hz * (*postdiv1)
+                                               * (*postdiv2);
+                                       return 0;
+                               }
+                       }
+               clk_debug("CANNOT FINE postdiv1/2 to make fout in range from 400M to 1600M, fout = %lu\n",
+                               fout_hz);
+       } else {
+               *postdiv1 = 1;
+               *postdiv2 = 1;
+       }
+       return 0;
+}
+
+static int rk3036_pll_clk_get_set(unsigned long fin_hz, unsigned long fout_hz,
+               u32 *refdiv, u32 *fbdiv, u32 *postdiv1,
+               u32 *postdiv2, u32 *frac)
+{
+       /* FIXME set postdiv1/2 always 1*/
+       u32 gcd, foutvco = fout_hz;
+       u64 fin_64, frac_64;
+       u32 f_frac;
+
+       if (!fin_hz || !fout_hz || fout_hz == fin_hz)
+               return -1;
+
+       rk3036_pll_clk_set_postdiv(fout_hz, postdiv1, postdiv2, &foutvco);
+       if (fin_hz / MHZ * MHZ == fin_hz && fout_hz / MHZ * MHZ == fout_hz) {
+               fin_hz /= MHZ;
+               foutvco /= MHZ;
+               gcd = clk_gcd(fin_hz, foutvco);
+               *refdiv = fin_hz / gcd;
+               *fbdiv = foutvco / gcd;
+
+               *frac = 0;
+
+               clk_debug("fin=%lu,fout=%lu,gcd=%u,refdiv=%u,fbdiv=%u,postdiv1=%u,postdiv2=%u,frac=%u\n",
+                       fin_hz, fout_hz, gcd, *refdiv, *fbdiv, *postdiv1, *postdiv2, *frac);
+       } else {
+               clk_debug("******frac div running, fin_hz=%lu, fout_hz=%lu,fin_INT_mhz=%lu, fout_INT_mhz=%lu\n",
+                       fin_hz, fout_hz, fin_hz / MHZ * MHZ, fout_hz / MHZ * MHZ);
+               clk_debug("******frac get postdiv1=%u, postdiv2=%u,foutvco=%u\n",
+                       *postdiv1, *postdiv2, foutvco);
+               gcd = clk_gcd(fin_hz / MHZ, foutvco / MHZ);
+               *refdiv = fin_hz / MHZ / gcd;
+               *fbdiv = foutvco / MHZ / gcd;
+               clk_debug("******frac get refdiv=%u, fbdiv=%u\n", *refdiv, *fbdiv);
+
+               *frac = 0;
+
+               f_frac = (foutvco % MHZ);
+               fin_64 = fin_hz;
+               do_div(fin_64, (u64)*refdiv);
+               frac_64 = (u64)f_frac << 24;
+               do_div(frac_64, fin_64);
+               *frac = (u32) frac_64;
+               clk_debug("frac=%x\n", *frac);
+       }
+       return 0;
+}
+static int rk3036_pll_set_con(struct clk_hw *hw, u32 refdiv, u32 fbdiv, u32 postdiv1, u32 postdiv2, u32 frac)
+{
+       struct pll_clk_set temp_clk_set;
+       temp_clk_set.pllcon0 = RK3036_PLL_SET_FBDIV(fbdiv) | RK3036_PLL_SET_POSTDIV1(postdiv1);
+       temp_clk_set.pllcon1 = RK3036_PLL_SET_REFDIV(refdiv) | RK3036_PLL_SET_POSTDIV2(postdiv2);
+       if (frac != 0)
+               temp_clk_set.pllcon1 |= RK3036_PLL_SET_DSMPD(0);
+       else
+               temp_clk_set.pllcon1 |= RK3036_PLL_SET_DSMPD(1);
+
+       temp_clk_set.pllcon2 = RK3036_PLL_SET_FRAC(frac);
+       temp_clk_set.rst_dly = 0;
+       clk_debug("setting....\n");
+       return rk3036_pll_clk_set_rate(&temp_clk_set, hw);
+}
+
+static int clk_pll_set_rate_3036_apll(struct clk_hw *hw, unsigned long rate,
+               unsigned long parent_rate)
+{
+       struct clk_pll *pll = to_clk_pll(hw);
+       unsigned long flags;
+       u32 refdiv, fbdiv, postdiv1, postdiv2, frac;
+       struct apll_clk_set *ps = (struct apll_clk_set *)(rk3036_apll_table);
+
+       while (ps->rate) {
+               if (ps->rate == rate) {
+                       break;
+               }
+               ps++;
+       }
+
+       clk_debug("%s %lu\n", __func__,  rate);
+       clk_debug("pllcon0 %08x\n", cru_readl(pll->reg + RK3188_PLL_CON(0)));
+       clk_debug("pllcon1 %08x\n", cru_readl(pll->reg + RK3188_PLL_CON(1)));
+       clk_debug("pllcon2 %08x\n", cru_readl(pll->reg + RK3188_PLL_CON(2)));
+       clk_debug("clksel0 %08x\n", cru_readl(RK3036_CRU_CLKSELS_CON(0)));
+       clk_debug("clksel1 %08x\n", cru_readl(RK3036_CRU_CLKSELS_CON(1)));
+       if (ps->rate == rate) {
+               printk("apll get a rate\n");
+
+               /*enter slowmode*/
+               local_irq_save(flags);
+               cru_writel(_RK3188_PLL_MODE_SLOW_SET(pll->mode_shift), pll->mode_offset);
+               loops_per_jiffy = LPJ_24M;
+
+               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));
+               cru_writel(ps->clksel0, RK3036_CRU_CLKSELS_CON(0));
+               cru_writel(ps->clksel1, RK3036_CRU_CLKSELS_CON(1));
+
+               clk_debug("pllcon0 %08x\n", cru_readl(pll->reg + RK3188_PLL_CON(0)));
+               clk_debug("pllcon1 %08x\n", cru_readl(pll->reg + RK3188_PLL_CON(1)));
+               clk_debug("pllcon2 %08x\n", cru_readl(pll->reg + RK3188_PLL_CON(2)));
+               clk_debug("clksel0 %08x\n", cru_readl(RK3036_CRU_CLKSELS_CON(0)));
+               clk_debug("clksel1 %08x\n", cru_readl(RK3036_CRU_CLKSELS_CON(1)));
+
+               /*wating lock state*/
+               udelay(ps->rst_dly);
+               rk3036_pll_wait_lock(hw);
+
+               /*return form slow*/
+               cru_writel(_RK3188_PLL_MODE_NORM_SET(pll->mode_shift), pll->mode_offset);
+               loops_per_jiffy = ps->lpj;
+               local_irq_restore(flags);
+       } else {
+               /*FIXME*/
+               rk3036_pll_clk_get_set(parent_rate, rate, &refdiv, &fbdiv, &postdiv1, &postdiv2, &frac);
+               rk3036_pll_set_con(hw, refdiv, fbdiv, postdiv1, postdiv2, frac);
+       }
+       clk_debug("setting OK\n");
+
+       return 0;       
+}
+static const struct clk_ops clk_pll_ops_3036_apll = {
+       .recalc_rate = clk_pll_recalc_rate_3036_apll,
+       .round_rate = clk_pll_round_rate_3036_apll,
+       .set_rate = clk_pll_set_rate_3036_apll,
+};
+
+
+/* CLK_PLL_3036_plus_autotype ops */
+
+static long clk_pll_round_rate_3036plus_auto(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 (pll_com_get_best_set(rate, rk3036plus_pll_com_table)->rate);
+}
+
+static int clk_pll_set_rate_3036plus_auto(struct clk_hw *hw, unsigned long rate,
+               unsigned long parent_rate)
+{
+       struct pll_clk_set *clk_set = (struct pll_clk_set *)(rk3036plus_pll_com_table);
+
+       clk_debug("******%s\n", __func__);
+       while (clk_set->rate) {
+               clk_debug("******%s clk_set->rate=%lu\n", __func__, clk_set->rate);
+               if (clk_set->rate == rate) {
+                       break;
+               }
+               clk_set++;
+       }
+       if (clk_set->rate == rate) {
+               rk3036_pll_clk_set_rate(clk_set, hw);
+       } else {
+               clk_debug("gpll is no corresponding rate=%lu\n", rate);
+               return -1;
+       }
+       clk_debug("******%s end\n", __func__);
+
+       return 0;       
+}
 
+static const struct clk_ops clk_pll_ops_3036plus_auto = {
+       .recalc_rate = clk_pll_recalc_rate_3036_apll,
+       .round_rate = clk_pll_round_rate_3036plus_auto,
+       .set_rate = clk_pll_set_rate_3036plus_auto,
+};
 
 const struct clk_ops *rk_get_pll_ops(u32 pll_flags)
 {
@@ -1363,6 +1719,12 @@ const struct clk_ops *rk_get_pll_ops(u32 pll_flags)
                case CLK_PLL_3188PLUS_AUTO:
                        return &clk_pll_ops_3188plus_auto;
 
+               case CLK_PLL_3036_APLL:
+                       return &clk_pll_ops_3036_apll;
+
+               case CLK_PLL_3036PLUS_AUTO:
+                       return &clk_pll_ops_3036plus_auto;
+
                default:
                        clk_err("%s: unknown pll_flags!\n", __func__);
                        return NULL;
old mode 100644 (file)
new mode 100755 (executable)
index 2479cb4..c3605aa
        .clksel1 = RK3288_CLK_L2RAM_DIV(l2_div) | RK3288_ATCLK_DIV(atclk_div) | RK3288_PCLK_DBG_DIV(pclk_dbg_div),\
        .lpj = (CLK_LOOPS_JIFFY_REF*_mhz) / CLK_LOOPS_RATE_REF,\
 }
+/***************************RK3036 PLL**************************************/
+#define LPJ_24M        (CLK_LOOPS_JIFFY_REF * 24) / CLK_LOOPS_RATE_REF
+/*****cru reg offset*****/
+#define RK3036_CRU_CLKSEL_CON          0x44
+#define RK3036_CRU_CLKGATE_CON         0xd0
+#define RK3036_CRU_GLB_SRST_FST        0x100
+#define RK3036_CRU_GLB_SRST_SND        0x104
+#define RK3036_CRU_SOFTRST_CON         0x110
+
+#define RK3036_CRU_CLKSELS_CON_CNT     (35)
+#define RK3036_CRU_CLKSELS_CON(i)      (RK3036_CRU_CLKSEL_CON + ((i) * 4))
+
+#define RK3036_CRU_CLKGATES_CON_CNT    (10)
+#define RK3036_CRU_CLKGATES_CON(i)     (RK3036_CRU_CLKGATE_CON + ((i) * 4))
+
+#define RK3036_CRU_SOFTRSTS_CON_CNT    (9)
+#define RK3036_CRU_SOFTRSTS_CON(i)     (RK3036_CRU_SOFTRST_CON + ((i) * 4))
+
+/*PLL_CON 0,1,2*/
+#define RK3036_PLL_PWR_ON                      (0)
+#define RK3036_PLL_PWR_DN                      (1)
+#define RK3036_PLL_BYPASS                      (1 << 15)
+#define RK3036_PLL_NO_BYPASS                   (0 << 15)
+/*con0*/
+#define RK3036_PLL_BYPASS_SHIFT                (15)
+
+#define RK3036_PLL_POSTDIV1_MASK               (0x7)
+#define RK3036_PLL_POSTDIV1_SHIFT              (12)
+#define RK3036_PLL_FBDIV_MASK                  (0xfff)
+#define RK3036_PLL_FBDIV_SHIFT                 (0)
+
+/*con1*/
+#define RK3036_PLL_RSTMODE_SHIFT               (15)
+#define RK3036_PLL_RST_SHIFT                   (14)
+#define RK3036_PLL_PWR_DN_SHIFT                (13)
+#define RK3036_PLL_DSMPD_SHIFT                 (12)
+#define RK3036_PLL_LOCK_SHIFT                  (10)
+
+#define RK3036_PLL_POSTDIV2_MASK               (0x7)
+#define RK3036_PLL_POSTDIV2_SHIFT              (6)
+#define RK3036_PLL_REFDIV_MASK                 (0x3f)
+#define RK3036_PLL_REFDIV_SHIFT                (0)
+
+/*con2*/
+#define RK3036_PLL_FOUT4PHASE_PWR_DN_SHIFT     (27)
+#define RK3036_PLL_FOUTVCO_PWR_DN_SHIFT        (26)
+#define RK3036_PLL_FOUTPOSTDIV_PWR_DN_SHIFT    (25)
+#define RK3036_PLL_DAC_PWR_DN_SHIFT            (24)
+
+#define RK3036_PLL_FRAC_MASK                   (0xffffff)
+#define RK3036_PLL_FRAC_SHIFT                  (0)
+
+#define CRU_GET_REG_BIT_VAL(reg, bits_shift)           (((reg) >> (bits_shift)) & (0x1))
+#define CRU_GET_REG_BITS_VAL(reg, bits_shift, msk)     (((reg) >> (bits_shift)) & (msk))
+#define CRU_SET_BIT(val, bits_shift)                   (((val) & (0x1)) << (bits_shift))
+#define CRU_W_MSK(bits_shift, msk)                     ((msk) << ((bits_shift) + 16))
+
+#define CRU_W_MSK_SETBITS(val, bits_shift, msk)        (CRU_W_MSK(bits_shift, msk)     \
+                                                       | CRU_SET_BITS(val, bits_shift, msk))
+#define CRU_W_MSK_SETBIT(val, bits_shift)              (CRU_W_MSK(bits_shift, 0x1)     \
+                                                       | CRU_SET_BIT(val, bits_shift))
+
+#define RK3036_PLL_SET_REFDIV(val)                             CRU_W_MSK_SETBITS(val, RK3036_PLL_REFDIV_SHIFT, RK3036_PLL_REFDIV_MASK)
+#define RK3036_PLL_SET_FBDIV(val)                              CRU_W_MSK_SETBITS(val, RK3036_PLL_FBDIV_SHIFT, RK3036_PLL_FBDIV_MASK)
+#define RK3036_PLL_SET_POSTDIV1(val)                           CRU_W_MSK_SETBITS(val, RK3036_PLL_POSTDIV1_SHIFT, RK3036_PLL_POSTDIV1_MASK)
+#define RK3036_PLL_SET_POSTDIV2(val)                           CRU_W_MSK_SETBITS(val, RK3036_PLL_POSTDIV2_SHIFT, RK3036_PLL_POSTDIV2_MASK)
+#define RK3036_PLL_SET_FRAC(val)                               CRU_SET_BITS(val, RK3036_PLL_FRAC_SHIFT, RK3036_PLL_FRAC_MASK)
+
+#define RK3036_PLL_GET_REFDIV(reg)                             CRU_GET_REG_BITS_VAL(reg, RK3036_PLL_REFDIV_SHIFT, RK3036_PLL_REFDIV_MASK)
+#define RK3036_PLL_GET_FBDIV(reg)                              CRU_GET_REG_BITS_VAL(reg, RK3036_PLL_FBDIV_SHIFT, RK3036_PLL_FBDIV_MASK)
+#define RK3036_PLL_GET_POSTDIV1(reg)                           CRU_GET_REG_BITS_VAL(reg, RK3036_PLL_POSTDIV1_SHIFT, RK3036_PLL_POSTDIV1_MASK)
+#define RK3036_PLL_GET_POSTDIV2(reg)                           CRU_GET_REG_BITS_VAL(reg, RK3036_PLL_POSTDIV2_SHIFT, RK3036_PLL_POSTDIV2_MASK)
+#define RK3036_PLL_GET_FRAC(reg)                               CRU_GET_REG_BITS_VAL(reg, RK3036_PLL_FRAC_SHIFT, RK3036_PLL_FRAC_MASK)
+
+/*#define APLL_SET_BYPASS(val)                         CRU_SET_BIT(val, PLL_BYPASS_SHIFT)*/
+#define RK3036_PLL_SET_DSMPD(val)                              CRU_W_MSK_SETBIT(val, RK3036_PLL_DSMPD_SHIFT)
+#define RK3036_PLL_GET_DSMPD(reg)                              CRU_GET_REG_BIT_VAL(reg, RK3036_PLL_DSMPD_SHIFT)
 
+/*******************CLKSEL0 BITS***************************/
+#define RK3036_CLK_SET_DIV_CON_SUB1(val, bits_shift, msk)      CRU_W_MSK_SETBITS((val - 1), bits_shift, msk)
+
+#define RK3036_CPU_CLK_PLL_SEL_SHIFT           (14)
+#define RK3036_CPU_CLK_PLL_SEL_MASK    (0x3)
+#define RK3036_CORE_CLK_PLL_SEL_SHIFT          (7)
+#define RK3036_SEL_APLL                        (0)
+#define RK3036_SEL_GPLL                        (1)
+#define RK3036_CPU_SEL_PLL(plls)               CRU_W_MSK_SETBITS(plls, RK3036_CPU_CLK_PLL_SEL_SHIFT, RK3036_CPU_CLK_PLL_SEL_MASK)
+#define RK3036_CORE_SEL_PLL(plls)              CRU_W_MSK_SETBIT(plls, RK3036_CORE_CLK_PLL_SEL_SHIFT)
+
+#define RK3036_ACLK_CPU_DIV_MASK               (0x1f)
+#define RK3036_ACLK_CPU_DIV_SHIFT              (8)
+#define RK3036_A9_CORE_DIV_MASK                (0x1f)
+#define RK3036_A9_CORE_DIV_SHIFT               (0)
+
+#define RATIO_11               (1)
+#define RATIO_21               (2)
+#define RATIO_41               (4)
+#define RATIO_81               (8)
+
+#define RK3036_ACLK_CPU_DIV(val)               RK3036_CLK_SET_DIV_CON_SUB1(val, RK3036_ACLK_CPU_DIV_SHIFT, RK3036_ACLK_CPU_DIV_MASK)
+#define RK3036_CLK_CORE_DIV(val)               RK3036_CLK_SET_DIV_CON_SUB1(val, RK3036_A9_CORE_DIV_SHIFT, RK3036_A9_CORE_DIV_MASK)
+/*******************CLKSEL1 BITS***************************/
+#define RK3036_PCLK_CPU_DIV_MASK               (0x7)
+#define RK3036_PCLK_CPU_DIV_SHIFT              (12)
+#define RK3036_HCLK_CPU_DIV_MASK               (0x3)
+#define RK3036_HCLK_CPU_DIV_SHIFT              (8)
+#define RK3036_ACLK_CORE_DIV_MASK              (0x7)
+#define RK3036_ACLK_CORE_DIV_SHIFT             (4)
+#define RK3036_CORE_PERIPH_DIV_MASK            (0xf)
+#define RK3036_CORE_PERIPH_DIV_SHIFT           (0)
+
+#define RK3036_PCLK_CPU_DIV(val)               RK3036_CLK_SET_DIV_CON_SUB1(val, RK3036_PCLK_CPU_DIV_SHIFT, RK3036_PCLK_CPU_DIV_MASK)
+#define RK3036_HCLK_CPU_DIV(val)               RK3036_CLK_SET_DIV_CON_SUB1(val, RK3036_HCLK_CPU_DIV_SHIFT, RK3036_HCLK_CPU_DIV_MASK)
+#define RK3036_ACLK_CORE_DIV(val)              RK3036_CLK_SET_DIV_CON_SUB1(val, RK3036_ACLK_CORE_DIV_SHIFT, RK3036_ACLK_CORE_DIV_MASK)
+#define RK3036_CLK_CORE_PERI_DIV(val)          RK3036_CLK_SET_DIV_CON_SUB1(val, RK3036_CORE_PERIPH_DIV_SHIFT, RK3036_CORE_PERIPH_DIV_MASK)
+
+/*******************clksel10***************************/
+#define RK3036_PERI_PLL_SEL_SHIFT      14
+#define RK3036_PERI_PLL_SEL_MASK       (0x3)
+#define RK3036_PERI_PCLK_DIV_MASK      (0x3)
+#define RK3036_PERI_PCLK_DIV_SHIFT     (12)
+#define RK3036_PERI_HCLK_DIV_MASK      (0x3)
+#define RK3036_PERI_HCLK_DIV_SHIFT     (8)
+#define RK3036_PERI_ACLK_DIV_MASK      (0x1f)
+#define RK3036_PERI_ACLK_DIV_SHIFT     (0)
+
+#define RK3036_SEL_3PLL_APLL           (0)
+#define RK3036_SEL_3PLL_DPLL           (1)
+#define RK3036_SEL_3PLL_GPLL           (2)
+
+
+#define RK3036_PERI_CLK_SEL_PLL(plls)  CRU_W_MSK_SETBITS(plls, RK3036_PERI_PLL_SEL_SHIFT, RK3036_PERI_PLL_SEL_MASK)
+#define RK3036_PERI_SET_ACLK_DIV(val)          RK3036_CLK_SET_DIV_CON_SUB1(val, RK3036_PERI_ACLK_DIV_SHIFT, RK3036_PERI_ACLK_DIV_MASK)
+
+/*******************gate BITS***************************/
+#define RK3036_CLK_GATE_CLKID_CONS(i)  RK3036_CRU_CLKGATES_CON((i) / 16)
+
+#define RK3036_CLK_GATE(i)             (1 << ((i)%16))
+#define RK3036_CLK_UN_GATE(i)          (0)
+
+#define RK3036_CLK_GATE_W_MSK(i)       (1 << (((i) % 16) + 16))
+#define RK3036_CLK_GATE_CLKID(i)       (16 * (i))
+
+#define _RK3036_APLL_SET_CLKS(_mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac, \
+               _periph_div, _aclk_core_div, _axi_div, _apb_div, _ahb_div) \
+{ \
+       .rate   = (_mhz) * MHZ, \
+       .pllcon0 = RK3036_PLL_SET_POSTDIV1(_postdiv1) | RK3036_PLL_SET_FBDIV(_fbdiv),   \
+       .pllcon1 = RK3036_PLL_SET_DSMPD(_dsmpd) | RK3036_PLL_SET_POSTDIV2(_postdiv2) | RK3036_PLL_SET_REFDIV(_refdiv),  \
+       .pllcon2 = RK3036_PLL_SET_FRAC(_frac),  \
+       .clksel1 = RK3036_ACLK_CORE_DIV(RATIO_##_aclk_core_div) | RK3036_CLK_CORE_PERI_DIV(RATIO_##_periph_div),        \
+       .lpj    = (CLK_LOOPS_JIFFY_REF * _mhz) / CLK_LOOPS_RATE_REF,    \
+       .rst_dly = 0,\
+}
+
+#define _RK3036_PLL_SET_CLKS(_mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac) \
+{ \
+       .rate   = (_mhz) * KHZ, \
+       .pllcon0 = RK3036_PLL_SET_POSTDIV1(_postdiv1) | RK3036_PLL_SET_FBDIV(_fbdiv),   \
+       .pllcon1 = RK3036_PLL_SET_DSMPD(_dsmpd) | RK3036_PLL_SET_POSTDIV2(_postdiv2) | RK3036_PLL_SET_REFDIV(_refdiv),  \
+       .pllcon2 = RK3036_PLL_SET_FRAC(_frac),  \
+}
 
 struct pll_clk_set {
        unsigned long   rate;