Example #1
0
/**
 * zynqmp_pll_recalc_rate - Recalculate clock frequency
 * @hw:			Handle between common and hardware-specific interfaces
 * @parent_rate:	Clock frequency of parent clock
 * Return:		Current clock frequency
 */
static unsigned long zynqmp_pll_recalc_rate(struct clk_hw *hw,
		unsigned long parent_rate)
{
	struct zynqmp_pll *clk = to_zynqmp_pll(hw);
	u32 fbdiv, div2, data;
	unsigned long rate, frac;

	/*
	 * makes probably sense to redundantly save fbdiv in the struct
	 * zynqmp_pll to save the IO access.
	 */
	fbdiv = (zynqmp_pm_mmio_readl(clk->pll_ctrl) & PLLCTRL_FBDIV_MASK) >>
			PLLCTRL_FBDIV_SHIFT;
	div2 = (zynqmp_pm_mmio_readl(clk->pll_ctrl) & PLLCTRL_DIV2_MASK) >>
			PLLCTRL_DIV2_SHIFT;
	if (div2)
		fbdiv = fbdiv * 2;

	rate =  parent_rate * fbdiv;
	if (pll_frac_get_mode(hw) == PLL_MODE_FRAC) {
		data = (zynqmp_pm_mmio_readl(clk->pll_ctrl + FRAC_OFFSET) &
			0xffff);
		frac = (rate * data) / FRAC_DIV;
		rate = rate + frac;
	}
	return rate;
}
Example #2
0
/**
 * zynqmp_pll_round_rate - Round a clock frequency
 * @hw:		Handle between common and hardware-specific interfaces
 * @rate:	Desired clock frequency
 * @prate:	Clock frequency of parent clock
 *
 * Return:	Frequency closest to @rate the hardware can generate
 */
static long zynqmp_pll_round_rate(struct clk_hw *hw, unsigned long rate,
		unsigned long *prate)
{
	u32 fbdiv;
	long rate_div, f;

	/* Enable the fractional mode if needed */
	rate_div = ((rate * FRAC_DIV) / *prate);
	f = rate_div % FRAC_DIV;
	pll_frac_set_mode(hw, !!f);

	if (pll_frac_get_mode(hw) == PLL_MODE_FRAC) {
		if (rate > PS_PLL_VCO_MAX) {
			fbdiv = rate / PS_PLL_VCO_MAX;
			rate = rate / (fbdiv + 1);
		}
		if (rate < PS_PLL_VCO_MIN) {
			fbdiv = DIV_ROUND_UP(PS_PLL_VCO_MIN, rate);
			rate = rate * fbdiv;
		}
		return rate;
	}

	fbdiv = DIV_ROUND_CLOSEST(rate, *prate);
	fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX);
	return *prate * fbdiv;
}
Example #3
0
static int zynqmp_pll_set_rate(struct clk_hw *hw, unsigned long rate,
		unsigned long parent_rate)
{
	struct zynqmp_pll *clk = to_zynqmp_pll(hw);
	u32 fbdiv, reg;
	u32 data;
	long rate_div, frac, m, f;

	if (pll_frac_get_mode(hw) == PLL_MODE_FRAC) {
		unsigned int children;

		/*
		 * We're running on a ZynqMP compatible machine, make sure the
		 * VPLL only has one child.
		 */
		children = clk_get_children("vpll");

		/* Account for vpll_to_lpd and dp_video_ref */
		if (children > 2)
			WARN(1, "Two devices are using vpll which is forbidden\n");

		rate_div = ((rate * FRAC_DIV) / parent_rate);
		m = rate_div / FRAC_DIV;
		f = rate_div % FRAC_DIV;
		m = clamp_t(u32, m, (PLL_FBDIV_MIN), (PLL_FBDIV_MAX));
		rate = parent_rate * m;
		frac = (parent_rate * f) / FRAC_DIV;
		reg = zynqmp_pm_mmio_readl(clk->pll_ctrl);
		reg &= ~PLLCTRL_FBDIV_MASK;
		reg |= m << PLLCTRL_FBDIV_SHIFT;
		zynqmp_pm_mmio_writel(reg, clk->pll_ctrl);
		reg = zynqmp_pm_mmio_readl(clk->pll_ctrl + FRAC_OFFSET);
		reg &= ~0xffff;

		data = (FRAC_DIV * f) / FRAC_DIV;
		data = data & 0xffff;
		reg |= data;
		zynqmp_pm_mmio_writel(reg, clk->pll_ctrl + FRAC_OFFSET);
		return (rate + frac);
	}

	fbdiv = DIV_ROUND_CLOSEST(rate, parent_rate);
	fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX);
	reg = zynqmp_pm_mmio_readl(clk->pll_ctrl);
	reg &= ~PLLCTRL_FBDIV_MASK;
	reg |= fbdiv << PLLCTRL_FBDIV_SHIFT;
	zynqmp_pm_mmio_writel(reg, clk->pll_ctrl);

	return parent_rate * fbdiv;
}
Example #4
0
/**
 * zynqmp_pll_round_rate - Round a clock frequency
 * @hw:		Handle between common and hardware-specific interfaces
 * @rate:	Desired clock frequency
 * @prate:	Clock frequency of parent clock
 *
 * Return:	Frequency closest to @rate the hardware can generate
 */
static long zynqmp_pll_round_rate(struct clk_hw *hw, unsigned long rate,
		unsigned long *prate)
{
	u32 fbdiv;
	long rate_div, frac, m, f;

	if (pll_frac_get_mode(hw) == PLL_MODE_FRAC) {
		rate_div = ((rate*100) / *prate);
		m = rate_div / 100;
		f = rate_div % 100;
		m = clamp_t(u32, m, (PLL_FBDIV_MIN), (PLL_FBDIV_MAX));
		rate = *prate * m;
		frac = (*prate * f) / 100;
		return (rate + frac);
	}

	fbdiv = DIV_ROUND_CLOSEST(rate, *prate);
	fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX);
	return *prate * fbdiv;
}