/* * Make sure PLL is working with valid input signal (Fdiv). If * you want to speed the function up just reduce CCU_PLL_NR_MAX. * This will cause a worse approximation though.
*/
nri = (parent_rate / CCU_PLL_FDIV_MAX) + 1;
nr_max = min(parent_rate / CCU_PLL_FDIV_MIN, CCU_PLL_NR_MAX);
/* * Find a closest [nr;nf;od] vector taking into account the * limitations like: 1) 700MHz <= Fvco <= 3.5GHz, 2) PLL Od is * either 1 or even number within the acceptable range (alas 1s * is also excluded by the next loop).
*/ for (; nri <= nr_max; ++nri) { /* Use Od factor to fulfill the limitation 2). */
num = CCU_PLL_CLKOD_FACTOR * rate;
denom = parent_rate / nri;
/* * Make sure Fvco is within the acceptable range to fulfill * the condition 1). Note due to the CCU_PLL_CLKOD_FACTOR value * the actual upper limit is also divided by that factor. * It's not big problem for us since practically there is no * need in clocks with that high frequency.
*/
nf_max = min(CCU_PLL_FVCO_MAX / denom, CCU_PLL_NF_MAX);
od_max = CCU_PLL_OD_MAX / CCU_PLL_CLKOD_FACTOR;
/* * Bypass the out-of-bound values, which can't be properly * handled by the rational fraction approximation algorithm.
*/ if (num / denom >= nf_max) {
n1 = nf_max;
d1 = 1;
} elseif (denom / num >= od_max) {
n1 = 1;
d1 = od_max;
} else {
rational_best_approximation(num, denom, nf_max, od_max,
&n1, &d1);
}
/* Select the best approximation of the target rate. */
freq = ccu_pll_calc_freq(parent_rate, nri, n1, d1);
err = abs((int64_t)freq - num); if (err < min_err) {
min_err = err;
*nr = nri;
*nf = n1;
*od = CCU_PLL_CLKOD_FACTOR * d1;
}
}
}
staticlong ccu_pll_round_rate(struct clk_hw *hw, unsignedlong rate, unsignedlong *parent_rate)
{ unsignedlong nr = 1, nf = 1, od = 1;
/* * This method is used for PLLs, which support the on-the-fly dividers * adjustment. So there is no need in gating such clocks.
*/ staticint ccu_pll_set_rate_reset(struct clk_hw *hw, unsignedlong rate, unsignedlong parent_rate)
{ struct ccu_pll *pll = to_ccu_pll(hw); unsignedlong nr, nf, od; unsignedlong flags;
u32 mask, val; int ret;
/* * This method is used for PLLs, which don't support the on-the-fly dividers * adjustment. So the corresponding clocks are supposed to be gated first.
*/ staticint ccu_pll_set_rate_norst(struct clk_hw *hw, unsignedlong rate, unsignedlong parent_rate)
{ struct ccu_pll *pll = to_ccu_pll(hw); unsignedlong nr, nf, od; unsignedlong flags;
u32 mask, val;
/* * Disable PLL if it was enabled by default or left enabled by the * system bootloader.
*/
mask = CCU_PLL_CTL_CLKR_MASK | CCU_PLL_CTL_CLKF_MASK |
CCU_PLL_CTL_CLKOD_MASK | CCU_PLL_CTL_EN;
val = FIELD_PREP(CCU_PLL_CTL_CLKR_MASK, nr - 1) |
FIELD_PREP(CCU_PLL_CTL_CLKF_MASK, nf - 1) |
FIELD_PREP(CCU_PLL_CTL_CLKOD_MASK, od - 1);
/* * It can be dangerous to change the PLL settings behind clock framework back, * therefore we don't provide any kernel config based compile time option for * this feature to enable.
*/ #undef CCU_PLL_ALLOW_WRITE_DEBUGFS #ifdef CCU_PLL_ALLOW_WRITE_DEBUGFS
pll = kzalloc(sizeof(*pll), GFP_KERNEL); if (!pll) return ERR_PTR(-ENOMEM);
/* * Note since Baikal-T1 System Controller registers are MMIO-backed * we won't check the regmap IO operations return status, because it * must be zero anyway.
*/
pll->hw.init = &hw_init;
pll->reg_ctl = pll_init->base + CCU_PLL_CTL;
pll->reg_ctl1 = pll_init->base + CCU_PLL_CTL1;
pll->sys_regs = pll_init->sys_regs;
pll->id = pll_init->id;
spin_lock_init(&pll->lock);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.