static void sunxi_clk_fators_disable(struct clk_hw *hw) { struct sunxi_clk_factors *factor = to_clk_factor(hw); struct sunxi_clk_factors_config *config = factor->config; unsigned long reg; unsigned long flags = 0; if(factor->flags & CLK_IGNORE_DISABLE) return; /* check if the pll disabled already */ reg = factor_readl(factor, factor->reg); if(!GET_BITS(config->enshift, 1, reg)) return; if(factor->lock) spin_lock_irqsave(factor->lock, flags); reg = factor_readl(factor, factor->reg); if(config->sdmwidth) reg = SET_BITS(config->sdmshift, config->sdmwidth, reg, 0); /* update for pll_ddr register */ if(config->updshift) reg = SET_BITS(config->updshift, 1, reg, 1); /* disable pll */ reg = SET_BITS(config->enshift, 1, reg, 0); factor_writel(factor,reg, factor->reg); /* disable pll lock if needed */ sunxi_clk_disable_plllock(factor); if(factor->lock) spin_unlock_irqrestore(factor->lock, flags); }
static int sunxi_clk_disable_plllock(struct sunxi_clk_factors *factor) { volatile u32 reg; switch (factor->lock_mode) { case PLL_LOCK_NEW_MODE: case PLL_LOCK_OLD_MODE: { /* make sure pll new mode is disable */ reg = factor_readl(factor,factor->pll_lock_ctrl_reg); reg = SET_BITS(factor->lock_en_bit, 1, reg, 0); factor_writel(factor,reg, factor->pll_lock_ctrl_reg); reg = factor_readl(factor, factor->pll_lock_ctrl_reg); reg = SET_BITS(28, 1, reg, 0); factor_writel(factor, reg, factor->pll_lock_ctrl_reg); return 0; } case PLL_LOCK_NONE_MODE: { return 0; } default: { WARN(1, "invaid pll lock mode:%u\n", factor->lock_mode); return -1; } } }
static int sunxi_clk_fators_enable(struct clk_hw *hw) { struct sunxi_clk_factors *factor = to_clk_factor(hw); struct sunxi_clk_factors_config *config = factor->config; unsigned long reg = factor_readl(factor,factor->reg); unsigned int loop = 300; unsigned long flags = 0; if(factor->lock) spin_lock_irqsave(factor->lock, flags); if(config->sdmwidth) { factor_writel(factor,config->sdmval, (void __iomem *)config->sdmpat); reg = SET_BITS(config->sdmshift, config->sdmwidth, reg, 1); } //enable the register reg = SET_BITS(config->enshift, 1, reg, 1); if(config->updshift) //update for pll_ddr register reg = SET_BITS(config->updshift, 1, reg, 1); factor_writel(factor,reg, factor->reg); while(loop--) { reg = factor_readl(factor,factor->lock_reg); if(GET_BITS(factor->lock_bit, 1, reg)) break; else udelay(10); } if(factor->lock) spin_unlock_irqrestore(factor->lock, flags); if(!loop) #if (defined CONFIG_FPGA_V4_PLATFORM) || (defined CONFIG_FPGA_V7_PLATFORM) printk("clk %s wait lock timeout\n",hw->clk->name); #else WARN(1, "clk %s wait lock timeout\n",hw->clk->name); #endif return 0; }
static unsigned long sunxi_clk_factors_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { unsigned long reg; struct clk_factors_value factor_val; struct sunxi_clk_factors *factor = to_clk_factor(hw); struct sunxi_clk_factors_config *config = factor->config; unsigned long flags = 0; if(!factor->calc_rate) return 0; if(factor->lock) spin_lock_irqsave(factor->lock, flags); reg = factor_readl(factor,factor->reg); if(factor->lock) spin_unlock_irqrestore(factor->lock, flags); if(config->nwidth) factor_val.factorn = GET_BITS(config->nshift, config->nwidth, reg); else factor_val.factorn = 0xffff; if(config->kwidth) factor_val.factork = GET_BITS(config->kshift, config->kwidth, reg); else factor_val.factork = 0xffff; if(config->mwidth) factor_val.factorm = GET_BITS(config->mshift, config->mwidth, reg); else factor_val.factorm = 0xffff; if(config->pwidth) factor_val.factorp = GET_BITS(config->pshift, config->pwidth, reg); else factor_val.factorp = 0xffff; if(config->d1width) factor_val.factord1 = GET_BITS(config->d1shift, config->d1width, reg); else factor_val.factord1 = 0xffff; if(config->d2width) factor_val.factord2 = GET_BITS(config->d2shift, config->d2width, reg); else factor_val.factord2 = 0xffff; if(config->frac) { factor_val.frac_mode = GET_BITS(config->modeshift, 1, reg); factor_val.frac_freq = GET_BITS(config->outshift, 1, reg); } else { factor_val.frac_mode = 0xffff; factor_val.frac_freq = 0xffff; } return factor->calc_rate(parent_rate, &factor_val); }
static int sunxi_clk_fators_enable(struct clk_hw *hw) { struct sunxi_clk_factors *factor = to_clk_factor(hw); struct sunxi_clk_factors_config *config = factor->config; unsigned long reg; unsigned long flags = 0; /* check if the pll enabled already */ reg = factor_readl(factor, factor->reg); if(GET_BITS(config->enshift, 1, reg)) return 0; if(factor->lock) spin_lock_irqsave(factor->lock, flags); sunxi_clk_disable_plllock(factor); /* get factor register value */ reg = factor_readl(factor, factor->reg); if(config->sdmwidth) { factor_writel(factor, config->sdmval, (void __iomem *)config->sdmpat); reg = SET_BITS(config->sdmshift, config->sdmwidth, reg, 1); } /* enable the register */ reg = SET_BITS(config->enshift, 1, reg, 1); /* update for pll_ddr register */ if(config->updshift) reg = SET_BITS(config->updshift, 1, reg, 1); factor_writel(factor,reg, factor->reg); if (sunxi_clk_is_lock(factor)) { if(factor->lock) spin_unlock_irqrestore(factor->lock, flags); WARN(1, "clk %s wait lock timeout\n", factor->hw.clk->name); return -1; } if(factor->lock) spin_unlock_irqrestore(factor->lock, flags); return 0; }
static int sunxi_clk_fators_is_enabled(struct clk_hw *hw) { unsigned long val; struct sunxi_clk_factors *factor = to_clk_factor(hw); struct sunxi_clk_factors_config *config = factor->config; unsigned long reg = factor_readl(factor,factor->reg); val = GET_BITS(config->enshift, 1, reg); return val ? 1 : 0; }
static void sunxi_clk_fators_disable(struct clk_hw *hw) { struct sunxi_clk_factors *factor = to_clk_factor(hw); struct sunxi_clk_factors_config *config = factor->config; unsigned long reg = factor_readl(factor,factor->reg); if(config->sdmwidth) reg = SET_BITS(config->sdmshift, config->sdmwidth, reg, 0); reg = SET_BITS(config->enshift, 1, reg, 0); factor_writel(factor,reg, factor->reg); }
static int sunxi_clk_fators_enable(struct clk_hw *hw) { struct sunxi_clk_factors *factor = to_clk_factor(hw); struct sunxi_clk_factors_config *config = factor->config; unsigned long reg = factor_readl(factor,factor->reg); if(config->sdmwidth) { factor_writel(factor,config->sdmval, (void __iomem *)config->sdmpat); reg = SET_BITS(config->sdmshift, config->sdmwidth, reg, 1); } reg = SET_BITS(config->enshift, 1, reg, 1); factor_writel(factor,reg, factor->reg); return 0; }
static int sunxi_clk_fators_is_enabled(struct clk_hw *hw) { unsigned long val; struct sunxi_clk_factors *factor = to_clk_factor(hw); struct sunxi_clk_factors_config *config = factor->config; unsigned long reg; unsigned long flags = 0; if(factor->lock) spin_lock_irqsave(factor->lock, flags); reg = factor_readl(factor,factor->reg); val = GET_BITS(config->enshift, 1, reg); if(factor->lock) spin_unlock_irqrestore(factor->lock, flags); return val ? 1 : 0; }
static int sunxi_clk_is_lock(struct sunxi_clk_factors *factor) { volatile u32 reg; u32 loop = 5000; switch (factor->lock_mode) { case PLL_LOCK_NEW_MODE: { /* enable pll new mode */ reg = factor_readl(factor, factor->pll_lock_ctrl_reg); reg = SET_BITS(28, 1, reg, 1); factor_writel(factor, reg, factor->pll_lock_ctrl_reg); reg = factor_readl(factor, factor->pll_lock_ctrl_reg); reg = SET_BITS(factor->lock_en_bit, 1, reg, 1); factor_writel(factor, reg, factor->pll_lock_ctrl_reg); while(loop--) { reg = factor_readl(factor,factor->lock_reg); if(GET_BITS(factor->lock_bit, 1, reg)) { udelay(20); break; } else { udelay(1); } } reg = factor_readl(factor,factor->pll_lock_ctrl_reg); reg = SET_BITS(factor->lock_en_bit, 1, reg, 0); factor_writel(factor,reg, factor->pll_lock_ctrl_reg); reg = factor_readl(factor, factor->pll_lock_ctrl_reg); reg = SET_BITS(28, 1, reg, 0); factor_writel(factor, reg, factor->pll_lock_ctrl_reg); if(!loop) { #if (defined CONFIG_FPGA_V4_PLATFORM) || (defined CONFIG_FPGA_V7_PLATFORM) printk("clk %s wait lock timeout\n", factor->hw.clk->name); return 0; #else WARN(1, "clk %s wait lock timeout\n", factor->hw.clk->name); return -1; #endif } return 0; } case PLL_LOCK_OLD_MODE: case PLL_LOCK_NONE_MODE: { while(loop--) { reg = factor_readl(factor,factor->lock_reg); if(GET_BITS(factor->lock_bit, 1, reg)) { udelay(20); break; } else { udelay(1); } } if(!loop) { #if (defined CONFIG_FPGA_V4_PLATFORM) || (defined CONFIG_FPGA_V7_PLATFORM) printk("clk %s wait lock timeout\n", factor->hw.clk->name); #else WARN(1, "clk %s wait lock timeout\n", factor->hw.clk->name); return -1; #endif } return 0; } default: { WARN(1, "invaid pll lock mode:%u\n", factor->lock_mode); return -1; } } }
static int sunxi_clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { unsigned long reg; struct clk_factors_value factor_val; struct sunxi_clk_factors *factor = to_clk_factor(hw); struct sunxi_clk_factors_config *config = factor->config; unsigned long flags = 0; if(!factor->get_factors) return 0; /* factor_val is initialized with its original value, * it's factors(such as:M,N,K,P,d1,d2...) are Random Value. * if donot judge the return value of "factor->get_factors", * it may change the original register value. */ if(factor->get_factors(rate, parent_rate, &factor_val) < 0) { /* cannot get right factors for clk,just break */ WARN(1, "clk %s set rate failed! Because cannot get right factors for clk\n", hw->clk->name); return 0; } if(factor->flags & CLK_RATE_FLAT_FACTORS) return sunxi_clk_factors_set_flat_facotrs(factor, &factor_val); if(factor->lock) spin_lock_irqsave(factor->lock, flags); sunxi_clk_disable_plllock(factor); reg = factor_readl(factor, factor->reg); if(config->sdmwidth) { factor_writel(factor, config->sdmval, (void __iomem *)config->sdmpat); reg = SET_BITS(config->sdmshift, config->sdmwidth, reg, 1); } if(config->nwidth) reg = SET_BITS(config->nshift, config->nwidth, reg, factor_val.factorn); if(config->kwidth) reg = SET_BITS(config->kshift, config->kwidth, reg, factor_val.factork); if(config->mwidth) reg = SET_BITS(config->mshift, config->mwidth, reg, factor_val.factorm); if(config->pwidth) reg = SET_BITS(config->pshift, config->pwidth, reg, factor_val.factorp); if(config->d1width) reg = SET_BITS(config->d1shift, config->d1width, reg, factor_val.factord1); if(config->d2width) reg = SET_BITS(config->d2shift, config->d2width, reg, factor_val.factord2); if(config->frac) { reg = SET_BITS(config->modeshift, 1, reg, factor_val.frac_mode); reg = SET_BITS(config->outshift, 1, reg, factor_val.frac_freq); } if(config->updshift) //update for pll_ddr register reg = SET_BITS(config->updshift, 1, reg, 1); factor_writel(factor,reg, factor->reg); #ifndef CONFIG_SUNXI_CLK_DUMMY_DEBUG if(GET_BITS(config->enshift, 1, reg)) { if (sunxi_clk_is_lock(factor)) { if(factor->lock) spin_unlock_irqrestore(factor->lock, flags); WARN(1, "clk %s wait lock timeout\n", factor->hw.clk->name); return -1; } } #endif if(factor->lock) spin_unlock_irqrestore(factor->lock, flags); return 0; }
static int sunxi_clk_factors_set_flat_facotrs(struct sunxi_clk_factors *factor, struct clk_factors_value *values) { struct sunxi_clk_factors_config *config = factor->config; u32 reg, tmp_factor_p, tmp_factor_m; unsigned long flags = 0; if(factor->lock) spin_lock_irqsave(factor->lock, flags); sunxi_clk_disable_plllock(factor); /*get all factors from the regitsters*/ reg = factor_readl(factor,factor->reg); tmp_factor_p = config->pwidth ? GET_BITS(config->pshift, config->pwidth, reg) : 0 ; tmp_factor_m = config->mwidth ? GET_BITS(config->mshift, config->mwidth, reg) : 0 ; /* 1).try to increase factor p first */ if(config->pwidth && (tmp_factor_p < values->factorp)) { reg = factor_readl(factor, factor->reg); reg = SET_BITS(config->pshift, config->pwidth, reg, values->factorp); factor_writel(factor,reg, factor->reg); if(factor->flags & CLK_RATE_FLAT_DELAY) udelay(config->delay); } /* 2).try to increase factor m first */ if(config->mwidth && (tmp_factor_m < values->factorm)) { reg = factor_readl(factor, factor->reg); reg = SET_BITS( config->mshift, config->mwidth, reg, values->factorm ); factor_writel(factor, reg, factor->reg); if(factor->flags & CLK_RATE_FLAT_DELAY) udelay(config->delay); } /* 3. write factor n & k */ reg = factor_readl(factor, factor->reg); if(config->nwidth) reg = SET_BITS(config->nshift, config->nwidth, reg, values->factorn); if(config->kwidth) reg = SET_BITS(config->kshift, config->kwidth, reg, values->factork); factor_writel(factor,reg, factor->reg); /* 4. do pair things for 2). decease factor m */ if(config->mwidth && (tmp_factor_m > values->factorm)) { reg = factor_readl(factor, factor->reg); reg = SET_BITS(config->mshift, config->mwidth, reg, values->factorm); factor_writel(factor, reg, factor->reg); if( factor->flags & CLK_RATE_FLAT_DELAY) udelay(config->delay); } /* 5. wait for PLL state stable */ if (sunxi_clk_is_lock(factor)) { if(factor->lock) spin_unlock_irqrestore(factor->lock, flags); WARN(1, "clk %s wait lock timeout\n", factor->hw.clk->name); return -1; } /*6.do pair things for 1). decease factor p */ if(config->pwidth && (tmp_factor_p > values->factorp)) { reg = factor_readl(factor, factor->reg); reg = SET_BITS(config->pshift, config->pwidth, reg, values->factorp); factor_writel(factor,reg, factor->reg); if(factor->flags & CLK_RATE_FLAT_DELAY) udelay(config->delay); } if(factor->lock) spin_unlock_irqrestore(factor->lock, flags); return 0; }
static int sunxi_clk_factors_set_flat_facotrs(struct sunxi_clk_factors *factor , struct clk_factors_value *values) { struct sunxi_clk_factors_config *config = factor->config; u32 reg, tmp_factor_p, tmp_factor_m; unsigned long flags = 0; #ifdef CONFIG_EVB_PLATFORM unsigned int loop = 300; /*lock loops*/ #endif if(factor->lock) spin_lock_irqsave(factor->lock, flags); /*get all factors from the regitsters*/ reg = factor_readl(factor,factor->reg); tmp_factor_p = config->pwidth ? GET_BITS( config->pshift , config->pwidth , reg) : 0 ; tmp_factor_m = config->mwidth ? GET_BITS( config->mshift , config->mwidth , reg) : 0 ; /* 1).try to increase factor p first */ if( config->pwidth && tmp_factor_p < values->factorp ) { reg = SET_BITS( config->pshift , config->pwidth , reg , values->factorp ); factor_writel(factor,reg, factor->reg); if( factor->flags & CLK_RATE_FLAT_DELAY) udelay(config->delay); } /* 2).try to increase factor m first */ if( config->mwidth && tmp_factor_m < values->factorm ) { reg = SET_BITS( config->mshift , config->mwidth , reg, values->factorm ); factor_writel(factor,reg, factor->reg); if( factor->flags & CLK_RATE_FLAT_DELAY) udelay(config->delay); } /* 3. write factor n & k */ if( config->nwidth ) reg = SET_BITS( config->nshift , config->nwidth , reg, values->factorn ); if( config->kwidth ) reg = SET_BITS( config->kshift , config->kwidth , reg, values->factork ); factor_writel(factor,reg, factor->reg); /* 4. do pair things for 2). decease factor m */ if( config->mwidth && tmp_factor_m > values->factorm) { reg = SET_BITS( config->mshift , config->mwidth , reg, values->factorm ); factor_writel(factor,reg, factor->reg); if( factor->flags & CLK_RATE_FLAT_DELAY) udelay(config->delay); } /* 5. wait for PLL state stable */ #ifdef CONFIG_EVB_PLATFORM while(loop--) { u32 reg_val = factor_readl(factor,factor->lock_reg); if(GET_BITS(factor->lock_bit, 1, reg_val)) break; else udelay(10); } if(!loop) #if (defined CONFIG_FPGA_V4_PLATFORM) || (defined CONFIG_FPGA_V7_PLATFORM) printk("clk %s wait lock timeout\n",factor->hw.clk->name); #else WARN(1, "clk %s wait lock timeout\n",factor->hw.clk->name); #endif #endif /*6.do pair things for 1). decease factor p */ if( config->pwidth && tmp_factor_p > values->factorp ) { reg = SET_BITS( config->pshift , config->pwidth , reg, values->factorp ); factor_writel(factor,reg, factor->reg); if( factor->flags & CLK_RATE_FLAT_DELAY) udelay(config->delay); } if(factor->lock) spin_unlock_irqrestore(factor->lock, flags); return 0; }
static int sunxi_clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { unsigned long reg; struct clk_factors_value factor_val; unsigned long orig_jiffies; struct sunxi_clk_factors *factor = to_clk_factor(hw); struct sunxi_clk_factors_config *config = factor->config; if(!factor->get_factors) return 0; factor->get_factors(rate, parent_rate, &factor_val); reg = factor_readl(factor,factor->reg); if(config->sdmwidth) { factor_writel(factor,config->sdmval, (void __iomem *)config->sdmpat); reg = SET_BITS(config->sdmshift, config->sdmwidth, reg, 1); } if(config->nwidth) reg = SET_BITS(config->nshift, config->nwidth, reg, factor_val.factorn); if(config->kwidth) reg = SET_BITS(config->kshift, config->kwidth, reg, factor_val.factork); if(config->mwidth) reg = SET_BITS(config->mshift, config->mwidth, reg, factor_val.factorm); if(config->pwidth) reg = SET_BITS(config->pshift, config->pwidth, reg, factor_val.factorp); if(config->d1width) reg = SET_BITS(config->d1shift, config->d1width, reg, factor_val.factord1); if(config->d2width) reg = SET_BITS(config->d2shift, config->d2width, reg, factor_val.factord2); if(config->frac) { reg = SET_BITS(config->modeshift, 1, reg, factor_val.frac_mode); reg = SET_BITS(config->outshift, 1, reg, factor_val.frac_freq); } factor_writel(factor,reg, factor->reg); #ifndef CONFIG_SUNXI_CLK_DUMMY_DEBUG orig_jiffies = jiffies; if(GET_BITS(config->enshift, 1, reg)) { while(1) { reg = factor_readl(factor,factor->lock_reg); if(GET_BITS(factor->lock_bit, 1, reg)) break; if(time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) { #if (defined CONFIG_FPGA_V4_PLATFORM) || (defined CONFIG_FPGA_V7_PLATFORM) printk("clk %s wait lock timeout\n",hw->clk->name); #else WARN(1, "clk %s wait lock timeout\n",hw->clk->name); #endif break; } } } #endif return 0; }