static freq_t _pll_set_freq(clk_t* clk, freq_t hz) { volatile uint32_t* ctrl_reg; volatile uint32_t* cfg_reg; uint32_t status_mask; uint32_t fin; uint8_t fdiv; fin = clk_get_freq(clk->parent); fdiv = fin / hz; fdiv = INRANGE(PLL_CTRL_FDIV_MIN, fdiv, PLL_CTRL_FDIV_MAX); status_mask = _decode_pll(clk, &ctrl_reg, &cfg_reg); if (status_mask == 0) { return 0; } /* Program the feedback divider value and the configuration register */ *ctrl_reg &= ~(PLL_CTRL_FDIV_MASK); *ctrl_reg |= PLL_CTRL_FDIV(fdiv); *cfg_reg = pll_cfg_tbl[fdiv - PLL_CTRL_FDIV_MIN].pll_cfg; /* Force the PLL into bypass mode */ *ctrl_reg |= PLL_CTRL_BYPASS_FORCE; /* Assert and de-assert the PLL reset */ *ctrl_reg |= PLL_CTRL_RESET; *ctrl_reg &= ~(PLL_CTRL_RESET); /* Verify that the PLL is locked */ while (!(clk_regs->pll_status & status_mask)); /* Disable the PLL bypass mode */ *ctrl_reg &= ~(PLL_CTRL_BYPASS_FORCE); return clk_get_freq(clk); }
static unsigned long zynq_pll_recalc_rate(struct clk *clk, unsigned long parent_rate) { struct zynq_pll_clk *pll = to_zynq_pll_clk(clk); return parent_rate * PLL_CTRL_FDIV(readl(pll->pll_ctrl)); }