Esempio n. 1
0
static int clk_dfs_set_rate(struct clk_hw *hw, unsigned long rate,
		unsigned long parent_rate)
{
	struct clk_dfs *dfs = to_clk_dfs(hw);
	u32 mfi;
	u32 portreset = readl_relaxed(DFS_PORTRESET(dfs->reg));

	writel_relaxed( DFS_CTRL_DLL_RESET, DFS_CTRL(dfs->reg) );
	writel_relaxed( portreset | ~DFS_PORTRESET_PORTRESET_SET(dfs->idx),
			DFS_PORTRESET(dfs->reg) );

	mfi = parent_rate/rate;
	writel_relaxed( DFS_DVPORTn_MFI_SET(mfi) | DFS_DVPORTn_MFN_SET(dfs->mfn),
			DFS_DVPORTn(dfs->reg,dfs->idx) );

	writel_relaxed( ~DFS_CTRL_DLL_RESET, DFS_CTRL(dfs->reg) );

	while( readl_relaxed(DFS_PORTSR(dfs->reg)) & (1 << (dfs->idx)) );

	return 0;
}
Esempio n. 2
0
/*
 * Program the pll according to the input parameters.
 * pll - ARM_PLL, PERIPH_PLL, ENET_PLL, DDR_PLL, VIDEO_PLL.
 * refclk_freq - input reference clock frequency (FXOSC - 40 MHZ, FIRC - 48 MHZ)
 * freq - expected output frequency for PHY0
 * freq1 - expected output frequency for PHY1
 * dfs_nr - number of DFS modules for current PLL
 * dfs - array with the activation dfs field, mfn and mfi
 * plldv_prediv - divider of clkfreq_ref
 * plldv_mfd - loop multiplication factor divider
 * pllfd_mfn - numerator loop multiplication factor divider
 * Please consult the PLLDIG chapter of platform manual
 * before to use this function.
 *)
 */
static int program_pll(enum pll_type pll, u32 refclk_freq, u32 freq0, u32 freq1,
		       u32 dfs_nr, u32 dfs[][DFS_PARAMS_Nr], u32 plldv_prediv,
		       u32 plldv_mfd, u32 pllfd_mfn)
{
	u32 i, rfdphi1, rfdphi, dfs_on = 0, fvco;

	/*
	 * This formula is from platform reference manual (Rev. 1, 6/2015), PLLDIG chapter.
	 */
	fvco =
	    (refclk_freq / plldv_prediv) * (plldv_mfd +
					    pllfd_mfn / (float)20480);

	/*
	 * VCO should have value in [ PLL_MIN_FREQ, PLL_MAX_FREQ ]. Please consult
	 * the platform DataSheet in order to determine the allowed values.
	 */

	if (fvco < PLL_MIN_FREQ || fvco > PLL_MAX_FREQ) {
		return -1;
	}

	if (select_pll_source_clk(pll, refclk_freq) < 0) {
		return -1;
	}

	rfdphi = fvco / freq0;

	rfdphi1 = (freq1 == 0) ? 0 : fvco / freq1;

	writel(PLLDIG_PLLDV_RFDPHI1_SET(rfdphi1) |
	       PLLDIG_PLLDV_RFDPHI_SET(rfdphi) |
	       PLLDIG_PLLDV_PREDIV_SET(plldv_prediv) |
	       PLLDIG_PLLDV_MFD(plldv_mfd), PLLDIG_PLLDV(pll));

	writel(readl(PLLDIG_PLLFD(pll)) | PLLDIG_PLLFD_MFN_SET(pllfd_mfn) |
	       PLLDIG_PLLFD_SMDEN, PLLDIG_PLLFD(pll));

	/* switch on the pll in current mode */
	writel(readl(MC_ME_RUNn_MC(0)) | MC_ME_RUNMODE_MC_PLL(pll),
	       MC_ME_RUNn_MC(0));

	entry_to_target_mode(MC_ME_MCTL_RUN0);

	/* Only ARM_PLL, ENET_PLL and DDR_PLL */
	if ((pll == ARM_PLL) || (pll == ENET_PLL) || (pll == DDR_PLL)) {
		/* DFS clk enable programming */
		writel(DFS_CTRL_DLL_RESET, DFS_CTRL(pll));

		writel(DFS_DLLPRG1_CPICTRL_SET(0x5) |
		       DFS_DLLPRG1_VSETTLCTRL_SET(0x1) |
		       DFS_DLLPRG1_CALBYPEN_SET(0x0) |
		       DFS_DLLPRG1_DACIN_SET(0x1) | DFS_DLLPRG1_LCKWT_SET(0x0) |
		       DFS_DLLPRG1_V2IGC_SET(0x5), DFS_DLLPRG1(pll));

		for (i = 0; i < dfs_nr; i++) {
			if (dfs[i][0]) {
				writel(DFS_DVPORTn_MFI_SET(dfs[i][2]) |
				       DFS_DVPORTn_MFN_SET(dfs[i][1]),
				       DFS_DVPORTn(pll, i));
				dfs_on |= (dfs[i][0] << i);
			}
		}

		writel(readl(DFS_CTRL(pll)) & ~DFS_CTRL_DLL_RESET,
		       DFS_CTRL(pll));
		writel(readl(DFS_PORTRESET(pll)) &
		       ~DFS_PORTRESET_PORTRESET_SET(dfs_on),
		       DFS_PORTRESET(pll));
		while ((readl(DFS_PORTSR(pll)) & dfs_on) != dfs_on) ;
	}

	entry_to_target_mode(MC_ME_MCTL_RUN0);

	return 0;

}