if (ctrl->flags & IPROC_CLK_PLL_ASIU) {
val = readl(pll->asiu_base + ctrl->asiu.offset);
val &= ~(1 << ctrl->asiu.en_shift);
iproc_pll_write(pll, pll->asiu_base, ctrl->asiu.offset, val);
}
if (ctrl->flags & IPROC_CLK_EMBED_PWRCTRL) {
val = readl(pll->control_base + ctrl->aon.offset);
val |= bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift;
iproc_pll_write(pll, pll->control_base, ctrl->aon.offset, val);
}
if (pll->pwr_base) { /* latch input value so core power can be shut down */
val = readl(pll->pwr_base + ctrl->aon.offset);
val |= 1 << ctrl->aon.iso_shift;
iproc_pll_write(pll, pll->pwr_base, ctrl->aon.offset, val);
/* power down the core */
val &= ~(bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift);
iproc_pll_write(pll, pll->pwr_base, ctrl->aon.offset, val);
}
}
if (ctrl->flags & IPROC_CLK_EMBED_PWRCTRL) {
val = readl(pll->control_base + ctrl->aon.offset);
val &= ~(bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift);
iproc_pll_write(pll, pll->control_base, ctrl->aon.offset, val);
}
if (pll->pwr_base) { /* power up the PLL and make sure it's not latched */
val = readl(pll->pwr_base + ctrl->aon.offset);
val |= bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift;
val &= ~(1 << ctrl->aon.iso_shift);
iproc_pll_write(pll, pll->pwr_base, ctrl->aon.offset, val);
}
/* certain PLLs also need to be ungated from the ASIU top level */ if (ctrl->flags & IPROC_CLK_PLL_ASIU) {
val = readl(pll->asiu_base + ctrl->asiu.offset);
val |= (1 << ctrl->asiu.en_shift);
iproc_pll_write(pll, pll->asiu_base, ctrl->asiu.offset, val);
}
/* determine Ki and Kp index based on target VCO frequency */ if (rate >= VCO_LOW && rate < VCO_HIGH) {
ki = 4;
kp_index = KP_BAND_MID;
} elseif (rate >= VCO_HIGH && rate < VCO_HIGH_HIGH) {
ki = 3;
kp_index = KP_BAND_HIGH;
} elseif (rate >= VCO_HIGH_HIGH && rate < VCO_MAX) {
ki = 3;
kp_index = KP_BAND_HIGH_HIGH;
} else {
pr_err("%s: pll: %s has invalid rate: %lu\n", __func__,
clk_name, rate); return -EINVAL;
}
kp = get_kp(ref_freq, kp_index); if (kp < 0) {
pr_err("%s: pll: %s has invalid kp\n", __func__, clk_name); return kp;
}
ret = __pll_enable(pll); if (ret) {
pr_err("%s: pll: %s fails to enable\n", __func__, clk_name); return ret;
}
if (pll_fractional_change_only(clk->pll, vco)) { /* program fractional part of NDIV */ if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) {
val = readl(pll->control_base + ctrl->ndiv_frac.offset);
val &= ~(bit_mask(ctrl->ndiv_frac.width) <<
ctrl->ndiv_frac.shift);
val |= vco->ndiv_frac << ctrl->ndiv_frac.shift;
iproc_pll_write(pll, pll->control_base,
ctrl->ndiv_frac.offset, val); return0;
}
}
/* put PLL in reset */
__pll_put_in_reset(pll);
/* set PLL in user mode before modifying PLL controls */ if (ctrl->flags & IPROC_CLK_PLL_USER_MODE_ON) {
val = readl(pll->control_base + ctrl->macro_mode.offset);
val &= ~(bit_mask(ctrl->macro_mode.width) <<
ctrl->macro_mode.shift);
val |= PLL_USER_MODE << ctrl->macro_mode.shift;
iproc_pll_write(pll, pll->control_base,
ctrl->macro_mode.offset, val);
}
/* program integer part of NDIV */
val = readl(pll->control_base + ctrl->ndiv_int.offset);
val &= ~(bit_mask(ctrl->ndiv_int.width) << ctrl->ndiv_int.shift);
val |= vco->ndiv_int << ctrl->ndiv_int.shift;
iproc_pll_write(pll, pll->control_base, ctrl->ndiv_int.offset, val);
/* program fractional part of NDIV */ if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) {
val = readl(pll->control_base + ctrl->ndiv_frac.offset);
val &= ~(bit_mask(ctrl->ndiv_frac.width) <<
ctrl->ndiv_frac.shift);
val |= vco->ndiv_frac << ctrl->ndiv_frac.shift;
iproc_pll_write(pll, pll->control_base, ctrl->ndiv_frac.offset,
val);
}
/* program PDIV */
val = readl(pll->control_base + ctrl->pdiv.offset);
val &= ~(bit_mask(ctrl->pdiv.width) << ctrl->pdiv.shift);
val |= vco->pdiv << ctrl->pdiv.shift;
iproc_pll_write(pll, pll->control_base, ctrl->pdiv.offset, val);
__pll_bring_out_reset(pll, kp, ka, ki);
ret = pll_wait_for_lock(pll); if (ret < 0) {
pr_err("%s: pll: %s failed to lock\n", __func__, clk_name); return ret;
}
/* channel enable is active low */
val = readl(pll->control_base + ctrl->enable.offset);
val &= ~(1 << ctrl->enable.enable_shift);
iproc_pll_write(pll, pll->control_base, ctrl->enable.offset, val);
/* also make sure channel is not held */
val = readl(pll->control_base + ctrl->enable.offset);
val &= ~(1 << ctrl->enable.hold_shift);
iproc_pll_write(pll, pll->control_base, ctrl->enable.offset, val);
iclk_array = kcalloc(num_clks, sizeof(struct iproc_clk), GFP_KERNEL); if (WARN_ON(!iclk_array)) goto err_clks;
pll->control_base = of_iomap(node, 0); if (WARN_ON(!pll->control_base)) goto err_pll_iomap;
/* Some SoCs do not require the pwr_base, thus failing is not fatal */
pll->pwr_base = of_iomap(node, 1);
/* some PLLs require gating control at the top ASIU level */ if (pll_ctrl->flags & IPROC_CLK_PLL_ASIU) {
pll->asiu_base = of_iomap(node, 2); if (WARN_ON(!pll->asiu_base)) goto err_asiu_iomap;
}
if (pll_ctrl->flags & IPROC_CLK_PLL_SPLIT_STAT_CTRL) { /* Some SoCs have a split status/control. If this does not *exist,assumetheyareunified.
*/
pll->status_base = of_iomap(node, 2); if (!pll->status_base) goto err_status_iomap;
} else
pll->status_base = pll->control_base;
/* initialize and register the PLL itself */
pll->ctrl = pll_ctrl;
iclk = &iclk_array[0];
iclk->pll = pll;
ret = of_property_read_string_index(node, "clock-output-names", 0, &clk_name); if (WARN_ON(ret)) goto err_pll_register;
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.