From: dkl Date: Thu, 13 Mar 2014 03:30:36 +0000 (+0800) Subject: clk: rk: add CLK_PLL_3288_APLL type support X-Git-Tag: firefly_0821_release~6113 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=1fe0958ebe7b69c4ed12829c14a89b2f8835ecdb;p=firefly-linux-kernel-4.4.55.git clk: rk: add CLK_PLL_3288_APLL type support --- diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index 320e65ee149a..428d9edf6fa9 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -5,7 +5,22 @@ #include "clk-pll.h" -static const struct apll_clk_set apll_table[] = { +static const struct pll_clk_set pll_com_table[] = { + _RK3188_PLL_SET_CLKS(1200000, 1, 50, 1), + _RK3188_PLL_SET_CLKS(1188000, 2, 99, 1), + _RK3188_PLL_SET_CLKS(891000, 8, 594, 2), + _RK3188_PLL_SET_CLKS(768000, 1, 64, 2), + _RK3188_PLL_SET_CLKS(594000, 2, 198, 4), + _RK3188_PLL_SET_CLKS(408000, 1, 68, 4), + _RK3188_PLL_SET_CLKS(384000, 2, 128, 4), + _RK3188_PLL_SET_CLKS(360000, 1, 60, 4), + _RK3188_PLL_SET_CLKS(300000, 1, 50, 4), + _RK3188_PLL_SET_CLKS(297000, 2, 198, 8), + _RK3188_PLL_SET_CLKS(148500, 2, 99, 8), + _RK3188_PLL_SET_CLKS(0, 0, 0, 0), +}; + +static const struct apll_clk_set rk3188_apll_table[] = { // (_mhz, nr, nf, no, _periph_div, _aclk_div) _RK3188_APLL_SET_CLKS(2208, 1, 92, 1, 8, 81), _RK3188_APLL_SET_CLKS(2184, 1, 91, 1, 8, 81), @@ -69,19 +84,68 @@ static const struct apll_clk_set apll_table[] = { _RK3188_APLL_SET_CLKS(0, 1, 32, 16, 2, 11), }; -static const struct pll_clk_set pll_com_table[] = { - _RK3188_PLL_SET_CLKS(1200000, 1, 50, 1), - _RK3188_PLL_SET_CLKS(1188000, 2, 99, 1), - _RK3188_PLL_SET_CLKS(891000, 8, 594, 2), - _RK3188_PLL_SET_CLKS(768000, 1, 64, 2), - _RK3188_PLL_SET_CLKS(594000, 2, 198, 4), - _RK3188_PLL_SET_CLKS(408000, 1, 68, 4), - _RK3188_PLL_SET_CLKS(384000, 2, 128, 4), - _RK3188_PLL_SET_CLKS(360000, 1, 60, 4), - _RK3188_PLL_SET_CLKS(300000, 1, 50, 4), - _RK3188_PLL_SET_CLKS(297000, 2, 198, 8), - _RK3188_PLL_SET_CLKS(148500, 2, 99, 8), - _RK3188_PLL_SET_CLKS(0, 0, 0, 0), +static const struct apll_clk_set rk3288_apll_table[] = { + // (_mhz, nr, nf, no, l2ram, m0, mp, atclk, pclk_dbg) + _RK3288_APLL_SET_CLKS(2208, 1, 92, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(2184, 1, 91, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(2160, 1, 90, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(2136, 1, 89, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(2112, 1, 88, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(2088, 1, 87, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(2064, 1, 86, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(2040, 1, 85, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(2016, 1, 84, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1992, 1, 83, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1968, 1, 82, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1944, 1, 81, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1920, 1, 80, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1896, 1, 79, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1872, 1, 78, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1848, 1, 77, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1824, 1, 76, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1800, 1, 75, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1776, 1, 74, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1752, 1, 73, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1728, 1, 72, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1704, 1, 71, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1680, 1, 70, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1656, 1, 69, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1632, 1, 68, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1608, 1, 67, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1560, 1, 65, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1512, 1, 63, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1488, 1, 62, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1464, 1, 61, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1440, 1, 60, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1416, 1, 59, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1392, 1, 58, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1368, 1, 57, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1344, 1, 56, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1320, 1, 55, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1296, 1, 54, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1272, 1, 53, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1248, 1, 52, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1224, 1, 51, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1200, 1, 50, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1176, 1, 49, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1128, 1, 47, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1104, 1, 46, 1, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(1008, 1, 84, 2, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(912, 1, 76, 2, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(888, 1, 74, 2, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(816, 1, 68, 2, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(792, 1, 66, 2, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(696, 1, 58, 2, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(600, 1, 50, 2, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(552, 1, 92, 4, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(504, 1, 84, 4, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(408, 1, 68, 4, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(312, 1, 52, 4, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(252, 1, 84, 8, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(216, 1, 72, 8, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(126, 1, 84, 16, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(48, 1, 32, 16, 2, 2, 4, 4, 4), + _RK3288_APLL_SET_CLKS(0, 1, 32, 16, 2, 2, 4, 4, 4), }; static void pll_wait_lock(struct clk_hw *hw) @@ -314,7 +378,7 @@ static long clk_pll_round_rate_3188_apll(struct clk_hw *hw, unsigned long rate, return rate; } - return (apll_get_best_set(rate, apll_table)->rate); + return (apll_get_best_set(rate, rk3188_apll_table)->rate); } /* 1: use, 0: no use */ @@ -409,7 +473,7 @@ static int clk_pll_set_rate_3188_apll(struct clk_hw *hw, unsigned long rate, temp_div); CHANGE_APLL: - ps = apll_get_best_set(rate, apll_table); + ps = apll_get_best_set(rate, rk3188_apll_table); clk_debug("apll will set rate %lu\n", ps->rate); clk_debug("table con:%08x,%08x,%08x, sel:%08x,%08x\n", ps->pllcon0, ps->pllcon1, ps->pllcon2, @@ -738,7 +802,7 @@ static int clk_pll_set_rate_3188plus_apll(struct clk_hw *hw, unsigned long rate, temp_div); CHANGE_APLL: - ps = apll_get_best_set(rate, apll_table); + ps = apll_get_best_set(rate, rk3188_apll_table); clk_debug("apll will set rate %lu\n", ps->rate); clk_debug("table con:%08x,%08x,%08x, sel:%08x,%08x\n", ps->pllcon0, ps->pllcon1, ps->pllcon2, @@ -827,6 +891,200 @@ static const struct clk_ops clk_pll_ops_3188plus_apll = { .set_rate = clk_pll_set_rate_3188plus_apll, }; +/* CLK_PLL_3288_APLL type ops */ +static unsigned long clk_pll_recalc_rate_3288_apll(struct clk_hw *hw, + unsigned long parent_rate) +{ + return clk_pll_recalc_rate_3188plus(hw, parent_rate); +} + +static long clk_pll_round_rate_3288_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, rk3288_apll_table)->rate); +} + +/* 1: use, 0: no use */ +#define RK3288_USE_ARM_GPLL 1 + +static int clk_pll_set_rate_3288_apll(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_arm_gpll"); + unsigned long arm_gpll_rate; + const struct apll_clk_set *ps; +// u32 old_aclk_div = 0, new_aclk_div = 0; + u32 temp_div; + unsigned long flags; + int sel_gpll = 0; + + +#if 0 + if (rate == parent_rate) { + clk_debug("pll %s set rate=%lu equal to parent rate\n", + __clk_get_name(hw->clk), rate); + cru_writel(_RK3188_PLL_MODE_SLOW_SET(pll->mode_shift), + pll->mode_offset); + /* pll power down */ + writel((0x1 << (16+1)) | (0x1<<1), pll->reg + RK3188_PLL_CON(3)); + clk_debug("pll %s enter slow mode, set rate OK!\n", + __clk_get_name(hw->clk)); + return 0; + } +#endif + +#if !RK3288_USE_ARM_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); + temp_div = DIV_ROUND_UP(arm_gpll_rate, __clk_get_rate(clk)); + temp_div = (temp_div == 0) ? 1 : temp_div; + if (temp_div > RK3288_CORE_CLK_MAX_DIV) { + clk_debug("temp_div %d > max_div %d\n", temp_div, + RK3288_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 1 + 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); + + /* firstly set div, then select arm_gpll path */ + cru_writel(RK3288_CORE_CLK_DIV(temp_div), RK3288_CRU_CLKSELS_CON(0)); + cru_writel(RK3288_CORE_SEL_PLL_W_MSK|RK3288_CORE_SEL_GPLL, + RK3288_CRU_CLKSELS_CON(0)); + + sel_gpll = 1; + //loops_per_jiffy = CLK_LOOPS_RECALC(arm_gpll_rate) / temp_div; + 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: + ps = apll_get_best_set(rate, rk3288_apll_table); + clk_debug("apll 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); + + local_irq_save(flags); + + /* If core src don't select gpll, apll need to enter slow mode + * before reset + */ + //FIXME + //if (!sel_gpll) + cru_writel(_RK3188_PLL_MODE_SLOW_SET(pll->mode_shift), pll->mode_offset); + + /* PLL enter rest */ + writel(_RK3188PLUS_PLL_RESET_SET(1), pll->reg + RK3188_PLL_CON(3)); + + writel(ps->pllcon0, pll->reg + RK3188_PLL_CON(0)); + writel(ps->pllcon1, pll->reg + RK3188_PLL_CON(1)); + writel(ps->pllcon2, pll->reg + RK3188_PLL_CON(2)); + + udelay(5); + + /* return from rest */ + writel(_RK3188PLUS_PLL_RESET_SET(0), pll->reg + RK3188_PLL_CON(3)); + + //wating lock state + udelay(ps->rst_dly); + pll_wait_lock(hw); + + if (rate >= __clk_get_rate(hw->clk)) { + cru_writel(ps->clksel0, RK3288_CRU_CLKSELS_CON(0)); + cru_writel(ps->clksel1, RK3288_CRU_CLKSELS_CON(37)); + } + + /* PLL return from slow mode */ + //FIXME + //if (!sel_gpll) + cru_writel(_RK3188_PLL_MODE_NORM_SET(pll->mode_shift), pll->mode_offset); + + /* reparent to apll, and set div to 1 */ + if (sel_gpll) { + cru_writel(RK3288_CORE_SEL_PLL_W_MSK|RK3288_CORE_SEL_APLL, + RK3288_CRU_CLKSELS_CON(0)); + cru_writel(RK3288_CORE_CLK_DIV(1), RK3288_CRU_CLKSELS_CON(0)); + } + + if (rate < __clk_get_rate(hw->clk)) { + cru_writel(ps->clksel0, RK3288_CRU_CLKSELS_CON(0)); + cru_writel(ps->clksel1, RK3288_CRU_CLKSELS_CON(37)); + } + + //loops_per_jiffy = ps->lpj; + smp_wmb(); + + local_irq_restore(flags); + + if (sel_gpll) { + sel_gpll = 0; + clk_disable(arm_gpll); + clk_unprepare(arm_gpll); + } + + //clk_debug("apll set loops_per_jiffy =%lu\n", loops_per_jiffy); + + clk_debug("apll set rate %lu, con(%x,%x,%x,%x), sel(%x,%x)\n", + ps->rate, + readl(pll->reg + RK3188_PLL_CON(0)), + readl(pll->reg + RK3188_PLL_CON(1)), + readl(pll->reg + RK3188_PLL_CON(2)), + readl(pll->reg + RK3188_PLL_CON(3)), + cru_readl(RK3288_CRU_CLKSELS_CON(0)), + cru_readl(RK3288_CRU_CLKSELS_CON(1))); + + return 0; +} + + +static const struct clk_ops clk_pll_ops_3288_apll = { + .recalc_rate = clk_pll_recalc_rate_3288_apll, + .round_rate = clk_pll_round_rate_3288_apll, + .set_rate = clk_pll_set_rate_3288_apll, +}; + + + const struct clk_ops *rk_get_pll_ops(u32 pll_flags) { switch (pll_flags) { @@ -842,6 +1100,9 @@ const struct clk_ops *rk_get_pll_ops(u32 pll_flags) case CLK_PLL_3188PLUS_APLL: return &clk_pll_ops_3188plus_apll; + case CLK_PLL_3288_APLL: + return &clk_pll_ops_3288_apll; + 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 index ba6262af6e5e..a2828eca0d94 100644 --- a/drivers/clk/rockchip/clk-pll.h +++ b/drivers/clk/rockchip/clk-pll.h @@ -11,6 +11,9 @@ #define CLK_LOOPS_RECALC(rate) \ div_u64(CLK_LOOPS_JIFFY_REF*(rate),CLK_LOOPS_RATE_REF*MHZ) +#define CLK_DIV_PLUS_ONE_SET(i, shift, width) \ + ((((i)-1) << (shift)) | (((2<<(width)) - 1) << ((shift)+16))) + /*******************RK3188 PLL******************************/ #define RK3188_PLL_CON(i) ((i) * 4) /*******************PLL WORK MODE*************************/ @@ -180,10 +183,60 @@ .pllcon0 = RK3188_PLL_CLKR_SET(nr) | RK3188_PLL_CLKOD_SET(no), \ .pllcon1 = RK3188_PLL_CLKF_SET(nf),\ .pllcon2 = RK3188_PLL_CLK_BWADJ_SET(nf >> 1),\ + .rst_dly = ((nr*500)/24+1),\ .clksel0 = RK3188_CORE_PERIPH_W_MSK | RK3188_CORE_PERIPH_##_periph_div,\ .clksel1 = RK3188_CORE_ACLK_W_MSK | RK3188_CORE_ACLK_##_aclk_div,\ .lpj = (CLK_LOOPS_JIFFY_REF*_mhz) / CLK_LOOPS_RATE_REF,\ +} + +/*******************RK3288 PLL***********************************/ +/*******************CLKSEL0 BITS***************************/ +#define RK3288_CORE_SEL_PLL_W_MSK (1 << 31) +#define RK3288_CORE_SEL_APLL (0 << 15) +#define RK3288_CORE_SEL_GPLL (1 << 15) + +#define RK3288_CORE_CLK_SHIFT 8 +#define RK3288_CORE_CLK_WIDTH 5 +#define RK3288_CORE_CLK_DIV(i) \ + CLK_DIV_PLUS_ONE_SET(i, RK3288_CORE_CLK_SHIFT, RK3288_CORE_CLK_WIDTH) +#define RK3288_CORE_CLK_MAX_DIV (2<> 1),\ .rst_dly = ((nr*500)/24+1),\ + .clksel0 = RK3288_ACLK_M0_DIV(m0_div) | RK3288_ACLK_MP_DIV(mp_div),\ + .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,\ } diff --git a/include/dt-bindings/clock/rockchip.h b/include/dt-bindings/clock/rockchip.h index 6b75e611fae8..add45f3d0f95 100644 --- a/include/dt-bindings/clock/rockchip.h +++ b/include/dt-bindings/clock/rockchip.h @@ -34,5 +34,7 @@ #define CLK_PLL_3188_APLL BIT(1) #define CLK_PLL_3188PLUS BIT(2) #define CLK_PLL_3188PLUS_APLL BIT(3) +#define CLK_PLL_3288_APLL BIT(4) + #endif /* _DT_BINDINGS_CLOCK_ROCKCHIP_H */ diff --git a/include/linux/rockchip/cru.h b/include/linux/rockchip/cru.h index 8e6255adbe6f..76007cbb8c1c 100644 --- a/include/linux/rockchip/cru.h +++ b/include/linux/rockchip/cru.h @@ -39,6 +39,17 @@ #define RK3188_PLL_MODE_NORM(id) ((0x1<<((id)*4))|(0x3<<(16+(id)*4))) #define RK3188_PLL_MODE_DEEP(id) ((0x2<<((id)*4))|(0x3<<(16+(id)*4))) + +/*******************RK3288********************************/ +/*******************CRU OFFSET*********************/ +#define RK3288_CRU_MODE_CON 0x50 +#define RK3288_CRU_CLKSEL_CON 0x60 +#define RK3288_CRU_CLKGATE_CON 0x160 + +#define RK3288_PLL_CONS(id, i) ((id) * 0x10 + ((i) * 4)) +#define RK3288_CRU_CLKSELS_CON(i) (RK3288_CRU_CLKSEL_CON + ((i) * 4)) +#define RK3288_CRU_CLKGATES_CON(i) (RK3288_CRU_CLKGATE_CON + ((i) * 4)) + #define RK3288_CRU_GLB_SRST_FST_VALUE 0x1b0 #define RK3288_CRU_GLB_SRST_SND_VALUE 0x1b4 #define RK3288_CRU_MISC_CON 0x1e8