static enum handoff local_pll_clk_handoff(struct clk *c) { struct pll_clk *pll = to_pll_clk(c); u32 mode = readl_relaxed(PLL_MODE_REG(pll)); u32 mask = PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL; unsigned long parent_rate; u32 lval, mval, nval, userval; if ((mode & mask) != mask) return HANDOFF_DISABLED_CLK; /* Assume bootloaders configure PLL to c->rate */ if (c->rate) return HANDOFF_ENABLED_CLK; parent_rate = clk_get_rate(c->parent); lval = readl_relaxed(PLL_L_REG(pll)); mval = readl_relaxed(PLL_M_REG(pll)); nval = readl_relaxed(PLL_N_REG(pll)); userval = readl_relaxed(PLL_CONFIG_REG(pll)); c->rate = parent_rate * lval; if (pll->masks.mn_en_mask && userval) { if (!nval) nval = 1; c->rate += (parent_rate * mval) / nval; } return HANDOFF_ENABLED_CLK; }
static int local_pll_clk_set_rate(struct clk *c, unsigned long rate) { struct pll_freq_tbl *nf; struct pll_clk *pll = to_pll_clk(c); unsigned long flags; for (nf = pll->freq_tbl; nf->freq_hz != PLL_FREQ_END && nf->freq_hz != rate; nf++) ; if (nf->freq_hz == PLL_FREQ_END) return -EINVAL; /* * Ensure PLL is off before changing rate. For optimization reasons, * assume no downstream clock is using actively using it. */ spin_lock_irqsave(&c->lock, flags); if (c->count) c->ops->disable(c); writel_relaxed(nf->l_val, PLL_L_REG(pll)); writel_relaxed(nf->m_val, PLL_M_REG(pll)); writel_relaxed(nf->n_val, PLL_N_REG(pll)); __pll_config_reg(PLL_CONFIG_REG(pll), nf, &pll->masks); if (c->count) c->ops->enable(c); spin_unlock_irqrestore(&c->lock, flags); return 0; }
static int local_pll_clk_set_rate(struct clk *c, unsigned long rate) { struct pll_freq_tbl *nf; struct pll_clk *pll = to_pll_clk(c); u32 mode; mode = readl_relaxed(PLL_MODE_REG(pll)); /* Don't change PLL's rate if it is enabled */ if ((mode & PLL_MODE_MASK) == PLL_MODE_MASK) return -EBUSY; for (nf = pll->freq_tbl; nf->freq_hz != PLL_FREQ_END && nf->freq_hz != rate; nf++) ; if (nf->freq_hz == PLL_FREQ_END) return -EINVAL; writel_relaxed(nf->l_val, PLL_L_REG(pll)); writel_relaxed(nf->m_val, PLL_M_REG(pll)); writel_relaxed(nf->n_val, PLL_N_REG(pll)); __pll_config_reg(PLL_CONFIG_REG(pll), nf, &pll->masks); return 0; }
void __init __configure_pll(struct pll_config *config, struct pll_config_regs *regs, u32 ena_fsm_mode) { u32 regval; writel_relaxed(config->l, PLL_L_REG(regs)); writel_relaxed(config->m, PLL_M_REG(regs)); writel_relaxed(config->n, PLL_N_REG(regs)); regval = readl_relaxed(PLL_CONFIG_REG(regs)); /* Enable the MN accumulator */ if (config->mn_ena_mask) { regval &= ~config->mn_ena_mask; regval |= config->mn_ena_val; } /* Enable the main output */ if (config->main_output_mask) { regval &= ~config->main_output_mask; regval |= config->main_output_val; } /* Set pre-divider and post-divider values */ regval &= ~config->pre_div_mask; regval |= config->pre_div_val; regval &= ~config->post_div_mask; regval |= config->post_div_val; /* Select VCO setting */ regval &= ~config->vco_mask; regval |= config->vco_val; writel_relaxed(regval, PLL_CONFIG_REG(regs)); }
static int local_pll_clk_set_rate(struct clk *c, unsigned long rate) { struct pll_freq_tbl *nf; struct pll_clk *pll = to_pll_clk(c); unsigned long flags; for (nf = pll->freq_tbl; nf->freq_hz != PLL_FREQ_END && nf->freq_hz != rate; nf++) ; if (nf->freq_hz == PLL_FREQ_END) return -EINVAL; spin_lock_irqsave(&c->lock, flags); if (c->count) c->ops->disable(c); writel_relaxed(nf->l_val, PLL_L_REG(pll)); writel_relaxed(nf->m_val, PLL_M_REG(pll)); writel_relaxed(nf->n_val, PLL_N_REG(pll)); __pll_config_reg(PLL_CONFIG_REG(pll), nf, &pll->masks); if (c->count) c->ops->enable(c); spin_unlock_irqrestore(&c->lock, flags); return 0; }
void __configure_pll(struct pll_config *config, struct pll_config_regs *regs, u32 ena_fsm_mode) { u32 regval; writel_relaxed(config->l, PLL_L_REG(regs)); writel_relaxed(config->m, PLL_M_REG(regs)); writel_relaxed(config->n, PLL_N_REG(regs)); regval = readl_relaxed(PLL_CONFIG_REG(regs)); /* Enable the MN accumulator */ if (config->mn_ena_mask) { regval &= ~config->mn_ena_mask; regval |= config->mn_ena_val; } /* Enable the main output */ if (config->main_output_mask) { regval &= ~config->main_output_mask; regval |= config->main_output_val; } /* Enable the aux output */ if (config->aux_output_mask) { regval &= ~config->aux_output_mask; regval |= config->aux_output_val; } /* Set pre-divider and post-divider values */ regval &= ~config->pre_div_mask; regval |= config->pre_div_val; regval &= ~config->post_div_mask; regval |= config->post_div_val; /* Select VCO setting */ regval &= ~config->vco_mask; regval |= config->vco_val; if (config->add_factor_mask) { regval &= ~config->add_factor_mask; regval |= config->add_factor_val; } writel_relaxed(regval, PLL_CONFIG_REG(regs)); if (regs->config_alt_reg) __configure_alt_config(config->alt_cfg, regs); if (regs->config_ctl_reg) writel_relaxed(config->cfg_ctl_val, PLL_CFG_CTL_REG(regs)); }
void __init __configure_pll(struct pll_config *config, struct pll_config_regs *regs, u32 ena_fsm_mode) { u32 regval; writel_relaxed(config->l, PLL_L_REG(regs)); writel_relaxed(config->m, PLL_M_REG(regs)); writel_relaxed(config->n, PLL_N_REG(regs)); regval = readl_relaxed(PLL_CONFIG_REG(regs)); if (config->mn_ena_mask) { regval &= ~config->mn_ena_mask; regval |= config->mn_ena_val; } if (config->main_output_mask) { regval &= ~config->main_output_mask; regval |= config->main_output_val; } if (config->aux_output_mask) { regval &= ~config->aux_output_mask; regval |= config->aux_output_val; } regval &= ~config->pre_div_mask; regval |= config->pre_div_val; regval &= ~config->post_div_mask; regval |= config->post_div_val; regval &= ~config->vco_mask; regval |= config->vco_val; writel_relaxed(regval, PLL_CONFIG_REG(regs)); }
int sr_pll_clk_enable(struct clk *c) { u32 mode; int count; unsigned long flags; struct pll_clk *pll = to_pll_clk(c); u32 lockmask = pll->masks.lock_mask ?: PLL_LOCKED_BIT; u32 status_reg, user_reg, l_reg, m_reg, n_reg, config_reg; spin_lock_irqsave(&pll_reg_lock, flags); if (unlikely(!to_pll_clk(c)->inited)) /* PLL initilazation is similar to HF PLL */ __hf_pll_init(c); /* Remove SPM HW event */ spm_event(pll->spm_ctrl.spm_base, pll->spm_ctrl.offset, pll->spm_ctrl.event_bit, false); mode = readl_relaxed(PLL_MODE_REG(pll)); /* De-assert active-low PLL reset. */ mode |= PLL_RESET_N | PLL_BYPASSNL; writel_relaxed(mode, PLL_MODE_REG(pll)); /* A 100us delay required before locking the PLL */ mb(); udelay(100); /* Wait for the PLL to lock */ for (count = ENABLE_WAIT_MAX_LOOPS; count > 0; count--) { if (readl_relaxed(PLL_STATUS_REG(pll)) & lockmask) break; udelay(1); } if (!(readl_relaxed(PLL_STATUS_REG(pll)) & lockmask)) { mode = readl_relaxed(PLL_MODE_REG(pll)); status_reg = readl_relaxed(PLL_STATUS_REG(pll)); user_reg = readl_relaxed(PLL_CONFIG_REG(pll)); config_reg = readl_relaxed(PLL_CFG_CTL_REG(pll)); l_reg = readl_relaxed(PLL_L_REG(pll)); m_reg = readl_relaxed(PLL_M_REG(pll)); n_reg = readl_relaxed(PLL_N_REG(pll)); pr_err("PLL %s didn't lock after enabling for L value 0x%x!\n", c->dbg_name, l_reg); pr_err("mode register is 0x%x\n", mode); pr_err("status register is 0x%x\n", status_reg); pr_err("user control register is 0x%x\n", user_reg); pr_err("config control register is 0x%x\n", config_reg); pr_err("L value register is 0x%x\n", l_reg); pr_err("M value register is 0x%x\n", m_reg); pr_err("N value control register is 0x%x\n", n_reg); if (pll->spm_ctrl.spm_base) pr_err("L2 spm_force_event_en 0x%x\n", readl_relaxed(pll->spm_ctrl.spm_base + SPM_FORCE_EVENT)); panic("PLL %s didn't lock after enabling it!\n", c->dbg_name); } /* Enable PLL output. */ mode |= PLL_OUTCTRL; writel_relaxed(mode, PLL_MODE_REG(pll)); /* Ensure that the write above goes through before returning. */ mb(); spin_unlock_irqrestore(&pll_reg_lock, flags); return 0; }
static int hf_pll_clk_enable(struct clk *c) { unsigned long flags; struct pll_clk *pll = to_pll_clk(c); int ret = 0, count; u32 mode; u32 lockmask = pll->masks.lock_mask ?: PLL_LOCKED_BIT; u32 status_reg, user_reg, l_reg, m_reg, n_reg, config_reg; spin_lock_irqsave(&pll_reg_lock, flags); if (unlikely(!to_pll_clk(c)->inited)) __hf_pll_init(c); /* Remove SPM HW event */ spm_event(pll->spm_ctrl.spm_base, pll->spm_ctrl.offset, pll->spm_ctrl.event_bit, false); mode = readl_relaxed(PLL_MODE_REG(pll)); /* Disable PLL bypass mode. */ mode |= PLL_BYPASSNL; writel_relaxed(mode, PLL_MODE_REG(pll)); /* * H/W requires a 5us delay between disabling the bypass and * de-asserting the reset. Use 10us to be sure. */ mb(); udelay(10); /* De-assert active-low PLL reset. */ mode |= PLL_RESET_N; writel_relaxed(mode, PLL_MODE_REG(pll)); /* A 50us delay required before locking the PLL. */ mb(); udelay(50); /* Wait for pll to lock. */ for (count = ENABLE_WAIT_MAX_LOOPS; count > 0; count--) { if (readl_relaxed(PLL_STATUS_REG(pll)) & lockmask) { udelay(1); /* * Check again to be sure. This is to avoid * breaking too early if there is a "transient" * lock. */ if ((readl_relaxed(PLL_STATUS_REG(pll)) & lockmask)) break; } udelay(1); } if (!(readl_relaxed(PLL_STATUS_REG(pll)) & lockmask)) { mode = readl_relaxed(PLL_MODE_REG(pll)); status_reg = readl_relaxed(PLL_STATUS_REG(pll)); user_reg = readl_relaxed(PLL_CONFIG_REG(pll)); config_reg = readl_relaxed(PLL_CFG_CTL_REG(pll)); l_reg = readl_relaxed(PLL_L_REG(pll)); m_reg = readl_relaxed(PLL_M_REG(pll)); n_reg = readl_relaxed(PLL_N_REG(pll)); pr_err("PLL %s didn't lock after enabling for L value 0x%x!\n", c->dbg_name, l_reg); pr_err("mode register is 0x%x\n", mode); pr_err("status register is 0x%x\n", status_reg); pr_err("user control register is 0x%x\n", user_reg); pr_err("config control register is 0x%x\n", config_reg); pr_err("L value register is 0x%x\n", l_reg); pr_err("M value register is 0x%x\n", m_reg); pr_err("N value control register is 0x%x\n", n_reg); if (pll->spm_ctrl.spm_base) pr_err("L2 spm_force_event_en 0x%x\n", readl_relaxed(pll->spm_ctrl.spm_base + SPM_FORCE_EVENT)); panic("PLL %s didn't lock after enabling it!\n", c->dbg_name); } /* Enable PLL output. */ mode |= PLL_OUTCTRL; writel_relaxed(mode, PLL_MODE_REG(pll)); /* Ensure that the write above goes through before returning. */ mb(); spin_unlock_irqrestore(&pll_reg_lock, flags); return ret; }