Ejemplo n.º 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;
}
Ejemplo n.º 2
0
/**
 * zynqmp_pll_enable - Enable clock
 * @hw:		Handle between common and hardware-specific interfaces
 *
 * Return:	0 always
 */
static int zynqmp_pll_enable(struct clk_hw *hw)
{
	u32 reg;
	struct zynqmp_pll *clk = to_zynqmp_pll(hw);

	if (zynqmp_pll_is_enabled(hw))
		return 0;

	pr_info("PLL: enable\n");

	reg = zynqmp_pm_mmio_readl(clk->pll_ctrl);
	reg |= PLLCTRL_BP_MASK;
	zynqmp_pm_mmio_writel(reg, clk->pll_ctrl);
	reg |= PLLCTRL_RESET_MASK;
	zynqmp_pm_mmio_writel(reg, clk->pll_ctrl);

	reg &= ~(PLLCTRL_RESET_MASK);
	zynqmp_pm_mmio_writel(reg, clk->pll_ctrl);
	while (!(zynqmp_pm_mmio_readl(clk->pll_status) & (1 << clk->lockbit)))
		cpu_relax();

	reg &= ~PLLCTRL_BP_MASK;
	zynqmp_pm_mmio_writel(reg, clk->pll_ctrl);

	return 0;
}
Ejemplo n.º 3
0
static inline enum pll_mode pll_frac_get_mode(struct clk_hw *hw)
{
	struct zynqmp_pll *clk = to_zynqmp_pll(hw);
	u32 reg;

	reg = zynqmp_pm_mmio_readl(clk->pll_ctrl + FRAC_OFFSET);
	reg = reg & PLLFCFG_FRAC_EN;
	return reg ? PLL_MODE_FRAC : PLL_MODE_INT;
}
Ejemplo n.º 4
0
/**
 * zynqmp_pll_is_enabled - Check if a clock is enabled
 * @hw:		Handle between common and hardware-specific interfaces
 *
 * Return:	1 if the clock is enabled, 0 otherwise
 */
static int zynqmp_pll_is_enabled(struct clk_hw *hw)
{
	u32 reg;
	struct zynqmp_pll *clk = to_zynqmp_pll(hw);

	reg = zynqmp_pm_mmio_readl(clk->pll_ctrl);

	return !(reg & (PLLCTRL_RESET_MASK));
}
Ejemplo n.º 5
0
/**
 * zynqmp_pll_disable - Disable clock
 * @hw:		Handle between common and hardware-specific interfaces
 *
 */
static void zynqmp_pll_disable(struct clk_hw *hw)
{
	struct zynqmp_pll *clk = to_zynqmp_pll(hw);

	if (!zynqmp_pll_is_enabled(hw))
		return;

	pr_info("PLL: shutdown\n");

	/* shut down PLL */
	zynqmp_pm_mmio_write((u32)(ulong)clk->pll_ctrl, PLLCTRL_RESET_MASK,
				PLLCTRL_RESET_VAL);
}
Ejemplo n.º 6
0
/**
 * zynqmp_pll_is_enabled - Check if a clock is enabled
 * @hw:		Handle between common and hardware-specific interfaces
 *
 * Return:	1 if the clock is enabled, 0 otherwise
 */
static int zynqmp_pll_is_enabled(struct clk_hw *hw)
{
	u32 reg;
	struct zynqmp_pll *clk = to_zynqmp_pll(hw);
	int ret;

	ret = zynqmp_pm_mmio_read((u32)(ulong)clk->pll_ctrl, &reg);
	if (ret)
		pr_warn_once("Read fail pll address: %x\n",
				(u32)(ulong)clk->pll_ctrl);

	return !(reg & (PLLCTRL_RESET_MASK));
}
Ejemplo n.º 7
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;
}
Ejemplo n.º 8
0
/**
 * pll_frac_set_mode - Set the fractional mode
 * @hw:		Handle between common and hardware-specific interfaces
 * @on:		Flag to determine the mode
 */
static inline void pll_frac_set_mode(struct clk_hw *hw, bool on)
{
	struct zynqmp_pll *clk = to_zynqmp_pll(hw);
	u32 reg = 0;
	int ret;

	if (on)
		reg = PLLFCFG_FRAC_EN;

	ret = zynqmp_pm_mmio_write((u32)(ulong)(clk->pll_ctrl + FRAC_OFFSET),
					PLLFCFG_FRAC_EN, reg);
	if (ret)
		pr_warn_once("Write fail pll address: %x\n",
				(u32)(ulong)(clk->pll_ctrl + FRAC_OFFSET));
}
Ejemplo n.º 9
0
static inline enum pll_mode pll_frac_get_mode(struct clk_hw *hw)
{
	struct zynqmp_pll *clk = to_zynqmp_pll(hw);
	u32 reg;
	int ret;

	ret = zynqmp_pm_mmio_read((u32)(ulong)(clk->pll_ctrl + FRAC_OFFSET),
					&reg);
	if (ret)
		pr_warn_once("Read fail pll address: %x\n",
				(u32)(ulong)(clk->pll_ctrl + FRAC_OFFSET));

	reg = reg & PLLFCFG_FRAC_EN;
	return reg ? PLL_MODE_FRAC : PLL_MODE_INT;
}