From c46a7d3bfde06f5ea36707f8a8a5a56c29e708a3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E5=BC=A0=E6=99=B4?= Date: Mon, 7 Jul 2014 14:06:37 +0800 Subject: [PATCH] rk3036:clk:support set pll clks and init clocks --- arch/arm/boot/dts/rk3036-clocks.dtsi | 27 +- arch/arm/boot/dts/rk3036.dtsi | 80 ++++++ drivers/clk/rockchip/clk-pll.c | 362 +++++++++++++++++++++++++++ drivers/clk/rockchip/clk-pll.h | 161 ++++++++++++ 4 files changed, 622 insertions(+), 8 deletions(-) mode change 100644 => 100755 arch/arm/boot/dts/rk3036-clocks.dtsi mode change 100644 => 100755 drivers/clk/rockchip/clk-pll.c mode change 100644 => 100755 drivers/clk/rockchip/clk-pll.h diff --git a/arch/arm/boot/dts/rk3036-clocks.dtsi b/arch/arm/boot/dts/rk3036-clocks.dtsi old mode 100644 new mode 100755 index 6464739f08e5..8e98257b6c13 --- a/arch/arm/boot/dts/rk3036-clocks.dtsi +++ b/arch/arm/boot/dts/rk3036-clocks.dtsi @@ -60,6 +60,13 @@ #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"; @@ -192,7 +199,7 @@ 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>; @@ -608,6 +615,7 @@ 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 */ @@ -792,6 +800,7 @@ 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 { @@ -855,6 +864,7 @@ clock-output-names = "clk_mac"; rockchip,div-type = ; #clock-cells = <0>; + #clock-init-cells = <1>; }; /* reg[15:14]: reserved */ @@ -938,6 +948,7 @@ clocks = <&clk_apll>, <&clk_dpll>, <&clk_gpll>; clock-output-names = "dclk_lcdc1"; #clock-cells = <0>; + #clock-init-cells = <1>; }; /* reg[7:2]: reserved */ @@ -950,8 +961,8 @@ rockchip,div-type = ; #clock-cells = <0>; rockchip,clkops-idx = - ; - rockchip,flags = ; + ; + rockchip,flags = ; }; }; @@ -1093,7 +1104,7 @@ 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>; @@ -1130,7 +1141,7 @@ <&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", @@ -1151,7 +1162,7 @@ reg = <0x00d4 0x4>; clocks = <&clk_timer0>, <&clk_timer1>, - <&dummy>, <&dummy>, + <&dummy>, <&jtag_tck>, <&aclk_vio_pre>, <&xin12m>, <&dummy>, <&dummy>, @@ -1441,7 +1452,7 @@ "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>; @@ -1466,7 +1477,7 @@ 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", diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi index fcc04c0584a1..b7ddf761a0f1 100755 --- a/arch/arm/boot/dts/rk3036.dtsi +++ b/arch/arm/boot/dts/rk3036.dtsi @@ -175,6 +175,86 @@ 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>; diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c old mode 100644 new mode 100755 index 2f54724a6a6b..d1dcfa2e3ed5 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -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; diff --git a/drivers/clk/rockchip/clk-pll.h b/drivers/clk/rockchip/clk-pll.h old mode 100644 new mode 100755 index 2479cb45ca2a..c3605aa27e22 --- a/drivers/clk/rockchip/clk-pll.h +++ b/drivers/clk/rockchip/clk-pll.h @@ -256,7 +256,168 @@ .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; -- 2.34.1