From 27b62b99172ccfe7412a80152eff2991b2f66151 Mon Sep 17 00:00:00 2001 From: chenxing Date: Thu, 18 Jul 2013 10:32:02 +0800 Subject: [PATCH] rk3026: add clock_data support --- arch/arm/mach-rk3026/clock_data.c | 2869 +++++++++++++++++++++++ arch/arm/mach-rk3026/include/mach/cru.h | 561 +++++ 2 files changed, 3430 insertions(+) create mode 100755 arch/arm/mach-rk3026/clock_data.c create mode 100755 arch/arm/mach-rk3026/include/mach/cru.h diff --git a/arch/arm/mach-rk3026/clock_data.c b/arch/arm/mach-rk3026/clock_data.c new file mode 100755 index 000000000000..942ac09e8a6c --- /dev/null +++ b/arch/arm/mach-rk3026/clock_data.c @@ -0,0 +1,2869 @@ +/* arch/arm/mach-rk2928/clock_data.c + * + * Copyright (C) 2012 ROCKCHIP, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include + +#define MHZ (1000 * 1000) +#define KHZ (1000) +#define CLK_LOOPS_JIFFY_REF 11996091ULL +#define CLK_LOOPS_RATE_REF (1200) //Mhz +#define CLK_LOOPS_RECALC(new_rate) div_u64(CLK_LOOPS_JIFFY_REF*(new_rate),CLK_LOOPS_RATE_REF*MHZ) +#define LPJ_24M (CLK_LOOPS_JIFFY_REF * 24) / CLK_LOOPS_RATE_REF + + +struct apll_clk_set { + unsigned long rate; + u32 pllcon0; + u32 pllcon1; + u32 pllcon2; //nb=bwadj+1;0:11;nb=nf/2 + u32 clksel0; + u32 clksel1; + u32 rst_dly;//us + unsigned long lpj; //loop per jeffise +}; + +struct pll_clk_set { + unsigned long rate; + u32 pllcon0; + u32 pllcon1; + u32 pllcon2; //nb=bwadj+1;0:11;nb=nf/2 + u32 rst_dly;//us +}; +#if 0 +#define CLKDATA_DBG(fmt, args...) printk("CLKDATA_DBG:\t"fmt, ##args) +#define CLKDATA_LOG(fmt, args...) printk("CLKDATA_LOG:\t"fmt, ##args) +#else +#define CLKDATA_DBG(fmt, args...) do {} while(0) +#define CLKDATA_LOG(fmt, args...) do {} while(0) +#endif +#define CLKDATA_ERR(fmt, args...) printk(KERN_ERR "CLKDATA_ERR:\t"fmt, ##args) +#define CLKDATA_WARNNING(fmt, args...) printk("CLKDATA_WANNING:\t"fmt, ##args) + +#define cru_readl(offset) readl_relaxed(RK2928_CRU_BASE + offset) +#define cru_writel(v, offset) do { writel_relaxed(v, RK2928_CRU_BASE + offset); dsb(); } while (0) + +#define rk_clock_udelay(a) udelay(a); + +#define PLLS_IN_NORM(pll_id) \ + (((cru_readl(CRU_MODE_CON) & PLL_MODE_MSK(pll_id)) == (PLL_MODE_NORM(pll_id) & PLL_MODE_MSK(pll_id)))\ + && !(cru_readl(PLL_CONS(pll_id, 0)) & PLL_BYPASS)) + +#define get_cru_bits(con, mask, shift)\ + ((cru_readl((con)) >> (shift)) & (mask)) + +#define CRU_DIV_SET(mask, shift, max) \ + .div_mask = (mask),\ +.div_shift = (shift),\ +.div_max = (max) + +#define CRU_SRC_SET(mask, shift ) \ + .src_mask = (mask),\ +.src_shift = (shift) + +#define CRU_PARENTS_SET(parents_array) \ + .parents = (parents_array),\ +.parents_num = ARRAY_SIZE((parents_array)) + +#define get_cru_bits(con,mask,shift)\ + ((cru_readl((con)) >> (shift)) & (mask)) + +#define set_cru_bits_w_msk(val,mask,shift,con)\ + cru_writel(((mask)<<(shift+16))|((val)<<(shift)),(con)) +#define regfile_readl(offset) readl_relaxed(RK2928_GRF_BASE + offset) +#define regfile_writel(v, offset) do { writel_relaxed(v, RK2928_GRF_BASE + offset); dsb(); } while (0) +#define cru_writel_frac(v,offset) cru_writel((v),(offset)) +/*******************PLL CON0 BITS***************************/ +#define SET_PLL_DATA(_pll_id,_table) \ +{\ + .id=(_pll_id),\ + .table=(_table),\ +} + +#define GATE_CLK(NAME,PARENT,ID) \ + static struct clk clk_##NAME = { \ + .name = #NAME, \ + .parent = &PARENT, \ + .mode = gate_mode, \ + .gate_idx = CLK_GATE_##ID, \ + } + +//FIXME +//lpj +#define _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 = PLL_SET_POSTDIV1(_postdiv1) | PLL_SET_FBDIV(_fbdiv), \ + .pllcon1 = PLL_SET_DSMPD(_dsmpd) | PLL_SET_POSTDIV2(_postdiv2) | PLL_SET_REFDIV(_refdiv), \ + .pllcon2 = PLL_SET_FRAC(_frac), \ + .clksel1 = ACLK_CORE_DIV(RATIO_##_aclk_core_div) | CLK_CORE_PERI_DIV(RATIO_##_periph_div), \ + .lpj = (CLK_LOOPS_JIFFY_REF * _mhz) / CLK_LOOPS_RATE_REF, \ + .rst_dly = 0,\ +} + +static const struct apll_clk_set apll_clks[] = { + _APLL_SET_CLKS(1248, 1, 52, 1, 1, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS(1200, 1, 50, 1, 1, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS(1104, 1, 46, 1, 1, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS(1008, 1, 42, 1, 1, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS( 912, 1, 38, 1, 1, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS( 816, 1, 34, 1, 1, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS( 696, 1, 29, 1, 1, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS( 600, 1, 25, 1, 1, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS( 504, 1, 21, 1, 1, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS( 408, 1, 17, 1, 1, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS( 312, 1, 52, 2, 2, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS( 216, 1, 36, 2, 2, 1, 0, 41, 21, 41, 21, 21), + _APLL_SET_CLKS( 0, 1, 0, 1, 1, 1, 0, 41, 21, 41, 21, 21), +}; + +#define _PLL_SET_CLKS(_mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac) \ +{ \ + .rate = (_mhz) * KHZ, \ + .pllcon0 = PLL_SET_POSTDIV1(_postdiv1) | PLL_SET_FBDIV(_fbdiv), \ + .pllcon1 = PLL_SET_DSMPD(_dsmpd) | PLL_SET_POSTDIV2(_postdiv2) | PLL_SET_REFDIV(_refdiv), \ + .pllcon2 = PLL_SET_FRAC(_frac), \ +} +static const struct pll_clk_set cpll_clks[] = { + _PLL_SET_CLKS(798000, 4, 133, 1, 1, 1, 0), + _PLL_SET_CLKS(1064000, 3, 133, 1, 1, 1, 0), +}; + +static const struct pll_clk_set gpll_clks[] = { + _PLL_SET_CLKS(297000, 2, 99, 4, 1, 1, 0), +}; + +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; +} + +static int frac_div_get_seting(unsigned long rate_out,unsigned long rate, + u32 *numerator,u32 *denominator) +{ + u32 gcd_vl; + gcd_vl = clk_gcd(rate, rate_out); + CLKDATA_DBG("frac_get_seting rate=%lu,parent=%lu,gcd=%d\n",rate_out,rate, gcd_vl); + + if (!gcd_vl) { + CLKDATA_ERR("gcd=0, i2s frac div is not be supported\n"); + return -ENOENT; + } + + *numerator = rate_out / gcd_vl; + *denominator = rate/ gcd_vl; + + CLKDATA_DBG("frac_get_seting numerator=%d,denominator=%d,times=%d\n", + *numerator, *denominator, *denominator / *numerator); + + if (*numerator > 0xffff || *denominator > 0xffff|| + (*denominator/(*numerator))<20) { + CLKDATA_ERR("can't get a available nume and deno\n"); + return -ENOENT; + } + + return 0; + +} +/************************option functions*****************/ +/************************clk recalc div rate**************/ + +//for free div +static unsigned long clksel_recalc_div(struct clk *clk) +{ + u32 div = get_cru_bits(clk->clksel_con, clk->div_mask, clk->div_shift) + 1; + unsigned long rate = clk->parent->rate / div; + + CLKDATA_DBG("ENTER %s clk=%s\n", __func__, clk->name); + CLKDATA_DBG("%s new clock rate is %lu (div %u)\n", clk->name, rate, div); + return rate; +} + +//for div 2^n +static unsigned long clksel_recalc_shift(struct clk *clk) +{ + u32 shift = get_cru_bits(clk->clksel_con, clk->div_mask, clk->div_shift); + unsigned long rate = clk->parent->rate >> shift; + CLKDATA_DBG("ENTER %s clk=%s\n", __func__, clk->name); + CLKDATA_DBG("%s new clock rate is %lu (shift %u)\n", clk->name, rate, shift); + return rate; +} + +//for rate equal to parent +static unsigned long clksel_recalc_equal_parent(struct clk *clk) +{ + unsigned long rate = clk->parent->rate; + CLKDATA_DBG("ENTER %s clk=%s\n", __func__, clk->name); + CLKDATA_DBG("%s new clock rate is %lu (equal to parent)\n", clk->name, rate); + + return rate; +} + +//for Fixed divide ratio +static unsigned long clksel_recalc_fixed_div2(struct clk *clk) +{ + unsigned long rate = clk->parent->rate >> 1; + CLKDATA_DBG("ENTER %s clk=%s\n", __func__, clk->name); + CLKDATA_DBG("%s new clock rate is %lu (div %u)\n", clk->name, rate, 2); + + return rate; +} + +static unsigned long clksel_recalc_fixed_div4(struct clk *clk) +{ + unsigned long rate = clk->parent->rate >> 2; + CLKDATA_DBG("ENTER %s clk=%s\n", __func__, clk->name); + CLKDATA_DBG("%s new clock rate is %lu (div %u)\n", clk->name, rate, 4); + + return rate; +} + +static unsigned long clksel_recalc_frac(struct clk *clk) +{ + unsigned long rate; + u64 rate64; + u32 r = cru_readl(clk->clksel_con), numerator, denominator; + CLKDATA_DBG("ENTER %s clk=%s\n", __func__, clk->name); + if (r == 0) // FPGA ? + return clk->parent->rate; + numerator = r >> 16; + denominator = r & 0xFFFF; + rate64 = (u64)clk->parent->rate * numerator; + do_div(rate64, denominator); + rate = rate64; + CLKDATA_DBG("%s new clock rate is %lu (frac %u/%u)\n", clk->name, rate, numerator, denominator); + return rate; +} + +#define FRAC_MODE 0 +static unsigned long pll_clk_recalc(u8 pll_id, unsigned long parent_rate) +{ + unsigned long rate; + unsigned int dsmp = 0; + u64 rate64 = 0, frac_rate64 = 0; + dsmp = PLL_GET_DSMPD(cru_readl(PLL_CONS(pll_id, 1))); + + if (PLLS_IN_NORM(pll_id)) { + u32 pll_con0 = cru_readl(PLL_CONS(pll_id, 0)); + u32 pll_con1 = cru_readl(PLL_CONS(pll_id, 1)); + u32 pll_con2 = cru_readl(PLL_CONS(pll_id, 2)); + //integer mode + rate64 = (u64)parent_rate * PLL_GET_FBDIV(pll_con0); + do_div(rate64, PLL_GET_REFDIV(pll_con1)); + + if (FRAC_MODE == dsmp) { + //fractional mode + frac_rate64 = (u64)parent_rate * PLL_GET_FRAC(pll_con2); + do_div(frac_rate64, PLL_GET_REFDIV(pll_con1)); + rate64 += frac_rate64 >> 24; + CLKDATA_DBG("%s id=%d frac_rate=%llu(%08x/2^24) by pass mode\n", + __func__, pll_id, frac_rate64 >> 24, PLL_GET_FRAC(pll_con2)); + } + do_div(rate64, PLL_GET_POSTDIV1(pll_con0)); + do_div(rate64, PLL_GET_POSTDIV2(pll_con1)); + + rate = rate64; + } else { + rate = parent_rate; + CLKDATA_DBG("pll_clk_recalc id=%d rate=%lu by pass mode\n", pll_id, rate); + } + return rate; +} + +static unsigned long plls_clk_recalc(struct clk *clk) +{ + return pll_clk_recalc(clk->pll->id, clk->parent->rate); +} + +/************************clk set rate*********************************/ +static int clksel_set_rate_freediv(struct clk *clk, unsigned long rate) +{ + u32 div = 0; + + for (div = 0; div < clk->div_max; div++) { + u32 new_rate = clk->parent->rate / (div + 1); + if (new_rate <= rate) { + set_cru_bits_w_msk(div,clk->div_mask,clk->div_shift,clk->clksel_con); + //clk->rate = new_rate; + CLKDATA_DBG("clksel_set_rate_freediv for clock %s to rate %ld (div %d)\n", clk->name, rate, div + 1); + return 0; + } + if (div == clk->div_max - 1) { + CLKDATA_WARNNING("%s clk=%s, div=%u, rate=%lu, new_rate=%u\n", + __func__, clk->name, div, rate, new_rate); + set_cru_bits_w_msk(div,clk->div_mask,clk->div_shift,clk->clksel_con); + return 0; + } + } + return -ENOENT; +} + +//for div 1 2 4 2^n +static int clksel_set_rate_shift(struct clk *clk, unsigned long rate) +{ + u32 shift; + for (shift = 0; (1 << shift) < clk->div_max; shift++) { + u32 new_rate = clk->parent->rate >> shift; + if (new_rate <= rate) { + set_cru_bits_w_msk(shift,clk->div_mask,clk->div_shift,clk->clksel_con); + clk->rate = new_rate; + CLKDATA_DBG("clksel_set_rate_shift for clock %s to rate %ld (shift %d)\n", clk->name, rate, shift); + return 0; + } + } + return -ENOENT; +} +#if 0 +//for div 2 4 2^n +static int clksel_set_rate_shift_2(struct clk *clk, unsigned long rate) +{ + u32 shift; + + for (shift = 1; (1 << shift) < clk->div_max; shift++) { + u32 new_rate = clk->parent->rate >> shift; + if (new_rate <= rate) { + set_cru_bits_w_msk(shift-1,clk->div_mask,clk->div_shift,clk->clksel_con); + clk->rate = new_rate; + CLKDATA_DBG("clksel_set_rate_shift for clock %s to rate %ld (shift %d)\n", clk->name, rate, shift); + return 0; + } + } + return -ENOENT; +} +#endif +//for div 1 2 4 2*n +static int clksel_set_rate_even(struct clk *clk, unsigned long rate) +{ + u32 div = 0, new_rate = 0; + for (div = 1; div < clk->div_max; div++) { + if (div >= 3 && div % 2 != 0) + continue; + new_rate = clk->parent->rate / div; + if (new_rate <= rate) { + set_cru_bits_w_msk(div - 1, clk->div_mask, clk->div_shift, clk->clksel_con); + clk->rate = new_rate; + pr_debug("%s for clock %s to rate %ld (even div = %d)\n", + __func__, clk->name, rate, div); + return 0; + } + } + return -ENOENT; +} + +static u32 clk_get_freediv(unsigned long rate_out, unsigned long rate ,u32 div_max) +{ + u32 div; + unsigned long new_rate; + for (div = 0; div rate==rate) + return clk->parent; + for(i=0;i<2;i++) + { + div[i]=clk_get_freediv(rate,clk->parents[i]->rate,clk->div_max); + new_rate[i] = clk->parents[i]->rate/div[i]; + if(new_rate[i]==rate) + { + *div_out=div[i]; + return clk->parents[i]; + } + } + if(new_rate[0]parents[i]; +} + +static int clkset_rate_freediv_autosel_parents(struct clk *clk, unsigned long rate) +{ + struct clk *p_clk; + u32 div,old_div; + int ret=0; + if(clk->rate==rate) + return 0; + p_clk=get_freediv_parents_div(clk,rate,&div); + + if(!p_clk) + return -ENOENT; + + CLKDATA_DBG("%s %lu,form %s\n",clk->name,rate,p_clk->name); + if (clk->parent != p_clk) + { + old_div=CRU_GET_REG_BITS_VAL(cru_readl(clk->clksel_con),clk->div_shift,clk->div_mask)+1; + + if(div>old_div) + { + set_cru_bits_w_msk(div-1,clk->div_mask,clk->div_shift,clk->clksel_con); + } + ret=clk_set_parent_nolock(clk,p_clk); + if(ret) + { + CLKDATA_ERR("%s can't set %lu,reparent err\n",clk->name,rate); + return -ENOENT; + } + } + //set div + set_cru_bits_w_msk(div-1,clk->div_mask,clk->div_shift,clk->clksel_con); + return 0; +} +#if 0 +//rate==div rate //hdmi +static int clk_freediv_autosel_parents_set_fixed_rate(struct clk *clk, unsigned long rate) +{ + struct clk *p_clk; + u32 div,old_div; + int ret; + p_clk=get_freediv_parents_div(clk,rate,&div); + + if(!p_clk) + return -ENOENT; + + if((p_clk->rate/div)!=rate||(p_clk->rate%div)) + return -ENOENT; + + if (clk->parent != p_clk) + { + old_div=CRU_GET_REG_BITS_VAL(cru_readl(clk->clksel_con), + clk->div_shift,clk->div_mask)+1; + if(div>old_div) + { + set_cru_bits_w_msk(div-1,clk->div_mask,clk->div_shift,clk->clksel_con); + } + ret=clk_set_parent_nolock(clk,p_clk); + if (ret) + { + CLKDATA_DBG("%s can't get rate%lu,reparent err\n",clk->name,rate); + return ret; + } + } + //set div + set_cru_bits_w_msk(div-1,clk->div_mask,clk->div_shift,clk->clksel_con); + return 0; +} +#endif +/************************round functions*****************/ +static long clksel_freediv_round_rate(struct clk *clk, unsigned long rate) +{ + return clk->parent->rate/clk_get_freediv(rate,clk->parent->rate,clk->div_max); +} + +static long clk_freediv_round_autosel_parents_rate(struct clk *clk, unsigned long rate) +{ + u32 div; + struct clk *p_clk; + if(clk->rate == rate) + return clk->rate; + p_clk=get_freediv_parents_div(clk,rate,&div); + if(!p_clk) + return 0; + return p_clk->rate/div; +} + +static const struct apll_clk_set* apll_clk_get_best_pll_set(unsigned long rate, + struct apll_clk_set *tables) +{ + const struct apll_clk_set *ps, *pt; + + /* find the arm_pll we want. */ + ps = pt = tables; + while (pt->rate) { + if (pt->rate == rate) { + ps = pt; + break; + } + // we are sorted, and ps->rate > pt->rate. + if ((pt->rate > rate || (rate - pt->rate < ps->rate - rate))) + ps = pt; + if (pt->rate < rate) + break; + pt++; + } + //CLKDATA_DBG("arm pll best rate=%lu\n",ps->rate); + return ps; +} +static long apll_clk_round_rate(struct clk *clk, unsigned long rate) +{ + return apll_clk_get_best_pll_set(rate, clk->pll->table)->rate; +} + +/************************others functions*****************/ +static void pll_wait_lock(int pll_idx) +{ + u32 pll_state[4]={1,0,2,3}; + u32 bit = 0x10u << pll_state[pll_idx]; + int delay = 24000000; + while (delay > 0) { + if ((cru_readl(PLL_CONS(pll_idx, 1)) & (0x1 << PLL_LOCK_SHIFT))) { + //CLKDATA_DBG("%s %08x\n", __func__, cru_readl(PLL_CONS(pll_idx, 1)) & (0x1 << PLL_LOCK_SHIFT)); + //CLKDATA_DBG("%s ! %08x\n", __func__, !(cru_readl(PLL_CONS(pll_idx, 1)) & (0x1 << PLL_LOCK_SHIFT))); + break; + } + delay--; + } + if (delay == 0) { + CLKDATA_ERR("wait pll bit 0x%x time out!\n", bit); + while(1); + } +} + +static int pll_clk_mode(struct clk *clk, int on) +{ + u8 pll_id = clk->pll->id; + // FIXME here 500 must be changed + u32 dly = 1500; + + CLKDATA_DBG("pll_mode %s(%d)\n", clk->name, on); + //FIXME + if (on) { + cru_writel(CRU_W_MSK_SETBIT(PLL_PWR_ON, PLL_BYPASS_SHIFT), PLL_CONS(pll_id, 0)); + rk_clock_udelay(dly); + pll_wait_lock(pll_id); + cru_writel(PLL_MODE_NORM(pll_id), CRU_MODE_CON); + } else { + cru_writel(PLL_MODE_SLOW(pll_id), CRU_MODE_CON); + cru_writel(CRU_W_MSK_SETBIT(PLL_PWR_DN, PLL_BYPASS_SHIFT), PLL_CONS(pll_id, 0)); + } + return 0; +} +static struct clk* clksel_get_parent(struct clk *clk) +{ + return clk->parents[(cru_readl(clk->clksel_con) >> clk->src_shift) & clk->src_mask]; +} +static int clksel_set_parent(struct clk *clk, struct clk *parent) +{ + u32 i; + if (unlikely(!clk->parents)) + return -EINVAL; + for (i = 0; (i parents_num); i++) { + if (clk->parents[i]!= parent) + continue; + set_cru_bits_w_msk(i,clk->src_mask,clk->src_shift,clk->clksel_con); + return 0; + } + return -EINVAL; +} + +static int gate_mode(struct clk *clk, int on) +{ + int idx = clk->gate_idx; + CLKDATA_DBG("ENTER %s clk=%s, on=%d\n", __func__, clk->name, on); + if (idx >= CLK_GATE_MAX) + return -EINVAL; + if(on) { + cru_writel(CLK_GATE_W_MSK(idx) | CLK_UN_GATE(idx), CLK_GATE_CLKID_CONS(idx)); + } else { + cru_writel(CLK_GATE_W_MSK(idx) | CLK_GATE(idx), CLK_GATE_CLKID_CONS(idx)); + } + return 0; +} +#define PLL_INT_MODE 1 +#define PLL_FRAC_MODE 0 + +#define rk2928_clock_udelay(a) udelay(a); +static int pll_clk_set_rate(struct pll_clk_set *clk_set, u8 pll_id) +{ + //enter slowmode + cru_writel(PLL_MODE_SLOW(pll_id), CRU_MODE_CON); + + cru_writel(clk_set->pllcon0, PLL_CONS(pll_id,0)); + cru_writel(clk_set->pllcon1, PLL_CONS(pll_id,1)); + cru_writel(clk_set->pllcon2, PLL_CONS(pll_id,2)); + + CLKDATA_DBG("id=%d,pllcon0%08x\n", pll_id, cru_readl(PLL_CONS(pll_id,0))); + CLKDATA_DBG("id=%d,pllcon1%08x\n", pll_id, cru_readl(PLL_CONS(pll_id,1))); + CLKDATA_DBG("id=%d,pllcon2%08x\n", pll_id, cru_readl(PLL_CONS(pll_id,2))); + //rk2928_clock_udelay(5); + + //wating lock state + rk2928_clock_udelay(clk_set->rst_dly); + pll_wait_lock(pll_id); + + //return form slow + cru_writel(PLL_MODE_NORM(pll_id), CRU_MODE_CON); + + return 0; +} +#define PLL_FREF_MIN (183*KHZ) +#define PLL_FREF_MAX (1500*MHZ) + +#define PLL_FVCO_MIN (300*MHZ) +#define PLL_FVCO_MAX (1500*MHZ) + +#define PLL_FOUT_MIN (18750*KHZ) +#define PLL_FOUT_MAX (1500*MHZ) + +#define PLL_NF_MAX (4096) +#define PLL_NR_MAX (64) +#define PLL_NO_MAX (16) + +static int pll_clk_check_legality(unsigned long fin_hz,unsigned long fout_hz, + u32 refdiv, u32 fbdiv, u32 postdiv1, u32 postdiv2) +{ + fin_hz /= MHZ; + if (fin_hz < 1 || fin_hz > 800) { + CLKDATA_ERR("%s fbdiv out of [1, 800]MHz\n", __func__); + return -1; + } + + if (fbdiv < 16 || fbdiv > 1600) { + CLKDATA_ERR("%s fbdiv out of [16, 1600]MHz\n", __func__); + return -1; + } + + if (fin_hz / refdiv < 1 || fin_hz / refdiv > 40) { + CLKDATA_ERR("%s fin / refdiv out of [1, 40]MHz\n", __func__); + return -1; + } + + if (fin_hz * fbdiv / refdiv < 400 || fin_hz * fbdiv / refdiv > 1600) { + CLKDATA_ERR("%s fin_hz * fbdiv / refdiv out of [400, 1600]MHz\n", __func__); + return -1; + } + + if (fin_hz * fbdiv / refdiv / postdiv1 / postdiv2 < 8 + || fin_hz * fbdiv / refdiv / postdiv1 / postdiv2 > 1600) { + CLKDATA_ERR("%s fin_hz * fbdiv / refdiv / postdiv1 / postdiv2 out of [8, 1600]MHz\n", __func__); + return -1; + } + +} + +static int pll_clk_check_legality_frac(unsigned long fin_hz,unsigned long fout_hz, + u32 refdiv, u32 fbdiv, u32 postdiv1, u32 postdiv2, u32 frac) +{ + fin_hz /= MHZ; + if (fin_hz < 10 || fin_hz > 800) { + CLKDATA_ERR("%s fin_hz out of [10, 800]MHz\n", __func__); + return -1; + } + if (fbdiv < 19 || fbdiv > 160) { + CLKDATA_ERR("%s fbdiv out of [19, 160]MHz\n", __func__); + return -1; + } + + if (fin_hz / refdiv < 1 || fin_hz / refdiv > 40) { + CLKDATA_ERR("%s fin / refdiv out of [1, 40]MHz\n", __func__); + return -1; + } + + if (fin_hz * fbdiv / refdiv < 400 || fin_hz * fbdiv / refdiv > 1600) { + CLKDATA_ERR("%s fin_hz * fbdiv / refdiv out of [400, 1600]MHz\n", __func__); + return -1; + } + + if (fin_hz * fbdiv / refdiv / postdiv1 / postdiv2 < 8 + || fin_hz * fbdiv / refdiv / postdiv1 / postdiv2 > 1600) { + CLKDATA_ERR("%s fin_hz * fbdiv / refdiv / postdiv1 / postdiv2 out of [8, 1600]MHz\n", __func__); + return -1; + } + +} +#define MIN_FOUTVCO_FREQ (400 * 1000 * 1000) +#define MAX_FOUTVCO_FREQ (1600 * 1000 * 1000) +static int 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; + } + } + CLKDATA_ERR("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 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; + + 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; + + printk("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 { + printk("******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); + printk("******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; + printk("******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; + printk("frac=%x\n", *frac); + } + return 0; +} +static int pll_set_con(u8 id, u32 refdiv, u32 fbdiv, u32 postdiv1, u32 postdiv2, u32 frac) +{ + struct pll_clk_set temp_clk_set; + temp_clk_set.pllcon0 = PLL_SET_FBDIV(fbdiv) | PLL_SET_POSTDIV1(postdiv1); + temp_clk_set.pllcon1 = PLL_SET_REFDIV(refdiv) | PLL_SET_POSTDIV2(postdiv2); + if (frac != 0) { + temp_clk_set.pllcon1 |= PLL_SET_DSMPD(0); + } else { + temp_clk_set.pllcon1 |= PLL_SET_DSMPD(1); + } + temp_clk_set.pllcon2 = PLL_SET_FRAC(frac); + temp_clk_set.rst_dly = 0; + CLKDATA_DBG("setting....\n"); + return pll_clk_set_rate(&temp_clk_set, id); +} +static int apll_clk_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long flags; + struct _pll_data *pll_data=clk->pll; + struct apll_clk_set *clk_set=(struct apll_clk_set*)pll_data->table; + + u32 fin_hz, fout_hz; + u32 refdiv, fbdiv, postdiv1, postdiv2, frac; + u8 pll_id = pll_data->id; + + fin_hz = clk->parent->rate; + fout_hz = rate; + + while(clk_set->rate) { + if (clk_set->rate == rate) { + break; + } + clk_set++; + } + + CLKDATA_DBG("%s %s %lu\n", __func__, clk->name, rate); + CLKDATA_DBG("pllcon0 %08x\n", cru_readl(PLL_CONS(0,0))); + CLKDATA_DBG("pllcon1 %08x\n", cru_readl(PLL_CONS(0,1))); + CLKDATA_DBG("pllcon2 %08x\n", cru_readl(PLL_CONS(0,2))); + //CLKDATA_DBG("pllcon3 %08x\n", cru_readl(PLL_CONS(0,3))); + CLKDATA_DBG("clksel0 %08x\n", cru_readl(CRU_CLKSELS_CON(0))); + CLKDATA_DBG("clksel1 %08x\n", cru_readl(CRU_CLKSELS_CON(1))); + if(clk_set->rate==rate) { + CLKDATA_DBG("apll get a rate\n"); + + //enter slowmode + local_irq_save(flags); + cru_writel(PLL_MODE_SLOW(pll_id), CRU_MODE_CON); + loops_per_jiffy = LPJ_24M; + + cru_writel(clk_set->pllcon0, PLL_CONS(pll_id,0)); + cru_writel(clk_set->pllcon1, PLL_CONS(pll_id,1)); + cru_writel(clk_set->pllcon2, PLL_CONS(pll_id,2)); + cru_writel(clk_set->clksel0, CRU_CLKSELS_CON(0)); + cru_writel(clk_set->clksel1, CRU_CLKSELS_CON(1)); + //local_irq_restore(flags); + + CLKDATA_DBG("pllcon0 %08x\n", cru_readl(PLL_CONS(0,0))); + CLKDATA_DBG("pllcon1 %08x\n", cru_readl(PLL_CONS(0,1))); + CLKDATA_DBG("pllcon2 %08x\n", cru_readl(PLL_CONS(0,2))); + CLKDATA_DBG("pllcon3 %08x\n", cru_readl(PLL_CONS(0,3))); + CLKDATA_DBG("clksel0 %08x\n", cru_readl(CRU_CLKSELS_CON(0))); + CLKDATA_DBG("clksel1 %08x\n", cru_readl(CRU_CLKSELS_CON(1))); + //rk2928_clock_udelay(5); + + //wating lock state + rk2928_clock_udelay(clk_set->rst_dly); + pll_wait_lock(pll_id); + + //return form slow + //local_irq_save(flags); + cru_writel(PLL_MODE_NORM(pll_id), CRU_MODE_CON); + loops_per_jiffy = clk_set->lpj; + local_irq_restore(flags); + } else { + // FIXME + pll_clk_get_set(clk->parent->rate, rate, &refdiv, &fbdiv, &postdiv1, &postdiv2, &frac); + pll_set_con(clk->pll->id, refdiv, fbdiv, postdiv1, postdiv2, frac); + } + + CLKDATA_DBG("setting OK\n"); + return 0; +} + +static int dpll_clk_set_rate(struct clk *clk, unsigned long rate) +{ + // FIXME do nothing here + CLKDATA_DBG("setting OK\n"); + return 0; +} + +static int cpll_clk_set_rate(struct clk *clk, unsigned long rate) +{ + // FIXME + struct _pll_data *pll_data=clk->pll; + struct pll_clk_set *clk_set=(struct pll_clk_set*)pll_data->table; + + unsigned long fin_hz, fout_hz; + u32 refdiv, fbdiv, postdiv1, postdiv2, frac; + fin_hz = clk->parent->rate; + fout_hz = rate; + + while(clk_set->rate) { + if (clk_set->rate == rate) { + break; + } + clk_set++; + } + + if(clk_set->rate==rate) { + CLKDATA_DBG("cpll get a rate\n"); + pll_clk_set_rate(clk_set, pll_data->id); + + } else { + CLKDATA_DBG("cpll get auto calc a rate\n"); + if(pll_clk_get_set(clk->parent->rate, rate, &refdiv, &fbdiv, &postdiv1, &postdiv2, &frac) != 0) { + pr_err("cpll auto set rate error\n"); + return -ENOENT; + } + CLKDATA_DBG("%s get fin=%lu, fout=%lu, rate=%lu, refdiv=%u, fbdiv=%u, postdiv1=%u, postdiv2=%u", + __func__, fin_hz, fout_hz, rate, refdiv, fbdiv, postdiv1, postdiv2); + pll_set_con(pll_data->id, refdiv, fbdiv, postdiv1, postdiv2, frac); + + } + + CLKDATA_DBG("setting OK\n"); + return 0; +} + +static int gpll_clk_set_rate(struct clk *clk, unsigned long rate) +{ + // FIXME + struct _pll_data *pll_data=clk->pll; + struct pll_clk_set *clk_set=(struct pll_clk_set*)pll_data->table; + + CLKDATA_DBG("******%s\n", __func__); + while(clk_set->rate) + { + CLKDATA_DBG("******%s clk_set->rate=%lu\n", __func__, clk_set->rate); + if (clk_set->rate == rate) { + break; + } + clk_set++; + } + if(clk_set->rate== rate) + { + pll_clk_set_rate(clk_set,pll_data->id); + //lpj_gpll = CLK_LOOPS_RECALC(rate); + } + else + { + CLKDATA_ERR("gpll is no corresponding rate=%lu\n", rate); + return -1; + } + CLKDATA_DBG("******%s end\n", __func__); + + return 0; +} + +/**********************pll datas*************************/ +static u32 rk2928_clock_flags = 0; +static struct _pll_data apll_data = SET_PLL_DATA(APLL_ID, (void *)apll_clks); +static struct _pll_data dpll_data = SET_PLL_DATA(DPLL_ID, NULL); +static struct _pll_data cpll_data = SET_PLL_DATA(CPLL_ID, (void *)cpll_clks); +static struct _pll_data gpll_data = SET_PLL_DATA(GPLL_ID, (void *)gpll_clks); +/*********************************************************/ +/************************clocks***************************/ +/*********************************************************/ + +static struct clk xin24m = { + .name = "xin24m", + .rate = 24 * MHZ, + .flags = RATE_FIXED, +}; + +static struct clk clk_12m = { + .name = "clk_12m", + .parent = &xin24m, + .rate = 12 * MHZ, + .flags = RATE_FIXED, +}; +/************************plls***********************/ +static struct clk arm_pll_clk = { + .name = "arm_pll", + .parent = &xin24m, + .mode = pll_clk_mode, + .recalc = plls_clk_recalc, + .set_rate = apll_clk_set_rate, + .round_rate = apll_clk_round_rate, + .pll = &apll_data, +}; + +static struct clk ddr_pll_clk = { + .name = "ddr_pll", + .parent = &xin24m, + .mode = pll_clk_mode, + .recalc = plls_clk_recalc, + .set_rate = dpll_clk_set_rate, + .pll = &dpll_data, +}; + +static struct clk codec_pll_clk = { + .name = "codec_pll", + .parent = &xin24m, + .mode = pll_clk_mode, + .recalc = plls_clk_recalc, + .set_rate = cpll_clk_set_rate, + .pll = &cpll_data, +}; + +static struct clk general_pll_clk = { + .name = "general_pll", + .parent = &xin24m, + .mode = pll_clk_mode, + .gate_idx = CLK_GATE_CPU_GPLL, + .recalc = plls_clk_recalc, + .set_rate = gpll_clk_set_rate, + .pll = &gpll_data, +}; +#define SELECT_FROM_2PLLS_GC {&general_pll_clk, &codec_pll_clk} +#define SELECT_FROM_2PLLS_CG {&codec_pll_clk, &general_pll_clk} + +GATE_CLK(ddrphy_src, ddr_pll_clk, DDRPHY_SRC); +GATE_CLK(ddrphy_gpll_src, general_pll_clk, DDRPHY_GPLL_SRC); +GATE_CLK(core_gpll, general_pll_clk, CORE_GPLL); +GATE_CLK(cpu_gpll, general_pll_clk, CPU_GPLL); +/*********ddr******/ +static int ddr_clk_set_rate(struct clk *c, unsigned long rate) +{ + // need to do nothing + return 0; +} + +static long ddr_clk_round_rate(struct clk *clk, unsigned long rate) +{ + return ddr_set_pll(rate / MHZ, 0) * MHZ; +} +static unsigned long ddr_clk_recalc_rate(struct clk *clk) +{ + unsigned long rate = clk->parent->recalc(clk->parent) >> 1; + return rate; +} + +static struct clk *clk_ddr_pllsel_parents[] = {&clk_ddrphy_src, &clk_ddrphy_gpll_src}; +static struct clk clk_ddr_pllsel = { + .name = "ddr_pllsel", + .parent = &ddr_pll_clk, + .clksel_con = CRU_CLKSELS_CON(26), + CRU_SRC_SET(0x1, 8), + CRU_PARENTS_SET(clk_ddr_pllsel_parents), +}; + +static struct clk clk_ddr_dll = { + .name = "ddr_dll", + .parent = &clk_ddr_pllsel, + .mode = gate_mode, + .gate_idx = CLK_GATE_DLL_DDR, + .set_rate = clksel_set_rate_freediv, + .recalc = clksel_recalc_div, + .clksel_con = CRU_CLKSELS_CON(5), + CRU_DIV_SET(0x3f, 0, 64), +}; + +static struct clk clk_ddrphy2x = { + .name = "ddrphy2x", + .parent = &clk_ddr_pllsel, + .mode = gate_mode, + .gate_idx = CLK_GATE_DDRPHY_SRC, + .recalc = clksel_recalc_shift, + .clksel_con = CRU_CLKSELS_CON(26), + CRU_DIV_SET(0x3, 0, 4), +}; + +static struct clk clk_ddrc = { + .name = "ddrc", + .parent = &clk_ddrphy2x, + .set_rate = ddr_clk_set_rate, + .recalc = ddr_clk_recalc_rate, + .round_rate = ddr_clk_round_rate, + .recalc = clksel_recalc_fixed_div2, +}; + +static struct clk clk_ddrphy = { + .name = "ddrphy", + .parent = &clk_ddrphy2x, + .recalc = clksel_recalc_fixed_div2, +}; + +/****************core*******************/ +#if 0 +static unsigned long core_clk_get_rate(struct clk *c) +{ + u32 div=(get_cru_bits(c->clksel_con,c->div_mask,c->div_shift)+1); + //c->parent->rate=c->parent->recalc(c->parent); + return c->parent->rate/div; +} +#endif +static long core_clk_round_rate(struct clk *clk, unsigned long rate) +{ + u32 div=(get_cru_bits(clk->clksel_con,clk->div_mask,clk->div_shift)+1); + return clk_round_rate_nolock(clk->parent,rate)/div; +} + +static int core_clksel_set_parent(struct clk *clk, struct clk *new_prt) +{ + // FIXME + u32 temp_div; + struct clk *old_prt; + + if(clk->parent==new_prt) + return 0; + if (unlikely(!clk->parents)) + return -EINVAL; + CLKDATA_DBG("%s,reparent %s\n",clk->name,new_prt->name); + //arm + old_prt=clk->parent; + + if(clk->parents[0]==new_prt) + { + new_prt->set_rate(new_prt,300*MHZ); + set_cru_bits_w_msk(0,clk->div_mask,clk->div_shift,clk->clksel_con); + } + else if(clk->parents[1]==new_prt) + { + + if(new_prt->rate>old_prt->rate) + { + temp_div=clk_get_freediv(old_prt->rate,new_prt->rate,clk->div_max); + set_cru_bits_w_msk(temp_div-1,clk->div_mask,clk->div_shift,clk->clksel_con); + } + set_cru_bits_w_msk(1,clk->src_mask,clk->src_shift,clk->clksel_con); + new_prt->set_rate(new_prt,300*MHZ); + } + else + return -1; + + return 0; +} + +// this clk is cpu? +static int arm_core_clk_set_rate(struct clk *c, unsigned long rate) +{ + int ret; + //set arm pll div 1 + //set_cru_bits_w_msk(0,c->div_mask,c->div_shift,c->clksel_con); + + CLKDATA_DBG("change clk pll %s to %lu\n",c->name,rate); + ret = clk_set_rate_nolock(c->parent, rate); + if (ret) { + CLKDATA_ERR("Failed to change clk pll %s to %lu\n",c->name,rate); + return ret; + } + CLKDATA_DBG("change clk pll %s to %lu OK\n",c->name,rate); + return 0; +} + +static struct clk *clk_core_pre_parents[2] = {&arm_pll_clk, &clk_core_gpll}; +static struct clk clk_dll_core = { + .name = "dll_core", + .parent = &arm_pll_clk, + .gate_idx = CLK_GATE_DLL_CORE, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(4), + CRU_DIV_SET(0x3f, 0, 64), +}; + +static struct clk clk_core_pre = { + .name = "core_pre", + .parent = &arm_pll_clk, + .recalc = clksel_recalc_div, + .set_rate = arm_core_clk_set_rate, + .round_rate = core_clk_round_rate, + .set_parent = core_clksel_set_parent, + .clksel_con = CRU_CLKSELS_CON(0), + CRU_DIV_SET(A9_CORE_DIV_MASK, A9_CORE_DIV_SHIFT, 32), + CRU_SRC_SET(0x1, CORE_CLK_PLL_SEL_SHIFT), + CRU_PARENTS_SET(clk_core_pre_parents), +}; + +static struct clk clk_core_periph = { + .name = "core_periph", + .parent = &clk_core_pre, + .mode = gate_mode, + .gate_idx = CLK_GATE_CORE_PERIPH, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(1), + CRU_DIV_SET(CORE_PERIPH_DIV_MASK, CORE_PERIPH_DIV_SHIFT, 16), +}; + +static struct clk clk_l2c = { + .name = "l2c", + .parent = &clk_core_pre, + .mode = gate_mode, + .gate_idx = CLK_GATE_CLK_L2C, +}; + +static struct clk aclk_core_pre = { + .name = "aclk_core_pre", + .parent = &clk_core_pre, + .mode = gate_mode, + .gate_idx = CLK_GATE_ACLK_CORE, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(1), + CRU_DIV_SET(ACLK_CORE_DIV_MASK, ACLK_CORE_DIV_SHIFT, 8), +}; + +/****************cpu*******************/ + +static struct clk *clk_cpu_div_parents[] = {&arm_pll_clk, &clk_cpu_gpll}; +/*seperate because of gating*/ +static struct clk clk_cpu_div = { + .name = "cpu_div", + .parent = &arm_pll_clk, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(0), + CRU_DIV_SET(ACLK_CPU_DIV_MASK, ACLK_CPU_DIV_SHIFT, 32), + CRU_SRC_SET(0x1, CPU_CLK_PLL_SEL_SHIFT), + CRU_PARENTS_SET(clk_cpu_div_parents), +}; +static struct clk aclk_cpu_pre = { + .name = "aclk_cpu_pre", + .parent = &clk_cpu_div, + .mode = gate_mode, + .gate_idx = CLK_GATE_ACLK_CPU, + .recalc = clksel_recalc_equal_parent, +}; +static struct clk hclk_cpu_pre = { + .name = "hclk_cpu_pre", + .parent = &aclk_cpu_pre, + .mode = gate_mode, + .gate_idx = CLK_GATE_HCLK_CPU, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(1), + CRU_DIV_SET(HCLK_CPU_DIV_MASK, HCLK_CPU_DIV_SHIFT, 4), +}; +static struct clk pclk_cpu_pre = { + .name = "pclk_cpu_pre", + .parent = &aclk_cpu_pre, + .mode = gate_mode, + .gate_idx = CLK_GATE_PCLK_CPU, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(1), + CRU_DIV_SET(PCLK_CPU_DIV_MASK, PCLK_CPU_DIV_SHIFT, 8), +}; +/****************vcodec*******************/ +// FIXME +static struct clk *clk_aclk_vepu_parents[] = SELECT_FROM_2PLLS_CG; +static struct clk *clk_aclk_vdpu_parents[] = SELECT_FROM_2PLLS_CG; +static struct clk aclk_vepu = { + .name = "aclk_vepu", + .parent = &codec_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_ACLK_VEPU_SRC, + .recalc = clksel_recalc_div, + .clksel_con = CRU_CLKSELS_CON(32), + .set_rate = clkset_rate_freediv_autosel_parents, + .round_rate = clk_freediv_round_autosel_parents_rate, + CRU_DIV_SET(0x1f, 0, 32), + CRU_SRC_SET(0x1, 7), + CRU_PARENTS_SET(clk_aclk_vepu_parents), +}; +static struct clk aclk_vdpu = { + .name = "aclk_vdpu", + .parent = &clk_cpu_div, + .mode = gate_mode, + .gate_idx = CLK_GATE_ACLK_VDPU_SRC, + .recalc = clksel_recalc_div, + .set_rate = clkset_rate_freediv_autosel_parents, + .round_rate = clk_freediv_round_autosel_parents_rate, + .clksel_con = CRU_CLKSELS_CON(32), + CRU_DIV_SET(0x1f, 8, 32), + CRU_SRC_SET(0x1, 15), + CRU_PARENTS_SET(clk_aclk_vdpu_parents), +}; +static struct clk hclk_vepu = { + .name = "hclk_vepu", + .parent = &aclk_vepu, + .mode = gate_mode, + .gate_idx = CLK_GATE_HCLK_VDPU, // hclk_vdpu and hclk_vepu use the same gating + .recalc = clksel_recalc_fixed_div4, +}; +static struct clk hclk_vdpu = { + .name = "hclk_vdpu", + .parent = &aclk_vepu, // do not use aclk_vdpu as hclk_vepu/hclk_vdpu src + .mode = gate_mode, + .gate_idx = CLK_GATE_HCLK_VDPU, + .recalc = clksel_recalc_fixed_div4, +}; + +/****************vio*******************/ +// name: lcdc0_aclk +static struct clk *clk_aclk_lcdc_parents[] = SELECT_FROM_2PLLS_CG; +static struct clk aclk_lcdc0_pre = { + .name = "aclk_lcdc0_pre", + .parent = &general_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_ACLK_LCDC0_SRC, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(31), + CRU_DIV_SET(0x1f, 0, 32), + CRU_SRC_SET(0x1, 7), + CRU_PARENTS_SET(clk_aclk_lcdc_parents), +}; +static struct clk aclk_lcdc1_pre = { + .name = "aclk_lcdc1_pre", + .parent = &general_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_ACLK_LCDC1_SRC, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(31), + CRU_DIV_SET(0x1f, 8, 32), + CRU_SRC_SET(0x1, 15), + CRU_PARENTS_SET(clk_aclk_lcdc_parents), +}; +static struct clk hclk_disp_pre = { + .name = "hclk_disp_pre", + .parent = &general_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_HCLK_DISP, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(30), + CRU_DIV_SET(0x1f, 8, 32), + CRU_SRC_SET(0x1, 15), + CRU_PARENTS_SET(clk_aclk_lcdc_parents), +}; + +/****************periph*******************/ +static struct clk *peri_aclk_parents[] = SELECT_FROM_2PLLS_GC; +static struct clk aclk_periph_pre = { + .name = "aclk_periph", + .parent = &general_pll_clk, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .mode = gate_mode, + .gate_idx = CLK_GATE_ACLK_PERIPH, + .clksel_con = CRU_CLKSELS_CON(10), + CRU_DIV_SET(PERI_ACLK_DIV_MASK, PERI_ACLK_DIV_SHIFT, 32), + CRU_SRC_SET(0x1, PERI_PLL_SEL_SHIFT), + CRU_PARENTS_SET(peri_aclk_parents), +}; + +static struct clk hclk_periph_pre = { + .name = "hclk_periph", + .parent = &aclk_periph_pre, + .recalc = clksel_recalc_shift, + .set_rate = clksel_set_rate_shift, + .mode = gate_mode, + .gate_idx = CLK_GATE_HCLK_PERIPH, + .clksel_con = CRU_CLKSELS_CON(10), + CRU_DIV_SET(PERI_HCLK_DIV_MASK, PERI_HCLK_DIV_SHIFT, 8), +}; + +static struct clk pclk_periph_pre = { + .name = "pclk_periph", + .parent = &aclk_periph_pre, + .recalc = clksel_recalc_shift, + .set_rate = clksel_set_rate_shift, + .mode = gate_mode, + .gate_idx = CLK_GATE_PCLK_PERIPH, + .clksel_con = CRU_CLKSELS_CON(10), + CRU_DIV_SET(PERI_PCLK_DIV_MASK, PERI_PCLK_DIV_SHIFT, 4), +}; + +static struct clk clk_crypto = { + .name = "clk_crypto", + .parent = &aclk_periph_pre, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(24), + CRU_DIV_SET(0x3, 0, 4), +}; + +/****************timer*******************/ +static struct clk *clk_timer0_parents[] = {&xin24m, &pclk_periph_pre}; +static struct clk *clk_timer1_parents[] = {&xin24m, &pclk_periph_pre}; +static struct clk clk_timer0 = { + .name = "timer0", + .parent = &xin24m, + .mode = gate_mode, + .gate_idx = CLK_GATE_TIMER0, + .recalc = clksel_recalc_equal_parent, + .clksel_con = CRU_CLKSELS_CON(2), + CRU_SRC_SET(0x1, 4), + CRU_PARENTS_SET(clk_timer0_parents), +}; +static struct clk clk_timer1 = { + .name = "timer1", + .parent = &xin24m, + .mode = gate_mode, + .gate_idx = CLK_GATE_TIMER1, + .recalc = clksel_recalc_equal_parent, + .clksel_con = CRU_CLKSELS_CON(2), + CRU_SRC_SET(0x1, 5), + CRU_PARENTS_SET(clk_timer1_parents), +}; +/****************sdmmc*******************/ +static struct clk *clk_sdmmc0_parents[] = SELECT_FROM_2PLLS_CG; +static struct clk clk_sdmmc0 = { + .name = "sdmmc0", + .parent = &general_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_MMC0_SRC, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_even, + .clksel_con = CRU_CLKSELS_CON(11), + CRU_SRC_SET(0x1, 6), + CRU_DIV_SET(0x3f,0,64), + CRU_PARENTS_SET(clk_sdmmc0_parents), +}; +#if 0 +static struct clk clk_sdmmc0_sample = { + .name = "sdmmc0_sample", + .parent = &general_pll_clk, + .recalc = , + //.set_rate = , + .clksel_con = , + CRU_DIV_SET(,,), +}; +static struct clk clk_sdmmc0_drv = { + .name = "sdmmc0_drv", + .parent = &clk_sdmmc0, + .recalc = , + //.set_rate = , + .clksel_con = , + CRU_DIV_SET(,,), +}; +#endif +/****************sdio*******************/ +static struct clk *clk_sdio_parents[] = SELECT_FROM_2PLLS_CG; +static struct clk clk_sdio = { + .name = "sdio", + .parent = &general_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_SDIO_SRC, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_even, + .clksel_con = CRU_CLKSELS_CON(12), + CRU_SRC_SET(0x1, 6), + CRU_DIV_SET(0x3f,0,64), + CRU_PARENTS_SET(clk_sdio_parents), +}; +#if 0 +static struct clk clk_sdio_sample = { + .name = "sdio_sample", + .parent = &general_pll_clk, + .recalc = , + //.set_rate = , + .clksel_con = , + CRU_DIV_SET(,,), +}; +static struct clk clk_sdio_drv = { + .name = "sdio_drv", + .parent = &clk_sdio, + .recalc = , + //.set_rate = , + .clksel_con = , + CRU_DIV_SET(,,), +}; +#endif +/****************emmc*******************/ +static struct clk *clk_emmc_parents[] = SELECT_FROM_2PLLS_CG; +static struct clk clk_emmc = { + .name = "emmc", + .parent = &general_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_EMMC_SRC, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .clksel_con =CRU_CLKSELS_CON(12), + CRU_SRC_SET(0x1, 7), + CRU_DIV_SET(0x3f,8,64), + CRU_PARENTS_SET(clk_emmc_parents), +}; +#if 0 +static struct clk clk_emmc_sample = { + .name = "emmc_sample", + .parent = &general_pll_clk, + .recalc = , + //.set_rate = , + .clksel_con = , + CRU_DIV_SET(,,), +}; +static struct clk clk_emmc_drv = { + .name = "emmc_drv", + .parent = &clk_emmc, + .recalc = , + //.set_rate = , + .clksel_con = , + CRU_DIV_SET(,,), +}; +#endif +/****************lcdc*******************/ +// DO NOT USE ARM_PLL +#if 0 +static int sclk_lcdc_set_rate(struct clk *clk, unsigned long rate) +{ + int ret = 0; + struct clk *parent; + + CLKDATA_DBG("enter %s clk=%s, rate=%lu\n", __func__, clk->name, rate); + parent = clk->parent; + ret = clk_set_rate_nolock(parent, rate); + set_cru_bits_w_msk(0, clk->div_mask, clk->div_shift, clk->clksel_con); + return ret; +} +#endif +static struct clk *dclk_lcdc_parents[] = SELECT_FROM_2PLLS_CG; +static struct clk dclk_lcdc0 = { + .name = "dclk_lcdc0", + .parent = &general_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_DCLK_LCDC0_SRC, + .recalc = clksel_recalc_div, + .set_rate = clkset_rate_freediv_autosel_parents, + //.set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(27), + CRU_DIV_SET(0xff, 8, 256), + CRU_SRC_SET(0x1, 0), + CRU_PARENTS_SET(dclk_lcdc_parents), +}; +static struct clk dclk_lcdc1 = { + .name = "dclk_lcdc1", + .parent = &general_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_DCLK_LCDC1_SRC, + .recalc = clksel_recalc_div, + .set_rate = clkset_rate_freediv_autosel_parents, + //.set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(28), + CRU_DIV_SET(0xff, 8, 256), + CRU_SRC_SET(0x1, 0), + CRU_PARENTS_SET(dclk_lcdc_parents), +}; +static struct clk *dclk_ebc_parents[] = SELECT_FROM_2PLLS_CG; +static struct clk dclk_ebc = { + .name = "dclk_ebc", + .parent = &general_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_DCLK_EBC_SRC, + .recalc = clksel_recalc_div, + //.set_rate = clkset_rate_freediv_autosel_parents, + .set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(23), + CRU_DIV_SET(0xff, 8, 256), + CRU_SRC_SET(0x1, 0), + CRU_PARENTS_SET(dclk_ebc_parents), +}; +/****************gps*******************/ +#if 0 +static struct clk hclk_gps_parents = SELECT_FROM_2PLLS_CG; +static struct clk hclk_gps = { + .name = "hclk_gps", + .parent = &general_pll_clk, + .recalc = , + //.set_rate = , + .clksel_con = , + CRU_DIV_SET(,,), +}; +#endif +/****************camera*******************/ +static int cif_out_set_rate(struct clk *clk, unsigned long rate) +{ + int ret = 0; + struct clk *parent; + + if (rate == 24 * MHZ) { + parent =clk->parents[1]; + } else { + parent=clk->parents[0]; + ret = clk_set_rate_nolock(parent, rate); + if (ret) + return ret; + } + if (clk->parent != parent) + ret = clk_set_parent_nolock(clk, parent); + + return ret; +} +static struct clk *clk_cif_out_div_parents[] = SELECT_FROM_2PLLS_CG; +static struct clk clk_cif_out_div = { + .name = "cif_out_div", + .parent = &general_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_CIF_OUT_SRC, + .recalc = clksel_recalc_div, + //.set_rate = clkset_rate_freediv_autosel_parents, + .set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(29), + CRU_SRC_SET(0x1, 0), + CRU_DIV_SET(0x1f, 1, 32), + CRU_PARENTS_SET(clk_cif_out_div_parents), +}; +static struct clk *clk_cif_out_parents[] = {&clk_cif_out_div, &xin24m}; +static struct clk clk_cif_out = { + .name = "cif0_out", + .parent = &clk_cif_out_div, + .set_rate = cif_out_set_rate, + .clksel_con = CRU_CLKSELS_CON(29), + CRU_SRC_SET(0x1, 7), + CRU_PARENTS_SET(clk_cif_out_parents), +}; +#if 0 +/*External clock*/ +static struct clk pclkin_cif0 = { + .name = "pclkin_cif0", + .mode = gate_mode, + .mode = gate_mode, + .gate_idx = CLK_GATE_PCLKIN_CIF, +}; + +static struct clk inv_cif0 = { + .name = "inv_cif0", + .parent = &pclkin_cif0, +}; + +static struct clk *cif0_in_parents[] = {&pclkin_cif0, &inv_cif0}; +static struct clk cif0_in = { + .name = "cif0_in", + .parent = &pclkin_cif0, + .clksel_con = CRU_CLKSELS_CON(30), + CRU_SRC_SET(0x1, 8), + CRU_PARENTS_SET(cif0_in_parents), +}; +#endif +/****************i2s*******************/ +#define I2S_SRC_DIV (0x0) +#define I2S_SRC_FRAC (0x1) +#define I2S_SRC_12M (0x2) + +static int i2s_set_rate(struct clk *clk, unsigned long rate) +{ + int ret = -EINVAL; + struct clk *parent; + + if (rate == clk->parents[I2S_SRC_12M]->rate){ + parent = clk->parents[I2S_SRC_12M]; + }else if((long)clk_round_rate_nolock(clk->parents[I2S_SRC_DIV],rate)==rate) + { + parent = clk->parents[I2S_SRC_DIV]; + } + else + { + parent =clk->parents[I2S_SRC_FRAC]; + } + + CLKDATA_DBG("%s %s set rate=%lu parent %s(old %s)\n", + __func__, clk->name,rate,parent->name,clk->parent->name); + + if(parent!=clk->parents[I2S_SRC_12M]) + { + ret = clk_set_rate_nolock(parent,rate);//div 1:1 + if (ret) + { + CLKDATA_DBG("%s set rate%lu err\n",clk->name,rate); + return ret; + } + } + + if (clk->parent != parent) + { + ret = clk_set_parent_nolock(clk, parent); + if (ret) + { + CLKDATA_DBG("%s can't get rate%lu,reparent err\n",clk->name,rate); + return ret; + } + } + + return ret; +}; +static struct clk *clk_i2s_div_parents[] = SELECT_FROM_2PLLS_GC; +static struct clk clk_i2s_pll = { + .name = "i2s_pll", + .parent = &general_pll_clk, + .clksel_con = CRU_CLKSELS_CON(2), + CRU_SRC_SET(0x1,15), + CRU_PARENTS_SET(clk_i2s_div_parents), +}; +static int i2s_fracdiv_set_rate(struct clk *clk, unsigned long rate) +{ + u32 numerator, denominator; + //clk_i2s_div->clk_i2s_pll->gpll/cpll + //clk->parent->parent + if(frac_div_get_seting(rate,clk->parent->parent->rate, + &numerator,&denominator)==0) + { + clk_set_rate_nolock(clk->parent,clk->parent->parent->rate);//PLL:DIV 1: + cru_writel_frac(numerator << 16 | denominator, clk->clksel_con); + CLKDATA_DBG("%s set rate=%lu,is ok\n",clk->name,rate); + } + else + { + CLKDATA_DBG("clk_frac_div can't get rate=%lu,%s\n",rate,clk->name); + return -ENOENT; + } + return 0; +} + + +static struct clk clk_i2s_div = { + .name = "i2s_div", + .parent = &clk_i2s_pll, + .mode = gate_mode, + .gate_idx = CLK_GATE_I2S_SRC, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + //.round_rate = clksel_freediv_round_rate, + .clksel_con = CRU_CLKSELS_CON(3), + CRU_DIV_SET(0x7f, 0, 128), +}; +static struct clk clk_i2s_frac_div = { + .name = "i2s_frac_div", + .parent = &clk_i2s_div, + .recalc = clksel_recalc_frac, + .set_rate = i2s_fracdiv_set_rate, + //.round_rate = clksel_freediv_round_rate, + .mode = gate_mode, + .gate_idx = CLK_GATE_I2S_FRAC_SRC, + .clksel_con = CRU_CLKSELS_CON(7), +}; + +static struct clk *clk_i2s_parents[] = {&clk_i2s_div, &clk_i2s_frac_div, &clk_12m}; +static struct clk clk_i2s = { + .name = "i2s", + .parent = &clk_i2s_div, + .set_rate = i2s_set_rate, + .clksel_con = CRU_CLKSELS_CON(3), + CRU_SRC_SET(0x3, 8), + CRU_PARENTS_SET(clk_i2s_parents), +}; + +/****************otgphy*******************/ +#if 0 +static struct clk clk_otgphy0 = { + .name = "otgphy0", + .parent = &clk_12m, + .recalc = , + //.set_rate = , + .clksel_con = , + CRU_DIV_SET(,,), +}; +static struct clk clk_otgphy1 = { + .name = "otgphy1", + .parent = &clk_12m, + .recalc = , + //.set_rate = , + .clksel_con = , + CRU_DIV_SET(,,), +}; +#endif +GATE_CLK(otgphy0, clk_12m, OTGPHY0); +GATE_CLK(otgphy1, clk_12m, OTGPHY1); +/****************saradc*******************/ +static struct clk clk_saradc = { + .name = "saradc", + .parent = &xin24m, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .mode = gate_mode, + .gate_idx = CLK_GATE_SARADC_SRC, + .clksel_con = CRU_CLKSELS_CON(24), + CRU_DIV_SET(0xff,8,256), +}; +/****************gpu_pre*******************/ +// name: gpu_aclk +static struct clk *clk_gpu_pre_parents[] = SELECT_FROM_2PLLS_CG; +static struct clk clk_gpu_pre = { + .name = "gpu_pre", + .parent = &general_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_GPU_PRE, + .recalc = clksel_recalc_div, + .set_rate = clkset_rate_freediv_autosel_parents, + //.set_rate = clksel_set_rate_freediv, + .round_rate = clk_freediv_round_autosel_parents_rate, + .clksel_con = CRU_CLKSELS_CON(34), + CRU_SRC_SET(0x1, 8), + CRU_DIV_SET(0x1f, 0, 32), + CRU_PARENTS_SET(clk_gpu_pre_parents), +}; + +static struct clk clk_dll_gpu = { + .name = "dll_gpu", + .parent = &general_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_GPU_PRE, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .round_rate = clksel_freediv_round_rate, + .clksel_con = CRU_CLKSELS_CON(6), + CRU_DIV_SET(0x3f, 0, 64), + CRU_PARENTS_SET(clk_gpu_pre_parents), +}; +/****************spi*******************/ +static struct clk *clk_spi_parents[] = SELECT_FROM_2PLLS_CG; +static struct clk clk_spi = { + .name = "spi", + .parent = &general_pll_clk, + .mode = gate_mode, + .gate_idx = CLK_GATE_SPI0_SRC, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .clksel_con = CRU_CLKSELS_CON(25), + CRU_SRC_SET(0x1, 8), + CRU_DIV_SET(0x7f, 0, 128), + CRU_PARENTS_SET(clk_spi_parents), +}; + +/****************uart*******************/ +static int clk_uart_fracdiv_set_rate(struct clk *clk, unsigned long rate) +{ + u32 numerator, denominator; + //clk_uart0_div->clk_uart_pll->gpll/cpll + //clk->parent->parent + if(frac_div_get_seting(rate,clk->parent->parent->rate, + &numerator,&denominator)==0) + { + clk_set_rate_nolock(clk->parent,clk->parent->parent->rate);//PLL:DIV 1: + + cru_writel_frac(numerator << 16 | denominator, clk->clksel_con); + + CLKDATA_DBG("%s set rate=%lu,is ok\n",clk->name,rate); + } + else + { + CLKDATA_ERR("clk_frac_div can't get rate=%lu,%s\n",rate,clk->name); + return -ENOENT; + } + return 0; +} +#define UART_SRC_DIV 0 +#define UART_SRC_FRAC 1 +#define UART_SRC_24M 2 +static int clk_uart_set_rate(struct clk *clk, unsigned long rate) +{ + int ret = 0; + struct clk *parent; + + if(rate==clk->parents[UART_SRC_24M]->rate)//24m + { + parent = clk->parents[UART_SRC_24M]; + } + else if((long)clk_round_rate_nolock(clk->parents[UART_SRC_DIV], rate)==rate) + { + parent = clk->parents[UART_SRC_DIV]; + } + else + { + parent = clk->parents[UART_SRC_FRAC]; + } + + + + CLKDATA_DBG(" %s set rate=%lu parent %s(old %s)\n", + clk->name,rate,parent->name,clk->parent->name); + + + if(parent!=clk->parents[UART_SRC_24M]) + { + ret = clk_set_rate_nolock(parent,rate); + if (ret) + { + CLKDATA_DBG("%s set rate%lu err\n",clk->name,rate); + return ret; + } + } + + if (clk->parent != parent) + { + ret = clk_set_parent_nolock(clk, parent); + if (ret) + { + CLKDATA_DBG("%s can't get rate%lu,reparent err\n",clk->name,rate); + return ret; + } + } + + + return ret; +} + + +static struct clk *clk_uart_pll_src_parents[] = SELECT_FROM_2PLLS_GC; +static struct clk clk_uart_pll = { + .name = "uart_pll", + .parent = &general_pll_clk, + .clksel_con = CRU_CLKSELS_CON(12), + CRU_SRC_SET(0x1, 15), + CRU_PARENTS_SET(clk_uart_pll_src_parents), +}; +static struct clk clk_uart0_div = { + .name = "uart0_div", + .parent = &clk_uart_pll, + .mode = gate_mode, + .gate_idx = CLK_GATE_UART0_SRC, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .round_rate = clksel_freediv_round_rate, + .clksel_con = CRU_CLKSELS_CON(13), + CRU_DIV_SET(0x7f, 0, 64), +}; +static struct clk clk_uart1_div = { + .name = "uart1_div", + .parent = &clk_uart_pll, + .mode = gate_mode, + .gate_idx = CLK_GATE_UART1_SRC, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .round_rate = clksel_freediv_round_rate, + .clksel_con = CRU_CLKSELS_CON(14), + CRU_DIV_SET(0x7f, 0, 64), +}; +static struct clk clk_uart2_div = { + .name = "uart2_div", + .parent = &clk_uart_pll, + .mode = gate_mode, + .gate_idx = CLK_GATE_UART2_SRC, + .recalc = clksel_recalc_div, + .set_rate = clksel_set_rate_freediv, + .round_rate = clksel_freediv_round_rate, + .clksel_con = CRU_CLKSELS_CON(15), + CRU_DIV_SET(0x7f, 0, 64), +}; +static struct clk clk_uart0_frac_div = { + .name = "uart0_frac_div", + .parent = &clk_uart0_div, + .mode = gate_mode, + .gate_idx = CLK_GATE_UART0_FRAC_SRC, + .recalc = clksel_recalc_frac, + .set_rate = clk_uart_fracdiv_set_rate, + .clksel_con = CRU_CLKSELS_CON(17), +}; +static struct clk clk_uart1_frac_div = { + .name = "uart1_frac_div", + .parent = &clk_uart1_div, + .mode = gate_mode, + .gate_idx = CLK_GATE_UART1_FRAC_SRC, + .recalc = clksel_recalc_frac, + .set_rate = clk_uart_fracdiv_set_rate, + .clksel_con = CRU_CLKSELS_CON(18), +}; +static struct clk clk_uart2_frac_div = { + .name = "uart2_frac_div", + .parent = &clk_uart2_div, + .mode = gate_mode, + .gate_idx = CLK_GATE_UART2_FRAC_SRC, + .recalc = clksel_recalc_frac, + .set_rate = clk_uart_fracdiv_set_rate, + .clksel_con = CRU_CLKSELS_CON(19), +}; + +static struct clk *clk_uart0_parents[] = {&clk_uart0_div, &clk_uart0_frac_div, &xin24m}; +static struct clk *clk_uart1_parents[] = {&clk_uart1_div, &clk_uart1_frac_div, &xin24m}; +static struct clk *clk_uart2_parents[] = {&clk_uart2_div, &clk_uart2_frac_div, &xin24m}; +static struct clk clk_uart0= { + .name = "uart0", + .parent = &xin24m, + .set_rate = clk_uart_set_rate, + .clksel_con = CRU_CLKSELS_CON(13), + CRU_SRC_SET(0x3, 8), + CRU_PARENTS_SET(clk_uart0_parents), +}; +static struct clk clk_uart1= { + .name = "uart1", + .parent = &xin24m, + .set_rate = clk_uart_set_rate, + .clksel_con = CRU_CLKSELS_CON(14), + CRU_SRC_SET(0x3, 8), + CRU_PARENTS_SET(clk_uart1_parents), +}; +static struct clk clk_uart2= { + .name = "uart2", + .parent = &xin24m, + .set_rate = clk_uart_set_rate, + .clksel_con = CRU_CLKSELS_CON(15), + CRU_SRC_SET(0x3, 8), + CRU_PARENTS_SET(clk_uart2_parents), +}; +/****************sub clock---pre*******************/ +/*************************aclk_cpu***********************/ +GATE_CLK(aclk_intmem, aclk_cpu_pre, ACLK_INTMEM); +GATE_CLK(aclk_strc_sys, aclk_cpu_pre, ACLK_STRC_SYS); + +/*************************hclk_cpu***********************/ +//FIXME +//GATE_CLK(hclk_cpubus, hclk_cpu_pre, HCLK_CPUBUS); +GATE_CLK(hclk_rom, hclk_cpu_pre, HCLK_ROM); + +/*************************pclk_cpu***********************/ +//FIXME +GATE_CLK(pclk_hdmi, pclk_cpu_pre, PCLK_HDMI); +GATE_CLK(pclk_acodec, pclk_cpu_pre, PCLK_ACODEC); +GATE_CLK(pclk_ddrupctl, pclk_cpu_pre, PCLK_DDRUPCTL); +GATE_CLK(pclk_grf, pclk_cpu_pre, PCLK_GRF); + +/*************************aclk_periph********************/ +GATE_CLK(aclk_peri_axi_matrix, aclk_periph_pre, ACLK_PERI_AXI_MATRIX); +GATE_CLK(aclk_dma2, aclk_periph_pre, ACLK_DMAC2); +GATE_CLK(aclk_peri_niu, aclk_periph_pre, ACLK_PERI_NIU); +GATE_CLK(aclk_cpu_peri, aclk_periph_pre, ACLK_CPU_PERI); +GATE_CLK(aclk_gps, aclk_periph_pre, ACLK_GPS); + +/*************************hclk_periph***********************/ +GATE_CLK(hclk_peri_axi_matrix, hclk_periph_pre, HCLK_PERI_AXI_MATRIX); +GATE_CLK(hclk_usb_peri, hclk_periph_pre, HCLK_USB_PERI); +GATE_CLK(hclk_otg0, clk_hclk_usb_peri, HCLK_OTG0); // is not parent in clk tree, but when hclk_otg0/1 open, +GATE_CLK(hclk_otg1, clk_hclk_usb_peri, HCLK_OTG1); // called hclk_otg20; must open hclk_usb_peri +GATE_CLK(hclk_i2s, hclk_periph_pre, HCLK_I2S); +GATE_CLK(hclk_peri_ahb_arbi, hclk_periph_pre, HCLK_PERI_ARBI); +GATE_CLK(nandc, hclk_periph_pre, HCLK_NANDC); +GATE_CLK(hclk_crypto, hclk_periph_pre, HCLK_CRYPTO); +GATE_CLK(hclk_sdmmc0, hclk_periph_pre, HCLK_SDMMC0); +GATE_CLK(hclk_sdio, hclk_periph_pre, HCLK_SDIO); +GATE_CLK(hclk_emmc, hclk_periph_pre, HCLK_EMMC); +GATE_CLK(hclk_emem_peri, hclk_periph_pre, HCLK_EMEM_PERI); + +/*************************pclk_periph***********************/ +GATE_CLK(pclk_peri_axi_matrix, pclk_periph_pre, PCLK_PERI_AXI_MATRIX); +GATE_CLK(pclk_spi0, pclk_periph_pre, PCLK_SPI0); +GATE_CLK(pclk_uart0, pclk_periph_pre, PCLK_UART0); +GATE_CLK(pclk_uart1, pclk_periph_pre, PCLK_UART1); +GATE_CLK(pclk_uart2, pclk_periph_pre, PCLK_UART2); +GATE_CLK(pclk_pwm01, pclk_periph_pre, PCLK_PWM01); +GATE_CLK(pclk_wdt, pclk_periph_pre, PCLK_WDT); +GATE_CLK(pclk_i2c0, pclk_periph_pre, PCLK_I2C0); +GATE_CLK(pclk_i2c1, pclk_periph_pre, PCLK_I2C1); +GATE_CLK(pclk_i2c2, pclk_periph_pre, PCLK_I2C2); +GATE_CLK(pclk_i2c3, pclk_periph_pre, PCLK_I2C3); +GATE_CLK(pclk_saradc, pclk_periph_pre, PCLK_SARADC); +GATE_CLK(pclk_efuse, pclk_periph_pre, PCLK_EFUSE); +GATE_CLK(pclk_timer0, pclk_periph_pre, PCLK_TIMER0); +GATE_CLK(pclk_timer1, pclk_periph_pre, PCLK_TIMER1); +GATE_CLK(gpio0, pclk_periph_pre, PCLK_GPIO0); +GATE_CLK(gpio1, pclk_periph_pre, PCLK_GPIO1); +GATE_CLK(gpio2, pclk_periph_pre, PCLK_GPIO2); +GATE_CLK(gpio3, pclk_periph_pre, PCLK_GPIO3); + +/*************************aclk_lcdc0***********************/ +GATE_CLK(aclk_lcdc0, aclk_lcdc0_pre, ACLK_LCDC0); +GATE_CLK(aclk_cif0, aclk_lcdc0_pre, ACLK_CIF); +GATE_CLK(aclk_rga, aclk_lcdc0_pre, ACLK_RGA); +GATE_CLK(aclk_vio0, aclk_lcdc0_pre, ACLK_VIO0); + +/*************************aclk_lcdc1***********************/ +GATE_CLK(aclk_lcdc1, aclk_lcdc1_pre, ACLK_LCDC1); +GATE_CLK(aclk_iep, aclk_lcdc1_pre, ACLK_IEP); +GATE_CLK(aclk_vio1_niu, aclk_lcdc1_pre, ACLK_VIO1); + +/*************************hclk_disp***********************/ +GATE_CLK(hclk_rga, hclk_disp_pre, HCLK_RGA); +GATE_CLK(hclk_lcdc0, hclk_disp_pre, HCLK_LCDC0); +GATE_CLK(hclk_lcdc1, hclk_disp_pre, HCLK_LCDC1); +GATE_CLK(hclk_iep, hclk_disp_pre, HCLK_IEP); +GATE_CLK(hclk_vio_bus, hclk_disp_pre, HCLK_VIO_BUS); +GATE_CLK(hclk_cif0, hclk_disp_pre, HCLK_CIF); +GATE_CLK(hclk_ebc, hclk_disp_pre, HCLK_EBC); + +/* Power domain, not exist in fact*/ +enum pmu_power_domain { + PD_A9_0 = 0, + PD_A9_1, + PD_ALIVE, + PD_RTC, + PD_SCU, + PD_CPU, + PD_PERI = 6, + PD_VIO, + PD_VIDEO, + PD_VCODEC = PD_VIDEO, + PD_GPU, + PD_DBG, +}; + +static int pm_off_mode(struct clk *clk, int on) +{ + return 0; +} +static struct clk pd_peri = { + .name = "pd_peri", + .flags = IS_PD, + .mode = pm_off_mode, + .gate_idx = PD_PERI, +}; + +static int pd_display_mode(struct clk *clk, int on) +{ + return 0; +} + +static struct clk pd_display = { + .name = "pd_display", + .flags = IS_PD, + .mode = pd_display_mode, + .gate_idx = PD_VIO, +}; + +static struct clk pd_lcdc0 = { + .parent = &pd_display, + .name = "pd_lcdc0", +}; +static struct clk pd_lcdc1 = { + .parent = &pd_display, + .name = "pd_lcdc1", +}; +static struct clk pd_cif0 = { + .parent = &pd_display, + .name = "pd_cif0", +}; +static struct clk pd_cif1 = { + .parent = &pd_display, + .name = "pd_cif1", +}; +static struct clk pd_rga = { + .parent = &pd_display, + .name = "pd_rga", +}; +static struct clk pd_ipp = { + .parent = &pd_display, + .name = "pd_ipp", +}; +static int pd_video_mode(struct clk *clk, int on) +{ + return 0; +} + +static struct clk pd_video = { + .name = "pd_video", + .flags = IS_PD, + .mode = pd_video_mode, + .gate_idx = PD_VIDEO, +}; + +static int pd_gpu_mode(struct clk *clk, int on) +{ + return 0; +} + +static struct clk pd_gpu = { + .name = "pd_gpu", + .flags = IS_PD, + .mode = pd_gpu_mode, + .gate_idx = PD_GPU, +}; +static struct clk pd_dbg = { + .name = "pd_dbg", + .flags = IS_PD, + .mode = pm_off_mode, + .gate_idx = PD_DBG, +}; + +#define PD_CLK(name) \ +{\ + .dev_id = NULL,\ + .con_id = #name,\ + .clk = &name,\ +} +/* Power domain END, not exist in fact*/ + +#define CLK(dev, con, ck) \ +{\ + .dev_id = dev,\ + .con_id = con,\ + .clk = ck,\ +} + +#define CLK_GATE_NODEV(name) \ +{\ + .dev_id = NULL,\ + .con_id = #name,\ + .clk = &clk_##name,\ +} + +static struct clk_lookup clks[] = { + CLK(NULL, "xin24m", &xin24m), + CLK(NULL, "xin12m", &clk_12m), + + CLK(NULL, "arm_pll", &arm_pll_clk), + CLK(NULL, "ddr_pll", &ddr_pll_clk), + CLK(NULL, "codec_pll", &codec_pll_clk), + CLK(NULL, "general_pll", &general_pll_clk), + + CLK_GATE_NODEV(ddrphy_src), + CLK_GATE_NODEV(ddrphy_gpll_src), + CLK_GATE_NODEV(core_gpll), + CLK_GATE_NODEV(cpu_gpll), + CLK(NULL, "ddr_pllsel", &clk_ddr_pllsel), + CLK(NULL, "ddrdll", &clk_ddr_dll), + CLK(NULL, "ddrphy2x", &clk_ddrphy2x), + CLK(NULL, "ddr", &clk_ddrc), + CLK(NULL, "ddrphy", &clk_ddrphy), + + CLK(NULL, "cpu", &clk_core_pre), + CLK(NULL, "core_periph", &clk_core_periph), + CLK(NULL, "l2c", &clk_l2c), + CLK(NULL, "aclk_core_pre", &aclk_core_pre), + CLK(NULL, "coredll", &clk_dll_core), + + CLK(NULL, "cpu_div", &clk_cpu_div), + CLK(NULL, "aclk_cpu_pre", &aclk_cpu_pre), + CLK(NULL, "pclk_cpu_pre", &pclk_cpu_pre), + CLK(NULL, "hclk_cpu_pre", &hclk_cpu_pre), + + CLK(NULL, "aclk_vepu", &aclk_vepu), + CLK(NULL, "aclk_vdpu", &aclk_vdpu), + CLK(NULL, "hclk_vepu", &hclk_vepu), + CLK(NULL, "hclk_vdpu", &hclk_vdpu), + + CLK(NULL, "aclk_lcdc0_pre", &aclk_lcdc0_pre), + CLK(NULL, "aclk_lcdc1_pre", &aclk_lcdc1_pre), + CLK(NULL, "hclk_lcdc1_pre", &hclk_disp_pre), + + CLK(NULL, "aclk_periph_pre", &aclk_periph_pre), + CLK(NULL, "pclk_periph_pre", &pclk_periph_pre), + CLK(NULL, "hclk_periph_pre", &hclk_periph_pre), + + CLK(NULL, "crypto", &clk_crypto), + + CLK(NULL, "timer0", &clk_timer0), + CLK(NULL, "timer1", &clk_timer1), + + CLK("rk29_sdmmc.0", "mmc", &clk_sdmmc0), + //CLK("rk29_sdmmc.0", "mmc_sample", &clk_sdmmc0_sample), + //CLK("rk29_sdmmc.0", "mmc_drv", &clk_sdmmc0_drv), + + CLK("rk29_sdmmc.1", "mmc", &clk_sdio), + //CLK("rk29_sdmmc.1", "mmc_sample", &clk_sdio_sample), + //CLK("rk29_sdmmc.1", "mmc_drv", &clk_sdio_drv), + + CLK(NULL, "emmc", &clk_emmc), + //CLK(NULL, "emmc_sample", &clk_emmc_sample), + //CLK(NULL, "emmc_drv", &clk_emmc_drv), + + CLK(NULL, "dclk_lcdc0", &dclk_lcdc0), + CLK(NULL, "dclk_lcdc1", &dclk_lcdc1), + CLK(NULL, "dclk_ebc", &dclk_ebc), + + CLK(NULL, "cif_out_div", &clk_cif_out_div), + CLK(NULL, "cif0_out", &clk_cif_out), +#if 0 + CLK(NULL, "pclkin_cif0", &pclkin_cif0), + CLK(NULL, "inv_cif0", &inv_cif0), + CLK(NULL, "cif0_in", &cif0_in), +#endif + CLK(NULL, "i2s_pll", &clk_i2s_pll), + CLK("rk29_i2s.0", "i2s_div", &clk_i2s_div), + CLK("rk29_i2s.0", "i2s_frac_div", &clk_i2s_frac_div), + CLK("rk29_i2s.0", "i2s", &clk_i2s), + + CLK(NULL, "otgphy0", &clk_otgphy0), + CLK(NULL, "otgphy1", &clk_otgphy1), + CLK(NULL, "saradc", &clk_saradc), + CLK(NULL, "gpudll", &clk_dll_gpu), + CLK(NULL, "gpu", &clk_gpu_pre), + + CLK("rk29xx_spim.0", "spi", &clk_spi), + + CLK(NULL, "uart_pll", &clk_uart_pll), + CLK("rk_serial.0", "uart_div", &clk_uart0_div), + CLK("rk_serial.1", "uart_div", &clk_uart1_div), + CLK("rk_serial.2", "uart_div", &clk_uart2_div), + CLK("rk_serial.0", "uart_frac_div", &clk_uart0_frac_div), + CLK("rk_serial.1", "uart_frac_div", &clk_uart1_frac_div), + CLK("rk_serial.2", "uart_frac_div", &clk_uart2_frac_div), + CLK("rk_serial.0", "uart", &clk_uart0), + CLK("rk_serial.1", "uart", &clk_uart1), + CLK("rk_serial.2", "uart", &clk_uart2), + + /*********fixed clock ******/ + CLK_GATE_NODEV(aclk_intmem), + CLK_GATE_NODEV(aclk_strc_sys), + + CLK_GATE_NODEV(hclk_rom), + + CLK_GATE_NODEV(pclk_hdmi), + CLK_GATE_NODEV(pclk_acodec), + CLK_GATE_NODEV(pclk_ddrupctl), + CLK_GATE_NODEV(pclk_grf), + + CLK_GATE_NODEV(aclk_peri_axi_matrix), + CLK_GATE_NODEV(aclk_dma2), + CLK_GATE_NODEV(aclk_peri_niu), + CLK_GATE_NODEV(aclk_cpu_peri), + CLK_GATE_NODEV(aclk_gps), + + CLK_GATE_NODEV(hclk_peri_axi_matrix), + CLK_GATE_NODEV(hclk_usb_peri), + CLK_GATE_NODEV(hclk_otg0), + CLK_GATE_NODEV(hclk_otg1), + CLK_GATE_NODEV(hclk_i2s), + CLK_GATE_NODEV(hclk_peri_ahb_arbi), + CLK_GATE_NODEV(nandc), + CLK_GATE_NODEV(hclk_crypto), + CLK("rk29_sdmmc.0", "hclk_mmc", &clk_hclk_sdmmc0), + CLK("rk29_sdmmc.1", "hclk_mmc", &clk_hclk_sdio), + CLK(NULL, "hclk_emmc", &clk_hclk_emmc), + CLK_GATE_NODEV(hclk_emem_peri), + + CLK_GATE_NODEV(pclk_peri_axi_matrix), + CLK("rk29xx_spim.0", "pclk_spi", &clk_pclk_spi0), + CLK("rk_serial.0", "pclk_uart", &clk_pclk_uart0), + CLK("rk_serial.1", "pclk_uart", &clk_pclk_uart1), + CLK("rk_serial.2", "pclk_uart", &clk_pclk_uart2), + CLK(NULL, "pwm01", &clk_pclk_pwm01), + CLK_GATE_NODEV(pclk_wdt), + CLK("rk30_i2c.0", "i2c", &clk_pclk_i2c0), + CLK("rk30_i2c.1", "i2c", &clk_pclk_i2c1), + CLK("rk30_i2c.2", "i2c", &clk_pclk_i2c2), + CLK("rk30_i2c.3", "i2c", &clk_pclk_i2c3), + CLK_GATE_NODEV(pclk_saradc), + CLK_GATE_NODEV(pclk_efuse), + CLK_GATE_NODEV(pclk_timer0), + CLK_GATE_NODEV(pclk_timer1), + CLK_GATE_NODEV(gpio0), + CLK_GATE_NODEV(gpio1), + CLK_GATE_NODEV(gpio2), + CLK_GATE_NODEV(gpio3), + + CLK_GATE_NODEV(aclk_lcdc0), + CLK_GATE_NODEV(aclk_cif0), + CLK_GATE_NODEV(aclk_rga), + CLK_GATE_NODEV(aclk_vio0), + + CLK_GATE_NODEV(aclk_lcdc1), + CLK_GATE_NODEV(aclk_iep), + CLK_GATE_NODEV(aclk_vio1_niu), + + CLK_GATE_NODEV(hclk_rga), + CLK_GATE_NODEV(hclk_lcdc0), + CLK_GATE_NODEV(hclk_lcdc1), + CLK_GATE_NODEV(hclk_iep), + CLK_GATE_NODEV(hclk_vio_bus), + CLK_GATE_NODEV(hclk_cif0), + CLK_GATE_NODEV(hclk_ebc), + + /* Power domain, not exist in fact*/ + PD_CLK(pd_peri), + PD_CLK(pd_display), + PD_CLK(pd_video), + PD_CLK(pd_lcdc0), + PD_CLK(pd_lcdc1), + PD_CLK(pd_cif0), + PD_CLK(pd_cif1), + PD_CLK(pd_rga), + PD_CLK(pd_ipp), + PD_CLK(pd_video), + PD_CLK(pd_gpu), + PD_CLK(pd_dbg), + +}; + +static void __init rk30_init_enable_clocks(void) +{ + CLKDATA_DBG("ENTER %s\n", __func__); + // core + clk_enable_nolock(&clk_core_pre); + clk_enable_nolock(&clk_core_periph); + clk_enable_nolock(&clk_l2c); + clk_enable_nolock(&aclk_core_pre); + + // logic + clk_enable_nolock(&aclk_cpu_pre); + clk_enable_nolock(&hclk_cpu_pre); + clk_enable_nolock(&pclk_cpu_pre); + + // ddr + clk_enable_nolock(&clk_ddrc); + clk_enable_nolock(&clk_ddrphy); + clk_enable_nolock(&clk_ddrphy2x); + + clk_enable_nolock(&aclk_periph_pre); + clk_enable_nolock(&pclk_periph_pre); + clk_enable_nolock(&hclk_periph_pre); + + // others + clk_enable_nolock(&clk_aclk_vio0); + clk_enable_nolock(&clk_pclk_pwm01); + clk_enable_nolock(&clk_hclk_otg0); + clk_enable_nolock(&clk_hclk_otg1); + +#if CONFIG_RK_DEBUG_UART == 0 + clk_enable_nolock(&clk_uart0); + clk_enable_nolock(&clk_pclk_uart0); + +#elif CONFIG_RK_DEBUG_UART == 1 + clk_enable_nolock(&clk_uart1); + clk_enable_nolock(&clk_pclk_uart1); + +#elif CONFIG_RK_DEBUG_UART == 2 + clk_enable_nolock(&clk_uart2); + clk_enable_nolock(&clk_pclk_uart2); +#endif + + /*************************aclk_cpu***********************/ + clk_enable_nolock(&clk_aclk_intmem); + clk_enable_nolock(&clk_aclk_strc_sys); + + /*************************hclk_cpu***********************/ + clk_enable_nolock(&clk_hclk_rom); + + /*************************pclk_cpu***********************/ + clk_enable_nolock(&clk_pclk_ddrupctl); + clk_enable_nolock(&clk_pclk_grf); + + /*************************aclk_periph***********************/ + clk_enable_nolock(&clk_aclk_dma2); + clk_enable_nolock(&clk_aclk_peri_niu); + clk_enable_nolock(&clk_aclk_cpu_peri); + clk_enable_nolock(&clk_aclk_peri_axi_matrix); + + /*************************hclk_periph***********************/ + clk_enable_nolock(&clk_hclk_peri_axi_matrix); + clk_enable_nolock(&clk_hclk_peri_ahb_arbi); + clk_enable_nolock(&clk_nandc); + + /*************************pclk_periph***********************/ + clk_enable_nolock(&clk_pclk_peri_axi_matrix); + /*************************hclk_vio***********************/ + clk_enable_nolock(&clk_hclk_vio_bus); +} + + +static void rk_dump_clock(struct clk *clk, int deep, const struct list_head *root_clocks) +{ + struct clk *ck; + int i; + unsigned long rate = clk->rate; + for (i = 0; i < deep; i++) + printk(" "); + + printk("%-11s ", clk->name); + if ((clk->mode == gate_mode) && (clk->gate_idx < CLK_GATE_MAX)) { + int idx = clk->gate_idx; + u32 v; + v = cru_readl(CLK_GATE_CLKID_CONS(idx)) & ((0x1) << (idx % 16)); + printk("%s ", v ? "off" : "on "); + } + + if (clk->pll) { + u32 pll_mode; + u32 pll_id = clk->pll->id; + pll_mode = cru_readl(CRU_MODE_CON)&PLL_MODE_MSK(pll_id); + if (pll_mode == (PLL_MODE_SLOW(pll_id) & PLL_MODE_MSK(pll_id))) + printk("slow "); + else if (pll_mode == (PLL_MODE_NORM(pll_id) & PLL_MODE_MSK(pll_id))) + printk("normal "); + //else if (pll_mode == (PLL_MODE_DEEP(pll_id) & PLL_MODE_MSK(pll_id))) + // printk("deep "); + + if(cru_readl(PLL_CONS(pll_id, 3)) & PLL_BYPASS) + printk("bypass "); + } else if(clk == &clk_ddrc) { + rate = clk->recalc(clk); + } + + if (rate >= MHZ) { + if (rate % MHZ) + printk("%ld.%06ld MHz", rate / MHZ, rate % MHZ); + else + printk("%ld MHz", rate / MHZ); + } else if (rate >= KHZ) { + if (rate % KHZ) + printk("%ld.%03ld KHz", rate / KHZ, rate % KHZ); + else + printk("%ld KHz", rate / KHZ); + } else { + printk("%ld Hz", rate); + } + + printk(" usecount = %d", clk->usecount); + + if (clk->parent) + printk(" parent = %s", clk->parent->name); + + printk("\n"); + + list_for_each_entry(ck, root_clocks, node) { + if (ck->parent == clk) + rk_dump_clock(ck, deep + 1, root_clocks); + } +} + +#if 1 +extern struct list_head *get_rk_clocks_head(void); + +void rk_dump_clock_info(void) +{ + struct clk* clk; + list_for_each_entry(clk, get_rk_clocks_head(), node) { + if (!clk->parent) + rk_dump_clock(clk, 0,get_rk_clocks_head()); + } +} +#endif + +#ifdef CONFIG_PROC_FS +static void dump_clock(struct seq_file *s, struct clk *clk, int deep,const struct list_head *root_clocks) +{ + struct clk* ck; + int i; + unsigned long rate = clk->rate; + //CLKDATA_DBG("dump_clock %s\n",clk->name); + for (i = 0; i < deep; i++) + seq_printf(s, " "); + + seq_printf(s, "%-11s ", clk->name); + + if ((clk->mode == gate_mode) && (clk->gate_idx < CLK_GATE_MAX)) { + int idx = clk->gate_idx; + u32 v; + v = cru_readl(CLK_GATE_CLKID_CONS(idx))&((0x1)<<(idx%16)); + seq_printf(s, "%s ", v ? "off" : "on "); + } + + if (clk->pll) + { + u32 pll_mode; + u32 pll_id=clk->pll->id; + pll_mode=cru_readl(CRU_MODE_CON)&PLL_MODE_MSK(pll_id); + if (pll_mode == (PLL_MODE_SLOW(pll_id) & PLL_MODE_MSK(pll_id))) + seq_printf(s, "slow "); + else if (pll_mode == (PLL_MODE_NORM(pll_id) & PLL_MODE_MSK(pll_id))) + seq_printf(s, "normal "); + if(cru_readl(PLL_CONS(pll_id,3)) & PLL_BYPASS) + seq_printf(s, "bypass "); + } + else if(clk == &ddr_pll_clk) { + rate = clk->recalc(clk); + } + + if (rate >= MHZ) { + if (rate % MHZ) + seq_printf(s, "%ld.%06ld MHz", rate / MHZ, rate % MHZ); + else + seq_printf(s, "%ld MHz", rate / MHZ); + } else if (rate >= KHZ) { + if (rate % KHZ) + seq_printf(s, "%ld.%03ld KHz", rate / KHZ, rate % KHZ); + else + seq_printf(s, "%ld KHz", rate / KHZ); + } else { + seq_printf(s, "%ld Hz", rate); + } + + seq_printf(s, " usecount = %d", clk->usecount); + + if (clk->parent) + seq_printf(s, " parent = %s", clk->parent->name); + + seq_printf(s, "\n"); + + list_for_each_entry(ck, root_clocks, node) { + if (ck->parent == clk) + dump_clock(s, ck, deep + 1,root_clocks); + } +} + +static void dump_regs(struct seq_file *s) +{ + int i=0; + seq_printf(s, "\nPLL(id=0 apll,id=1,dpll,id=2,cpll,id=3 cpll)\n"); + seq_printf(s, "\nPLLRegisters:\n"); + for(i=0;i>1; + pclk_p = aclk_p>>2; + break; + case 1188*MHZ: + aclk_p = aclk_p>>3;// 0 + hclk_p = aclk_p>>1; + pclk_p = aclk_p>>2; + + case 297 * MHZ: + aclk_p = gpll_rate>>0; + hclk_p = aclk_p>>1; + pclk_p = aclk_p>>1; + break; + + case 300 * MHZ: + aclk_p = gpll_rate>>1; + hclk_p = aclk_p>>0; + pclk_p = aclk_p>>1; + break; + default: + aclk_p = 150 * MHZ; + hclk_p = 150 * MHZ; + pclk_p = 75 * MHZ; + break; + } + clk_set_parent_nolock(&aclk_periph_pre, &general_pll_clk); + clk_set_rate_nolock(&aclk_periph_pre, aclk_p); + clk_set_rate_nolock(&hclk_periph_pre, hclk_p); + clk_set_rate_nolock(&pclk_periph_pre, pclk_p); +} + +static void cpu_axi_init(void) +{ + unsigned long aclk_cpu_rate, hclk_cpu_rate, pclk_cpu_rate; + unsigned long gpll_rate = general_pll_clk.rate; + switch (gpll_rate) { + case 297 * MHZ: + aclk_cpu_rate = gpll_rate >> 0; + hclk_cpu_rate = aclk_cpu_rate >> 1; + pclk_cpu_rate = aclk_cpu_rate >> 2; + break; + + default: + aclk_cpu_rate = 150 * MHZ; + hclk_cpu_rate = 150 * MHZ; + pclk_cpu_rate = 75 * MHZ; + break; + } + + clk_set_parent_nolock(&clk_cpu_div, &clk_cpu_gpll); + clk_set_rate_nolock(&clk_cpu_div, gpll_rate); + clk_set_rate_nolock(&aclk_cpu_pre, aclk_cpu_rate); + clk_set_rate_nolock(&hclk_cpu_pre, hclk_cpu_rate); + clk_set_rate_nolock(&pclk_cpu_pre, pclk_cpu_rate); +} + +#define CLK_FLG_MAX_I2S_12288KHZ (1<<1) +#define CLK_FLG_MAX_I2S_22579_2KHZ (1<<2) +#define CLK_FLG_MAX_I2S_24576KHZ (1<<3) +#define CLK_FLG_MAX_I2S_49152KHZ (1<<4) + +void rk2928_clock_common_i2s_init(void) +{ + unsigned long i2s_rate; + //struct clk *max_clk,*min_clk; + //20 times + if(rk2928_clock_flags & CLK_FLG_MAX_I2S_49152KHZ) { + i2s_rate = 49152000; + + } else if(rk2928_clock_flags & CLK_FLG_MAX_I2S_24576KHZ) { + i2s_rate = 24576000; + + } else if(rk2928_clock_flags & CLK_FLG_MAX_I2S_22579_2KHZ) { + i2s_rate = 22579000; + + } else if(rk2928_clock_flags & CLK_FLG_MAX_I2S_12288KHZ) { + i2s_rate = 12288000; + + } else { + i2s_rate = 49152000; + } + + if(((i2s_rate * 20) <= codec_pll_clk.rate) + || !(codec_pll_clk.rate % i2s_rate)) { + clk_set_parent_nolock(&clk_i2s_pll, &codec_pll_clk); + + } else if(((i2s_rate * 20) <= general_pll_clk.rate) + || !(general_pll_clk.rate % i2s_rate)) { + clk_set_parent_nolock(&clk_i2s_pll, &general_pll_clk); + + } else { + if(general_pll_clk.rate > codec_pll_clk.rate) + clk_set_parent_nolock(&clk_i2s_pll, &general_pll_clk); + else + clk_set_parent_nolock(&clk_i2s_pll, &codec_pll_clk); + } + +} +static void __init rk2928_clock_common_init(unsigned long gpll_rate,unsigned long cpll_rate) +{ + + //general + clk_set_rate_nolock(&general_pll_clk, gpll_rate); + //code pll + clk_set_rate_nolock(&codec_pll_clk, cpll_rate); + + cpu_axi_init(); + + clk_set_rate_nolock(&clk_core_pre, 600 * MHZ); + + //periph clk + periph_clk_set_init(); + + //i2s + rk2928_clock_common_i2s_init(); + + // spi + clk_set_rate_nolock(&clk_spi, clk_spi.parent->rate); + + // uart +#if 0 + clk_set_parent_nolock(&clk_uart_pll, &codec_pll_clk); +#else + clk_set_parent_nolock(&clk_uart_pll, &general_pll_clk); +#endif + //mac + // FIXME +#if 0 + if(!(gpll_rate%(50*MHZ))) + clk_set_parent_nolock(&clk_mac_pll_div, &general_pll_clk); + else if(!(ddr_pll_clk.rate%(50*MHZ))) + clk_set_parent_nolock(&clk_mac_pll_div, &ddr_pll_clk); + else + CRU_PRINTK_ERR("mac can't get 50mhz\n"); + //hsadc + //auto pll sel + //clk_set_parent_nolock(&clk_hsadc_pll_div, &general_pll_clk); + + //lcdc1 hdmi + //clk_set_parent_nolock(&dclk_lcdc1_div, &general_pll_clk); + + //lcdc0 lcd auto sel pll + //clk_set_parent_nolock(&dclk_lcdc0_div, &general_pll_clk); +#endif + + //cif + clk_set_parent_nolock(&clk_cif_out_div, &general_pll_clk); + + // FIXME yxj this plase cause display unusual + //clk_set_parent_nolock(&aclk_vio_pre, &general_pll_clk); + + //axi lcdc auto sel + //clk_set_parent_nolock(&aclk_lcdc0, &general_pll_clk); + //clk_set_parent_nolock(&aclk_lcdc1, &general_pll_clk); + // FIXME + + clk_set_rate_nolock(&aclk_lcdc0_pre, 300*MHZ); + clk_set_rate_nolock(&aclk_lcdc1_pre, 300*MHZ); + clk_set_rate_nolock(&hclk_disp_pre, 300*MHZ); + //axi vepu auto sel + clk_set_parent_nolock(&aclk_vepu, &codec_pll_clk); + clk_set_parent_nolock(&aclk_vdpu, &codec_pll_clk); + + clk_set_rate_nolock(&aclk_vepu, 200*MHZ); + clk_set_rate_nolock(&aclk_vdpu, 200*MHZ); + //gpu auto sel + //clk_set_parent_nolock(&clk_gpu_pre, &general_pll_clk); + clk_set_rate_nolock(&clk_gpu_pre, 133 * MHZ); + + clk_set_parent_nolock(&clk_sdmmc0, &general_pll_clk); + clk_set_parent_nolock(&clk_sdio, &general_pll_clk); + clk_set_parent_nolock(&clk_emmc, &general_pll_clk); + clk_set_parent_nolock(&dclk_lcdc0, &general_pll_clk); + clk_set_parent_nolock(&dclk_lcdc1, &general_pll_clk); + + clk_set_rate_nolock(&clk_sdmmc0, 24750000); + clk_set_rate_nolock(&clk_sdio, 24750000); + + rk_dump_clock_info(); +} +void __init _rk2928_clock_data_init(unsigned long gpll,unsigned long cpll,int flags) +{ + struct clk_lookup *clk; + clk_register_dump_ops(&dump_ops); + clk_register_default_ops_clk(&def_ops_clk); + + rk2928_clock_flags = flags; + + CLKDATA_DBG("%s total %d clks\n", __func__, ARRAY_SIZE(clks)); + for (clk = clks; clk < clks + ARRAY_SIZE(clks); clk++) { + CLKDATA_DBG("%s add dev_id=%s, con_id=%s\n", + __func__, clk->dev_id ? clk->dev_id : "NULL", clk->con_id ? clk->con_id : "NULL"); + clkdev_add(clk); + clk_register(clk->clk); + } + + CLKDATA_DBG("clk_recalculate_root_clocks_nolock\n"); + clk_recalculate_root_clocks_nolock(); + // print loader config + //rk_dump_clock_info(); + loops_per_jiffy = CLK_LOOPS_RECALC(arm_pll_clk.rate); + + /* + * Only enable those clocks we will need, let the drivers + * enable other clocks as necessary + */ + rk30_init_enable_clocks(); + /* + * Disable any unused clocks left on by the bootloader + */ + clk_disable_unused(); + + CLKDATA_DBG("rk2928_clock_common_init, gpll=%lu, cpll=%lu\n", gpll, cpll); + rk2928_clock_common_init(gpll, cpll); + preset_lpj = loops_per_jiffy; + + CLKDATA_DBG("%s clks init finish\n", __func__); +} + +int rk292x_dvfs_init(void); +void __init rk2928_clock_data_init(unsigned long gpll,unsigned long cpll,u32 flags) +{ + printk("%s version: 2013-7-17\n", __func__); + _rk2928_clock_data_init(gpll,cpll,flags); + rk292x_dvfs_init(); +} + diff --git a/arch/arm/mach-rk3026/include/mach/cru.h b/arch/arm/mach-rk3026/include/mach/cru.h new file mode 100755 index 000000000000..5308b5e71c40 --- /dev/null +++ b/arch/arm/mach-rk3026/include/mach/cru.h @@ -0,0 +1,561 @@ +#ifndef __MACH_CRU_H +#define __MACH_CRU_H + +enum rk_plls_id { + APLL_ID = 0, + DPLL_ID, + CPLL_ID, + GPLL_ID, + END_PLL_ID, +}; + +/*****cru reg offset*****/ + +#define CRU_MODE_CON 0x40 +#define CRU_CLKSEL_CON 0x44 +#define CRU_CLKGATE_CON 0xd0 +#define CRU_GLB_SRST_FST 0x100 +#define CRU_GLB_SRST_SND 0x104 +#define CRU_SOFTRST_CON 0x110 + +#define PLL_CONS(id, i) ((id) * 0x10 + ((i) * 4)) + +#define CRU_CLKSELS_CON_CNT (35) +#define CRU_CLKSELS_CON(i) (CRU_CLKSEL_CON + ((i) * 4)) + +#define CRU_CLKGATES_CON_CNT (10) +#define CRU_CLKGATES_CON(i) (CRU_CLKGATE_CON + ((i) * 4)) + +#define CRU_SOFTRSTS_CON_CNT (9) +#define CRU_SOFTRSTS_CON(i) (CRU_SOFTRST_CON + ((i) * 4)) + +#define CRU_MISC_CON (0x134) +#define CRU_GLB_CNT_TH (0x140) + +/*PLL_CON 0,1,2*/ +#define PLL_PWR_ON (0) +#define PLL_PWR_DN (1) +#define PLL_BYPASS (1 << 15) +#define PLL_NO_BYPASS (0 << 15) +//con0 +#define PLL_BYPASS_SHIFT (15) + +#define PLL_POSTDIV1_MASK (0x7) +#define PLL_POSTDIV1_SHIFT (12) +#define PLL_FBDIV_MASK (0xfff) +#define PLL_FBDIV_SHIFT (0) + +//con1 +#define PLL_RSTMODE_SHIFT (15) +#define PLL_RST_SHIFT (14) +#define PLL_PWR_DN_SHIFT (13) +#define PLL_DSMPD_SHIFT (12) +#define PLL_LOCK_SHIFT (10) + +#define PLL_POSTDIV2_MASK (0x7) +#define PLL_POSTDIV2_SHIFT (6) +#define PLL_REFDIV_MASK (0x3f) +#define PLL_REFDIV_SHIFT (0) + +//con2 +#define PLL_FOUT4PHASE_PWR_DN_SHIFT (27) +#define PLL_FOUTVCO_PWR_DN_SHIFT (26) +#define PLL_FOUTPOSTDIV_PWR_DN_SHIFT (25) +#define PLL_DAC_PWR_DN_SHIFT (24) + +#define PLL_FRAC_MASK (0xffffff) +#define 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_SET_BITS(val, bits_shift, msk) (((val) & (msk)) << (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 PLL_SET_REFDIV(val) CRU_W_MSK_SETBITS(val, PLL_REFDIV_SHIFT, PLL_REFDIV_MASK) +#define PLL_SET_FBDIV(val) CRU_W_MSK_SETBITS(val, PLL_FBDIV_SHIFT, PLL_FBDIV_MASK) +#define PLL_SET_POSTDIV1(val) CRU_W_MSK_SETBITS(val, PLL_POSTDIV1_SHIFT, PLL_POSTDIV1_MASK) +#define PLL_SET_POSTDIV2(val) CRU_W_MSK_SETBITS(val, PLL_POSTDIV2_SHIFT, PLL_POSTDIV2_MASK) +#define PLL_SET_FRAC(val) CRU_SET_BITS(val, PLL_FRAC_SHIFT, PLL_FRAC_MASK) + +#define PLL_GET_REFDIV(reg) CRU_GET_REG_BITS_VAL(reg, PLL_REFDIV_SHIFT, PLL_REFDIV_MASK) +#define PLL_GET_FBDIV(reg) CRU_GET_REG_BITS_VAL(reg, PLL_FBDIV_SHIFT, PLL_FBDIV_MASK) +#define PLL_GET_POSTDIV1(reg) CRU_GET_REG_BITS_VAL(reg, PLL_POSTDIV1_SHIFT, PLL_POSTDIV1_MASK) +#define PLL_GET_POSTDIV2(reg) CRU_GET_REG_BITS_VAL(reg, PLL_POSTDIV2_SHIFT, PLL_POSTDIV2_MASK) +#define PLL_GET_FRAC(reg) CRU_GET_REG_BITS_VAL(reg, PLL_FRAC_SHIFT, PLL_FRAC_MASK) + +//#define APLL_SET_BYPASS(val) CRU_SET_BIT(val, PLL_BYPASS_SHIFT) +#define PLL_SET_DSMPD(val) CRU_W_MSK_SETBIT(val, PLL_DSMPD_SHIFT) +#define PLL_GET_DSMPD(reg) CRU_GET_REG_BIT_VAL(reg, PLL_DSMPD_SHIFT) +/*******************MODE BITS***************************/ +#define PLL_MODE_MSK(id) (0x1 << ((id) * 4)) +#define PLL_MODE_SHIFT(id) ((id) * 4) +#define PLL_MODE_SLOW(id) (CRU_W_MSK_SETBIT(0x0, PLL_MODE_SHIFT(id))) +#define PLL_MODE_NORM(id) (CRU_W_MSK_SETBIT(0x1, PLL_MODE_SHIFT(id))) +/*******************CLKSEL0 BITS***************************/ +#define CLK_SET_DIV_CON_SUB1(val, bits_shift, msk) CRU_W_MSK_SETBITS((val - 1), bits_shift, msk) + +#define CPU_CLK_PLL_SEL_SHIFT (13) +#define CORE_CLK_PLL_SEL_SHIFT (7) +#define SEL_APLL (0) +#define SEL_GPLL (1) +#define CPU_SEL_PLL(plls) CRU_W_MSK_SETBIT(plls, CPU_CLK_PLL_SEL_SHIFT) +#define CORE_SEL_PLL(plls) CRU_W_MSK_SETBIT(plls, CORE_CLK_PLL_SEL_SHIFT) + +#define ACLK_CPU_DIV_MASK (0x1f) +#define ACLK_CPU_DIV_SHIFT (8) +#define A9_CORE_DIV_MASK (0x1f) +#define A9_CORE_DIV_SHIFT (0) + +#define RATIO_11 (1) +#define RATIO_21 (2) +#define RATIO_41 (4) +#define RATIO_81 (8) + +#define ACLK_CPU_DIV(val) CLK_SET_DIV_CON_SUB1(val, ACLK_CPU_DIV_SHIFT, ACLK_CPU_DIV_MASK) +#define CLK_CORE_DIV(val) CLK_SET_DIV_CON_SUB1(val, A9_CORE_DIV_SHIFT, A9_CORE_DIV_MASK) +/*******************CLKSEL1 BITS***************************/ +#define PCLK_CPU_DIV_MASK (0x7) +#define PCLK_CPU_DIV_SHIFT (12) +#define HCLK_CPU_DIV_MASK (0x3) +#define HCLK_CPU_DIV_SHIFT (8) +#define ACLK_CORE_DIV_MASK (0x7) +#define ACLK_CORE_DIV_SHIFT (4) +#define CORE_PERIPH_DIV_MASK (0xf) +#define CORE_PERIPH_DIV_SHIFT (0) + +#define PCLK_CPU_DIV(val) CLK_SET_DIV_CON_SUB1(val, PCLK_CPU_DIV_SHIFT, PCLK_CPU_DIV_MASK) +#define HCLK_CPU_DIV(val) CLK_SET_DIV_CON_SUB1(val, HCLK_CPU_DIV_SHIFT, HCLK_CPU_DIV_MASK) +#define ACLK_CORE_DIV(val) CLK_SET_DIV_CON_SUB1(val, ACLK_CORE_DIV_SHIFT, ACLK_CORE_DIV_MASK) +#define CLK_CORE_PERI_DIV(val) CLK_SET_DIV_CON_SUB1(val, CORE_PERIPH_DIV_SHIFT, CORE_PERIPH_DIV_MASK) + +/*******************clksel10***************************/ +#define PERI_PLL_SEL_SHIFT 15 +#define PERI_PCLK_DIV_MASK (0x3) +#define PERI_PCLK_DIV_SHIFT (12) +#define PERI_HCLK_DIV_MASK (0x3) +#define PERI_HCLK_DIV_SHIFT (8) +#define PERI_ACLK_DIV_MASK (0x1f) +#define PERI_ACLK_DIV_SHIFT (0) + +#define SEL_2PLL_GPLL (0) +#define SEL_2PLL_CPLL (1) + +#define PERI_CLK_SEL_PLL(plls) CRU_W_MSK_SETBIT(plls, PERI_PLL_SEL_SHIFT) +#define PERI_SET_ACLK_DIV(val) CLK_SET_DIV_CON_SUB1(val, PERI_ACLK_DIV_SHIFT, PERI_ACLK_DIV_MASK) +/*******************gate BITS***************************/ +#define CLK_GATE_CLKID_CONS(i) CRU_CLKGATES_CON((i) / 16) + +#define CLK_GATE(i) (1 << ((i)%16)) +#define CLK_UN_GATE(i) (0) + +#define CLK_GATE_W_MSK(i) (1 << (((i) % 16) + 16)) +#define CLK_GATE_CLKID(i) (16 * (i)) + +enum cru_clk_gate { + /* SCU CLK GATE 0 CON */ + CLK_GATE_CORE_PERIPH = CLK_GATE_CLKID(0), + CLK_GATE_CPU_GPLL, + CLK_GATE_DDRPHY_SRC, + CLK_GATE_ACLK_CPU, + + CLK_GATE_HCLK_CPU, + CLK_GATE_PCLK_CPU, + CLK_GATE_CORE_GPLL, + CLK_GATE_ACLK_CORE, + + CLK_GATE_DDRPHY_GPLL_SRC, + CLK_GATE_I2S_SRC, + CLK_GATE_I2S_FRAC_SRC, + CLK_GATE_HCLK_DISP, + + CLK_GATE_CRYPTO, + CLK_GATE_0RES13, + CLK_GATE_0RES14, + CLK_GATE_TESTCLK, + + CLK_GATE_TIMER0 = CLK_GATE_CLKID(1), + CLK_GATE_TIMER1, + CLK_GATE_1RES2, + CLK_GATE_JTAG, + + CLK_GATE_ACLK_LCDC1_SRC, + CLK_GATE_OTGPHY0, + CLK_GATE_OTGPHY1, + CLK_GATE_DLL_DDR, + + CLK_GATE_UART0_SRC, + CLK_GATE_UART0_FRAC_SRC, + CLK_GATE_UART1_SRC, + CLK_GATE_UART1_FRAC_SRC, + + CLK_GATE_UART2_SRC, + CLK_GATE_UART2_FRAC_SRC, + CLK_GATE_DLL_GPU, + CLK_GATE_DLL_CORE, + + CLK_GATE_PERIPH_SRC = CLK_GATE_CLKID(2), + CLK_GATE_ACLK_PERIPH, + CLK_GATE_HCLK_PERIPH, + CLK_GATE_PCLK_PERIPH, + + CLK_GATE_2RES4, + CLK_GATE_2RES5, + CLK_GATE_2RES6, + CLK_GATE_2RES7, + + CLK_GATE_SARADC_SRC, + CLK_GATE_SPI0_SRC, + CLK_GATE_2RES10, + CLK_GATE_MMC0_SRC, + + CLK_GATE_2RES12, + CLK_GATE_SDIO_SRC, + CLK_GATE_EMMC_SRC, + CLK_GATE_2RES15, + + CLK_GATE_ACLK_LCDC0_SRC = CLK_GATE_CLKID(3), + CLK_GATE_DCLK_LCDC0_SRC, + CLK_GATE_DCLK_LCDC1_SRC, + CLK_GATE_PCLKIN_CIF, + + CLK_GATE_DCLK_EBC_SRC, + CLK_GATE_HCLK_CRYPTO, + CLK_GATE_HCLK_EMEM_PERI, + CLK_GATE_CIF_OUT_SRC, + + CLK_GATE_PCLK_HDMI, + CLK_GATE_ACLK_VEPU_SRC, + CLK_GATE_3RES10, + CLK_GATE_ACLK_VDPU_SRC, + + CLK_GATE_HCLK_VDPU, + CLK_GATE_GPU_PRE, + CLK_GATE_ACLK_GPS, + CLK_GATE_3RES15, + + CLK_GATE_HCLK_PERI_AXI_MATRIX = CLK_GATE_CLKID(4), + CLK_GATE_PCLK_PERI_AXI_MATRIX, + CLK_GATE_ACLK_CPU_PERI, + CLK_GATE_ACLK_PERI_AXI_MATRIX, + + CLK_GATE_4RES4, + CLK_GATE_4RES5, + CLK_GATE_4RES6, + CLK_GATE_4RES7, + + CLK_GATE_4RES8, + CLK_GATE_4RES9, + CLK_GATE_ACLK_STRC_SYS, + CLK_GATE_4RES11, + + CLK_GATE_ACLK_INTMEM, + CLK_GATE_4RES13, + CLK_GATE_4RES14, + CLK_GATE_4RES15, + + CLK_GATE_5RES0 = CLK_GATE_CLKID(5), + CLK_GATE_ACLK_DMAC2, + CLK_GATE_PCLK_EFUSE, + CLK_GATE_5RES3, + + CLK_GATE_PCLK_GRF, + CLK_GATE_5RES5, + CLK_GATE_HCLK_ROM, + CLK_GATE_PCLK_DDRUPCTL, + + CLK_GATE_5RES8, + CLK_GATE_HCLK_NANDC, + CLK_GATE_HCLK_SDMMC0, + CLK_GATE_HCLK_SDIO, + + CLK_GATE_5RES12, + CLK_GATE_HCLK_OTG0, + CLK_GATE_PCLK_ACODEC, + CLK_GATE_5RES15, + + CLK_GATE_ACLK_LCDC0 = CLK_GATE_CLKID(6), + CLK_GATE_HCLK_LCDC0, + CLK_GATE_6RES2, + CLK_GATE_6RES3, + + CLK_GATE_HCLK_CIF, + CLK_GATE_ACLK_CIF, + CLK_GATE_6RES6, + CLK_GATE_6RES7, + + CLK_GATE_6RES8, + CLK_GATE_6RES9, + CLK_GATE_HCLK_RGA, + CLK_GATE_ACLK_RGA, + + CLK_GATE_HCLK_VIO_BUS, + CLK_GATE_ACLK_VIO0, + CLK_GATE_6RES14, + CLK_GATE_6RES15, + + CLK_GATE_HCLK_EMMC = CLK_GATE_CLKID(7), + CLK_GATE_7RES1, + CLK_GATE_HCLK_I2S, + CLK_GATE_HCLK_OTG1, + + CLK_GATE_7RES4, + CLK_GATE_7RES5, + CLK_GATE_7RES6, + CLK_GATE_PCLK_TIMER0, + + CLK_GATE_PCLK_TIMER1, + CLK_GATE_7RES9, + CLK_GATE_PCLK_PWM01, + CLK_GATE_7RES11, + + CLK_GATE_PCLK_SPI0, + CLK_GATE_7RES13, + CLK_GATE_PCLK_SARADC, + CLK_GATE_PCLK_WDT, + + CLK_GATE_PCLK_UART0 = CLK_GATE_CLKID(8), + CLK_GATE_PCLK_UART1, + CLK_GATE_PCLK_UART2, + CLK_GATE_8RES3, + + CLK_GATE_PCLK_I2C0, + CLK_GATE_PCLK_I2C1, + CLK_GATE_PCLK_I2C2, + CLK_GATE_PCLK_I2C3, + + CLK_GATE_8RES8, + CLK_GATE_PCLK_GPIO0, + CLK_GATE_PCLK_GPIO1, + CLK_GATE_PCLK_GPIO2, + + CLK_GATE_PCLK_GPIO3, + CLK_GATE_8RES13, + CLK_GATE_8RES14, + CLK_GATE_8RES15, + + CLK_GATE_CLK_CORE_DBG = CLK_GATE_CLKID(9), + CLK_GATE_PCLK_DBG, + CLK_GATE_9RES2, + CLK_GATE_9RES3, + + CLK_GATE_CLK_L2C, + CLK_GATE_HCLK_LCDC1, + CLK_GATE_ACLK_LCDC1, + CLK_GATE_HCLK_IEP, + + CLK_GATE_ACLK_IEP, + CLK_GATE_HCLK_EBC, + CLK_GATE_ACLK_VIO1, + CLK_GATE_9RES11, + + CLK_GATE_9RES12, + CLK_GATE_HCLK_USB_PERI, + CLK_GATE_HCLK_PERI_ARBI, + CLK_GATE_ACLK_PERI_NIU, + + CLK_GATE_MAX, +}; + +#define SOFT_RST_ID(i) (16 * (i)) + +enum cru_soft_reset { + SOFT_RST_CORE_SRST_WDT_SEL = SOFT_RST_ID(0), + SOFT_RST_0RES1, + SOFT_RST_MCORE, + SOFT_RST_CORE0, + + SOFT_RST_CORE1, + SOFT_RST_0RES5, + SOFT_RST_0RES6, + SOFT_RST_MCORE_DBG, + + SOFT_RST_CORE0_DBG, + SOFT_RST_CORE1_DBG, + SOFT_RST_CORE0_WDT, + SOFT_RST_CORE1_WDT, + + SOFT_RST_0RES12, + SOFT_RST_ACLK_CORE, + SOFT_RST_STRC_SYS_AXI, + SOFT_RST_L2C, + + SOFT_RST_1RES0 = SOFT_RST_ID(1), + SOFT_RST_CPUSYS_AHB, + SOFT_RST_L2MEM_CON_AXI, + SOFT_RST_AHB2APB, + + SOFT_RST_1RES4, + SOFT_RST_INTMEM, + SOFT_RST_ROM, + SOFT_RST_PERI_NIU, + + SOFT_RST_I2S, + SOFT_RST_DDR_DLL, + SOFT_RST_GPU_DLL, + SOFT_RST_TIMER0, + + SOFT_RST_TIMER1, + SOFT_RST_CORE_DLL, + SOFT_RST_EFUSE_APB, + SOFT_RST_ACODEC, + + SOFT_RST_GPIO0 = SOFT_RST_ID(2), + SOFT_RST_GPIO1, + SOFT_RST_GPIO2, + SOFT_RST_GPIO3, + + SOFT_RST_2RES4, + SOFT_RST_2RES5, + SOFT_RST_2RES6, + SOFT_RST_UART0, + + SOFT_RST_UART1, + SOFT_RST_UART2, + SOFT_RST_2RES10, + SOFT_RST_I2C0, + + SOFT_RST_I2C1, + SOFT_RST_I2C2, + SOFT_RST_I2C3, + SOFT_RST_2RES15, + + SOFT_RST_PWM0 = SOFT_RST_ID(3), + SOFT_RST_PWM1, + SOFT_RST_DAP_PO, + SOFT_RST_DAP, + + SOFT_RST_DAP_SYS, + SOFT_RST_CRYPTO, + SOFT_RST_3RES6, + SOFT_RST_GRF, + + SOFT_RST_3RES8, + SOFT_RST_PERIPHSYS_AXI, + SOFT_RST_PERIPHSYS_AHB, + SOFT_RST_PERIPHSYS_APB, + + SOFT_RST_PWM2, + SOFT_RST_CPU_PERI, + SOFT_RST_EMEM_PERI, + SOFT_RST_USB_PERI, + + SOFT_RST_DMA2 = SOFT_RST_ID(4), + SOFT_RST_4RES1, + SOFT_RST_4RES2, + SOFT_RST_GPS, + + SOFT_RST_NANDC, + SOFT_RST_USBOTG0, + SOFT_RST_4RES6, + SOFT_RST_OTGC0, + + SOFT_RST_USBOTG1, + SOFT_RST_4RES9, + SOFT_RST_OTGC1, + SOFT_RST_4RES11, + + SOFT_RST_4RES12, + SOFT_RST_4RES13, + SOFT_RST_4RES14, + SOFT_RST_DDRMSCH, + + SOFT_RST_5RES0 = SOFT_RST_ID(5), + SOFT_RST_MMC0, + SOFT_RST_SDIO, + SOFT_RST_EMMC, + + SOFT_RST_SPI0, + SOFT_RST_5RES5, + SOFT_RST_WDT, + SOFT_RST_SARADC, + + SOFT_RST_DDRPHY, + SOFT_RST_DDRPHY_APB, + SOFT_RST_DDRCTRL, + SOFT_RST_DDRCTRL_APB, + + SOFT_RST_5RES12, + SOFT_RST_5RES13, + SOFT_RST_5RES14, + SOFT_RST_5RES15, + + SOFT_RST_HDMI_PCLK = SOFT_RST_ID(6), + SOFT_RST_VIO_ARBI_AHB, + SOFT_RST_VIO0_AXI, + SOFT_RST_VIO_BUS_AHB, + + SOFT_RST_LCDC0_AXI, + SOFT_RST_LCDC0_AHB, + SOFT_RST_LCDC0_DCLK, + SOFT_RST_UTMI0, + + SOFT_RST_UTMI1, + SOFT_RST_USBPOR, + SOFT_RST_IEP_AXI, + SOFT_RST_IEP_AHB, + + SOFT_RST_RGA_AXI, + SOFT_RST_RGA_AHB, + SOFT_RST_CIF0, + SOFT_RST_6RES15, + + SOFT_RST_VCODEC_AXI = SOFT_RST_ID(7), + SOFT_RST_VCODEC_AHB, + SOFT_RST_VIO1_AXI, + SOFT_RST_7RES3, + + SOFT_RST_VCODEC_NIU_AXI, + SOFT_RST_LCDC1_AXI, + SOFT_RST_LCDC1_AHB, + SOFT_RST_LCDC1_DCLK, + + SOFT_RST_GPU, + SOFT_RST_7RES9, + SOFT_RST_GPU_NIU_AXI, + SOFT_RST_EBC_AXI, + + SOFT_RST_EBC_AHB, + SOFT_RST_7RES13, + SOFT_RST_7RES14, + SOFT_RST_7RES15, + + SOFT_RST_8RES0 = SOFT_RST_ID(8), + SOFT_RST_8RES1, + SOFT_RST_CORE_DBG, + SOFT_RST_DBG_APB, + + SOFT_RST_8RES4, + SOFT_RST_8RES5, + SOFT_RST_8RES6, + SOFT_RST_8RES7, + + SOFT_RST_8RES8, + SOFT_RST_8RES9, + SOFT_RST_8RES10, + SOFT_RST_8RES11, + + SOFT_RST_8RES12, + SOFT_RST_8RES13, + SOFT_RST_8RES14, + SOFT_RST_8RES15, + + SOFT_RST_MAX, +}; + +/*****cru reg end*****/ +static inline void cru_set_soft_reset(enum cru_soft_reset idx, bool on) +{ + const void __iomem *reg = RK2928_CRU_BASE + CRU_SOFTRSTS_CON(idx >> 4); + u32 val = on ? 0x10001U << (idx & 0xf) : 0x10000U << (idx & 0xf); + writel_relaxed(val, reg); + dsb(); +} + +#endif -- 2.34.1