/* * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #define pr_fmt(fmt) "%s: " fmt, __func__ #include #include #include #include #include #include #include #include #include "clock.h" #define PLL_OUTCTRL BIT(0) #define PLL_BYPASSNL BIT(1) #define PLL_RESET_N BIT(2) #define PLL_MODE_MASK BM(3, 0) #define PLL_EN_REG(x) (*(x)->base + (unsigned long) (x)->en_reg) #define PLL_STATUS_REG(x) (*(x)->base + (unsigned long) (x)->status_reg) #define PLL_ALT_STATUS_REG(x) (*(x)->base + (unsigned long) \ (x)->alt_status_reg) #define PLL_MODE_REG(x) (*(x)->base + (unsigned long) (x)->mode_reg) #define PLL_L_REG(x) (*(x)->base + (unsigned long) (x)->l_reg) #define PLL_M_REG(x) (*(x)->base + (unsigned long) (x)->m_reg) #define PLL_N_REG(x) (*(x)->base + (unsigned long) (x)->n_reg) #define PLL_CONFIG_REG(x) (*(x)->base + (unsigned long) (x)->config_reg) #define PLL_ALPHA_REG(x) (*(x)->base + (unsigned long) (x)->alpha_reg) #define PLL_CFG_ALT_REG(x) (*(x)->base + (unsigned long) \ (x)->config_alt_reg) #define PLL_CFG_CTL_REG(x) (*(x)->base + (unsigned long) \ (x)->config_ctl_reg) #define PLL_CFG_CTL_HI_REG(x) (*(x)->base + (unsigned long) \ (x)->config_ctl_hi_reg) #define PLL_TEST_CTL_LO_REG(x) (*(x)->base + (unsigned long) \ (x)->test_ctl_lo_reg) #define PLL_TEST_CTL_HI_REG(x) (*(x)->base + (unsigned long) \ (x)->test_ctl_hi_reg) static DEFINE_SPINLOCK(pll_reg_lock); #define ENABLE_WAIT_MAX_LOOPS 200 #define PLL_LOCKED_BIT BIT(16) #define SPM_FORCE_EVENT 0x4 static int pll_vote_clk_enable(struct clk *c) { u32 ena, count; unsigned long flags; struct pll_vote_clk *pllv = to_pll_vote_clk(c); spin_lock_irqsave(&pll_reg_lock, flags); ena = readl_relaxed(PLL_EN_REG(pllv)); ena |= pllv->en_mask; writel_relaxed(ena, PLL_EN_REG(pllv)); spin_unlock_irqrestore(&pll_reg_lock, flags); /* * Use a memory barrier since some PLL status registers are * not within the same 1K segment as the voting registers. */ mb(); /* Wait for pll to enable. */ for (count = ENABLE_WAIT_MAX_LOOPS; count > 0; count--) { if (readl_relaxed(PLL_STATUS_REG(pllv)) & pllv->status_mask) return 0; udelay(1); } WARN("PLL %s didn't enable after voting for it!\n", c->dbg_name); return -ETIMEDOUT; } static void pll_vote_clk_disable(struct clk *c) { u32 ena; unsigned long flags; struct pll_vote_clk *pllv = to_pll_vote_clk(c); spin_lock_irqsave(&pll_reg_lock, flags); ena = readl_relaxed(PLL_EN_REG(pllv)); ena &= ~(pllv->en_mask); writel_relaxed(ena, PLL_EN_REG(pllv)); spin_unlock_irqrestore(&pll_reg_lock, flags); } static int pll_vote_clk_is_enabled(struct clk *c) { struct pll_vote_clk *pllv = to_pll_vote_clk(c); return !!(readl_relaxed(PLL_STATUS_REG(pllv)) & pllv->status_mask); } static enum handoff pll_vote_clk_handoff(struct clk *c) { struct pll_vote_clk *pllv = to_pll_vote_clk(c); if (readl_relaxed(PLL_EN_REG(pllv)) & pllv->en_mask) return HANDOFF_ENABLED_CLK; return HANDOFF_DISABLED_CLK; } static void __iomem *pll_vote_clk_list_registers(struct clk *c, int n, struct clk_register_data **regs, u32 *size) { struct pll_vote_clk *pllv = to_pll_vote_clk(c); static struct clk_register_data data1[] = { {"APPS_VOTE", 0x0}, }; if (n) return ERR_PTR(-EINVAL); *regs = data1; *size = ARRAY_SIZE(data1); return PLL_EN_REG(pllv); } struct clk_ops clk_ops_pll_vote = { .enable = pll_vote_clk_enable, .disable = pll_vote_clk_disable, .is_enabled = pll_vote_clk_is_enabled, .handoff = pll_vote_clk_handoff, .list_registers = pll_vote_clk_list_registers, }; /* * spm_event() -- Set/Clear SPM events * PLL off sequence -- enable (1) * Set L2_SPM_FORCE_EVENT_EN[bit] register to 1 * Set L2_SPM_FORCE_EVENT[bit] register to 1 * PLL on sequence -- enable (0) * Clear L2_SPM_FORCE_EVENT[bit] register to 0 * Clear L2_SPM_FORCE_EVENT_EN[bit] register to 0 */ static void spm_event(void __iomem *base, u32 offset, u32 bit, bool enable) { uint32_t val; if (!base) return; if (enable) { /* L2_SPM_FORCE_EVENT_EN */ val = readl_relaxed(base + offset); val |= BIT(bit); writel_relaxed(val, (base + offset)); /* Ensure that the write above goes through. */ mb(); /* L2_SPM_FORCE_EVENT */ val = readl_relaxed(base + offset + SPM_FORCE_EVENT); val |= BIT(bit); writel_relaxed(val, (base + offset + SPM_FORCE_EVENT)); /* Ensure that the write above goes through. */ mb(); } else { /* L2_SPM_FORCE_EVENT */ val = readl_relaxed(base + offset + SPM_FORCE_EVENT); val &= ~BIT(bit); writel_relaxed(val, (base + offset + SPM_FORCE_EVENT)); /* Ensure that the write above goes through. */ mb(); /* L2_SPM_FORCE_EVENT_EN */ val = readl_relaxed(base + offset); val &= ~BIT(bit); writel_relaxed(val, (base + offset)); /* Ensure that the write above goes through. */ mb(); } } static void __pll_config_reg(void __iomem *pll_config, struct pll_freq_tbl *f, struct pll_config_masks *masks) { u32 regval; regval = readl_relaxed(pll_config); /* Enable the MN counter if used */ if (f->m_val) regval |= masks->mn_en_mask; /* Set pre-divider and post-divider values */ regval &= ~masks->pre_div_mask; regval |= f->pre_div_val; regval &= ~masks->post_div_mask; regval |= f->post_div_val; /* Select VCO setting */ regval &= ~masks->vco_mask; regval |= f->vco_val; /* Enable main output if it has not been enabled */ if (masks->main_output_mask && !(regval & masks->main_output_mask)) regval |= masks->main_output_mask; writel_relaxed(regval, pll_config); } static int sr2_pll_clk_enable(struct clk *c) { unsigned long flags; struct pll_clk *pll = to_pll_clk(c); int ret = 0, count; u32 mode = readl_relaxed(PLL_MODE_REG(pll)); u32 lockmask = pll->masks.lock_mask ?: PLL_LOCKED_BIT; spin_lock_irqsave(&pll_reg_lock, flags); spm_event(pll->spm_ctrl.spm_base, pll->spm_ctrl.offset, pll->spm_ctrl.event_bit, false); /* 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. Delay 10us just to be safe. */ mb(); udelay(10); /* De-assert active-low PLL reset. */ mode |= PLL_RESET_N; writel_relaxed(mode, PLL_MODE_REG(pll)); /* Wait for 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)) pr_err("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; } void __variable_rate_pll_init(struct clk *c) { struct pll_clk *pll = to_pll_clk(c); u32 regval; regval = readl_relaxed(PLL_CONFIG_REG(pll)); if (pll->masks.post_div_mask) { regval &= ~pll->masks.post_div_mask; regval |= pll->vals.post_div_masked; } if (pll->masks.pre_div_mask) { regval &= ~pll->masks.pre_div_mask; regval |= pll->vals.pre_div_masked; } if (pll->masks.main_output_mask) regval |= pll->masks.main_output_mask; if (pll->masks.early_output_mask) regval |= pll->masks.early_output_mask; if (pll->vals.enable_mn) regval |= pll->masks.mn_en_mask; else regval &= ~pll->masks.mn_en_mask; writel_relaxed(regval, PLL_CONFIG_REG(pll)); regval = readl_relaxed(PLL_MODE_REG(pll)); if (pll->masks.apc_pdn_mask) regval &= ~pll->masks.apc_pdn_mask; writel_relaxed(regval, PLL_MODE_REG(pll)); writel_relaxed(pll->vals.alpha_val, PLL_ALPHA_REG(pll)); writel_relaxed(pll->vals.config_ctl_val, PLL_CFG_CTL_REG(pll)); if (pll->vals.config_ctl_hi_val) writel_relaxed(pll->vals.config_ctl_hi_val, PLL_CFG_CTL_HI_REG(pll)); if (pll->init_test_ctl) { writel_relaxed(pll->vals.test_ctl_lo_val, PLL_TEST_CTL_LO_REG(pll)); writel_relaxed(pll->vals.test_ctl_hi_val, PLL_TEST_CTL_HI_REG(pll)); } pll->inited = true; } static int variable_rate_pll_clk_enable(struct clk *c) { unsigned long flags; struct pll_clk *pll = to_pll_clk(c); int ret = 0, count; u32 mode, testlo; u32 lockmask = pll->masks.lock_mask ?: PLL_LOCKED_BIT; u32 mode_lock; u64 time; bool early_lock = false; spin_lock_irqsave(&pll_reg_lock, flags); if (unlikely(!to_pll_clk(c)->inited)) __variable_rate_pll_init(c); mode = readl_relaxed(PLL_MODE_REG(pll)); /* Set test control bits as required by HW doc */ if (pll->test_ctl_lo_reg && pll->vals.test_ctl_lo_val && pll->pgm_test_ctl_enable) writel_relaxed(pll->vals.test_ctl_lo_val, PLL_TEST_CTL_LO_REG(pll)); /* Enable test_ctl debug */ mode |= BIT(3); writel_relaxed(mode, PLL_MODE_REG(pll)); testlo = readl_relaxed(PLL_TEST_CTL_LO_REG(pll)); testlo &= ~BM(7, 6); testlo |= 0xC0; writel_relaxed(testlo, PLL_TEST_CTL_LO_REG(pll)); /* Wait for the write to complete */ mb(); /* 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)); /* * 5us delay mandated by HPG. However, put in a 200us delay here. * This is to address possible locking issues with the PLL exhibit * early "transient" locks about 16us from this point. With this * higher delay, we avoid running into those transients. */ mb(); udelay(200); /* Clear test control bits */ if (pll->test_ctl_lo_reg && pll->vals.test_ctl_lo_val && pll->pgm_test_ctl_enable) writel_relaxed(0x0, PLL_TEST_CTL_LO_REG(pll)); time = sched_clock(); /* 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; else early_lock = true; } udelay(1); } time = sched_clock() - time; mode_lock = readl_relaxed(PLL_STATUS_REG(pll)); if (!(mode_lock & lockmask)) { pr_err("PLL lock bit detection total wait time: %lld ns", time); pr_err("PLL %s didn't lock after enabling for L value 0x%x!\n", c->dbg_name, readl_relaxed(PLL_L_REG(pll))); pr_err("mode register is 0x%x\n", readl_relaxed(PLL_STATUS_REG(pll))); pr_err("user control register is 0x%x\n", readl_relaxed(PLL_CONFIG_REG(pll))); pr_err("config control register is 0x%x\n", readl_relaxed(PLL_CFG_CTL_REG(pll))); pr_err("test control high register is 0x%x\n", readl_relaxed(PLL_TEST_CTL_HI_REG(pll))); pr_err("test control low register is 0x%x\n", readl_relaxed(PLL_TEST_CTL_LO_REG(pll))); pr_err("early lock? %s\n", early_lock ? "yes" : "no"); testlo = readl_relaxed(PLL_TEST_CTL_LO_REG(pll)); testlo &= ~BM(7, 6); writel_relaxed(testlo, PLL_TEST_CTL_LO_REG(pll)); /* Wait for the write to complete */ mb(); pr_err("test_ctl_lo = 0x%x, pll status is: 0x%x\n", readl_relaxed(PLL_TEST_CTL_LO_REG(pll)), readl_relaxed(PLL_ALT_STATUS_REG(pll))); testlo = readl_relaxed(PLL_TEST_CTL_LO_REG(pll)); testlo &= ~BM(7, 6); testlo |= 0x40; writel_relaxed(testlo, PLL_TEST_CTL_LO_REG(pll)); /* Wait for the write to complete */ mb(); pr_err("test_ctl_lo = 0x%x, pll status is: 0x%x\n", readl_relaxed(PLL_TEST_CTL_LO_REG(pll)), readl_relaxed(PLL_ALT_STATUS_REG(pll))); testlo = readl_relaxed(PLL_TEST_CTL_LO_REG(pll)); testlo &= ~BM(7, 6); testlo |= 0x80; writel_relaxed(testlo, PLL_TEST_CTL_LO_REG(pll)); /* Wait for the write to complete */ mb(); pr_err("test_ctl_lo = 0x%x, pll status is: 0x%x\n", readl_relaxed(PLL_TEST_CTL_LO_REG(pll)), readl_relaxed(PLL_ALT_STATUS_REG(pll))); testlo = readl_relaxed(PLL_TEST_CTL_LO_REG(pll)); testlo &= ~BM(7, 6); testlo |= 0xC0; writel_relaxed(testlo, PLL_TEST_CTL_LO_REG(pll)); /* Wait for the write to complete */ mb(); pr_err("test_ctl_lo = 0x%x, pll status is: 0x%x\n", readl_relaxed(PLL_TEST_CTL_LO_REG(pll)), readl_relaxed(PLL_ALT_STATUS_REG(pll))); panic("failed to lock %s PLL\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; } static void variable_rate_pll_clk_disable_hwfsm(struct clk *c) { struct pll_clk *pll = to_pll_clk(c); u32 regval; /* Set test control bit to stay-in-CFA if necessary */ if (pll->test_ctl_lo_reg && pll->pgm_test_ctl_enable) { regval = readl_relaxed(PLL_TEST_CTL_LO_REG(pll)); writel_relaxed(regval | BIT(16), PLL_TEST_CTL_LO_REG(pll)); } /* 8 reference clock cycle delay mandated by the HPG */ udelay(1); } static int variable_rate_pll_clk_enable_hwfsm(struct clk *c) { struct pll_clk *pll = to_pll_clk(c); int count; u32 lockmask = pll->masks.lock_mask ?: PLL_LOCKED_BIT; unsigned long flags; u32 regval; spin_lock_irqsave(&pll_reg_lock, flags); /* Clear test control bit if necessary */ if (pll->test_ctl_lo_reg && pll->pgm_test_ctl_enable) { regval = readl_relaxed(PLL_TEST_CTL_LO_REG(pll)); regval &= ~BIT(16); writel_relaxed(regval, PLL_TEST_CTL_LO_REG(pll)); } /* Wait for 50us explicitly to avoid transient locks */ udelay(50); 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)) pr_err("PLL %s didn't lock after enabling it!\n", c->dbg_name); spin_unlock_irqrestore(&pll_reg_lock, flags); return 0; } static void __pll_clk_enable_reg(void __iomem *mode_reg) { u32 mode = readl_relaxed(mode_reg); /* Disable PLL bypass mode. */ mode |= PLL_BYPASSNL; writel_relaxed(mode, mode_reg); /* * H/W requires a 5us delay between disabling the bypass and * de-asserting the reset. Delay 10us just to be safe. */ mb(); udelay(10); /* De-assert active-low PLL reset. */ mode |= PLL_RESET_N; writel_relaxed(mode, mode_reg); /* Wait until PLL is locked. */ mb(); udelay(50); /* Enable PLL output. */ mode |= PLL_OUTCTRL; writel_relaxed(mode, mode_reg); /* Ensure that the write above goes through before returning. */ mb(); } static int local_pll_clk_enable(struct clk *c) { unsigned long flags; struct pll_clk *pll = to_pll_clk(c); spin_lock_irqsave(&pll_reg_lock, flags); __pll_clk_enable_reg(PLL_MODE_REG(pll)); spin_unlock_irqrestore(&pll_reg_lock, flags); return 0; } static void __pll_clk_disable_reg(void __iomem *mode_reg) { u32 mode = readl_relaxed(mode_reg); mode &= ~PLL_MODE_MASK; writel_relaxed(mode, mode_reg); } static void local_pll_clk_disable(struct clk *c) { unsigned long flags; struct pll_clk *pll = to_pll_clk(c); /* * Disable the PLL output, disable test mode, enable * the bypass mode, and assert the reset. */ spin_lock_irqsave(&pll_reg_lock, flags); spm_event(pll->spm_ctrl.spm_base, pll->spm_ctrl.offset, pll->spm_ctrl.event_bit, true); __pll_clk_disable_reg(PLL_MODE_REG(pll)); spin_unlock_irqrestore(&pll_reg_lock, flags); } 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 long local_pll_clk_round_rate(struct clk *c, unsigned long rate) { struct pll_freq_tbl *nf; struct pll_clk *pll = to_pll_clk(c); if (!pll->freq_tbl) return -EINVAL; for (nf = pll->freq_tbl; nf->freq_hz != PLL_FREQ_END; nf++) if (nf->freq_hz >= rate) return nf->freq_hz; nf--; return nf->freq_hz; } 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 enum handoff variable_rate_pll_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; u32 lval; pll->src_rate = clk_get_rate(c->parent); lval = readl_relaxed(PLL_L_REG(pll)); if (!lval) return HANDOFF_DISABLED_CLK; c->rate = pll->src_rate * lval; if (c->rate > pll->max_rate || c->rate < pll->min_rate) { WARN(1, "%s: Out of spec PLL", c->dbg_name); return HANDOFF_DISABLED_CLK; } if ((mode & mask) != mask) return HANDOFF_DISABLED_CLK; return HANDOFF_ENABLED_CLK; } static long variable_rate_pll_round_rate(struct clk *c, unsigned long rate) { struct pll_clk *pll = to_pll_clk(c); if (!pll->src_rate) return 0; if (pll->no_prepared_reconfig && c->prepare_count && c->rate != rate) return -EINVAL; if (rate < pll->min_rate) rate = pll->min_rate; if (rate > pll->max_rate) rate = pll->max_rate; return min(pll->max_rate, DIV_ROUND_UP(rate, pll->src_rate) * pll->src_rate); } /* * For optimization reasons, assumes no downstream clocks are actively using * it. */ static int variable_rate_pll_set_rate(struct clk *c, unsigned long rate) { struct pll_clk *pll = to_pll_clk(c); unsigned long flags; u32 l_val; if (rate != variable_rate_pll_round_rate(c, rate)) return -EINVAL; l_val = rate / pll->src_rate; spin_lock_irqsave(&c->lock, flags); if (c->count && c->ops->disable) c->ops->disable(c); writel_relaxed(l_val, PLL_L_REG(pll)); if (c->count && c->ops->enable) c->ops->enable(c); spin_unlock_irqrestore(&c->lock, flags); return 0; } int sr_pll_clk_enable(struct clk *c) { u32 mode; unsigned long flags; struct pll_clk *pll = to_pll_clk(c); spin_lock_irqsave(&pll_reg_lock, flags); mode = readl_relaxed(PLL_MODE_REG(pll)); /* De-assert active-low PLL reset. */ mode |= PLL_RESET_N; writel_relaxed(mode, PLL_MODE_REG(pll)); /* * H/W requires a 5us delay between disabling the bypass and * de-asserting the reset. Delay 10us just to be safe. */ mb(); udelay(10); /* Disable PLL bypass mode. */ mode |= PLL_BYPASSNL; writel_relaxed(mode, PLL_MODE_REG(pll)); /* Wait until PLL is locked. */ mb(); udelay(60); /* 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; } int sr_hpm_lp_pll_clk_enable(struct clk *c) { unsigned long flags; struct pll_clk *pll = to_pll_clk(c); u32 count, mode; int ret = 0; spin_lock_irqsave(&pll_reg_lock, flags); /* Disable PLL bypass mode and de-assert reset. */ mode = PLL_BYPASSNL | PLL_RESET_N; writel_relaxed(mode, PLL_MODE_REG(pll)); /* Wait for pll to lock. */ for (count = ENABLE_WAIT_MAX_LOOPS; count > 0; count--) { if (readl_relaxed(PLL_STATUS_REG(pll)) & PLL_LOCKED_BIT) break; udelay(1); } if (!(readl_relaxed(PLL_STATUS_REG(pll)) & PLL_LOCKED_BIT)) { WARN("PLL %s didn't lock after enabling it!\n", c->dbg_name); ret = -ETIMEDOUT; goto out; } /* Enable PLL output. */ mode |= PLL_OUTCTRL; writel_relaxed(mode, PLL_MODE_REG(pll)); /* Ensure the write above goes through before returning. */ mb(); out: spin_unlock_irqrestore(&pll_reg_lock, flags); return ret; } static void __iomem *variable_rate_pll_list_registers(struct clk *c, int n, struct clk_register_data **regs, u32 *size) { struct pll_clk *pll = to_pll_clk(c); static struct clk_register_data data[] = { {"MODE", 0x0}, {"L", 0x4}, {"ALPHA", 0x8}, {"USER_CTL", 0x10}, {"CONFIG_CTL", 0x14}, {"STATUS", 0x1C}, }; if (n) return ERR_PTR(-EINVAL); *regs = data; *size = ARRAY_SIZE(data); return PLL_MODE_REG(pll); } static void __iomem *local_pll_clk_list_registers(struct clk *c, int n, struct clk_register_data **regs, u32 *size) { /* Not compatible with 8960 & friends */ struct pll_clk *pll = to_pll_clk(c); static struct clk_register_data data[] = { {"MODE", 0x0}, {"L", 0x4}, {"M", 0x8}, {"N", 0xC}, {"USER", 0x10}, {"CONFIG", 0x14}, {"STATUS", 0x1C}, }; if (n) return ERR_PTR(-EINVAL); *regs = data; *size = ARRAY_SIZE(data); return PLL_MODE_REG(pll); } struct clk_ops clk_ops_local_pll = { .enable = local_pll_clk_enable, .disable = local_pll_clk_disable, .set_rate = local_pll_clk_set_rate, .handoff = local_pll_clk_handoff, .list_registers = local_pll_clk_list_registers, }; struct clk_ops clk_ops_sr2_pll = { .enable = sr2_pll_clk_enable, .disable = local_pll_clk_disable, .set_rate = local_pll_clk_set_rate, .round_rate = local_pll_clk_round_rate, .handoff = local_pll_clk_handoff, .list_registers = local_pll_clk_list_registers, }; struct clk_ops clk_ops_variable_rate_pll_hwfsm = { .enable = variable_rate_pll_clk_enable_hwfsm, .disable = variable_rate_pll_clk_disable_hwfsm, .set_rate = variable_rate_pll_set_rate, .round_rate = variable_rate_pll_round_rate, .handoff = variable_rate_pll_handoff, .list_registers = variable_rate_pll_list_registers, }; struct clk_ops clk_ops_variable_rate_pll = { .enable = variable_rate_pll_clk_enable, .disable = local_pll_clk_disable, .set_rate = variable_rate_pll_set_rate, .round_rate = variable_rate_pll_round_rate, .handoff = variable_rate_pll_handoff, .list_registers = variable_rate_pll_list_registers, }; static DEFINE_SPINLOCK(soft_vote_lock); static int pll_acpu_vote_clk_enable(struct clk *c) { int ret = 0; unsigned long flags; struct pll_vote_clk *pllv = to_pll_vote_clk(c); spin_lock_irqsave(&soft_vote_lock, flags); if (!*pllv->soft_vote) ret = pll_vote_clk_enable(c); if (ret == 0) *pllv->soft_vote |= (pllv->soft_vote_mask); spin_unlock_irqrestore(&soft_vote_lock, flags); return ret; } static void pll_acpu_vote_clk_disable(struct clk *c) { unsigned long flags; struct pll_vote_clk *pllv = to_pll_vote_clk(c); spin_lock_irqsave(&soft_vote_lock, flags); *pllv->soft_vote &= ~(pllv->soft_vote_mask); if (!*pllv->soft_vote) pll_vote_clk_disable(c); spin_unlock_irqrestore(&soft_vote_lock, flags); } static enum handoff pll_acpu_vote_clk_handoff(struct clk *c) { if (pll_vote_clk_handoff(c) == HANDOFF_DISABLED_CLK) return HANDOFF_DISABLED_CLK; if (pll_acpu_vote_clk_enable(c)) return HANDOFF_DISABLED_CLK; return HANDOFF_ENABLED_CLK; } struct clk_ops clk_ops_pll_acpu_vote = { .enable = pll_acpu_vote_clk_enable, .disable = pll_acpu_vote_clk_disable, .is_enabled = pll_vote_clk_is_enabled, .handoff = pll_acpu_vote_clk_handoff, .list_registers = pll_vote_clk_list_registers, }; static void __set_fsm_mode(void __iomem *mode_reg, u32 bias_count, u32 lock_count) { u32 regval = readl_relaxed(mode_reg); /* De-assert reset to FSM */ regval &= ~BIT(21); writel_relaxed(regval, mode_reg); /* Program bias count */ regval &= ~BM(19, 14); regval |= BVAL(19, 14, bias_count); writel_relaxed(regval, mode_reg); /* Program lock count */ regval &= ~BM(13, 8); regval |= BVAL(13, 8, lock_count); writel_relaxed(regval, mode_reg); /* Enable PLL FSM voting */ regval |= BIT(20); writel_relaxed(regval, mode_reg); } static void __configure_alt_config(struct pll_alt_config config, struct pll_config_regs *regs) { u32 regval; regval = readl_relaxed(PLL_CFG_ALT_REG(regs)); if (config.mask) { regval &= ~config.mask; regval |= config.val; } writel_relaxed(regval, PLL_CFG_ALT_REG(regs)); } 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 configure_sr_pll(struct pll_config *config, struct pll_config_regs *regs, u32 ena_fsm_mode) { __configure_pll(config, regs, ena_fsm_mode); if (ena_fsm_mode) __set_fsm_mode(PLL_MODE_REG(regs), 0x1, 0x8); } void configure_sr_hpm_lp_pll(struct pll_config *config, struct pll_config_regs *regs, u32 ena_fsm_mode) { __configure_pll(config, regs, ena_fsm_mode); if (ena_fsm_mode) __set_fsm_mode(PLL_MODE_REG(regs), 0x1, 0x0); } static void *votable_pll_clk_dt_parser(struct device *dev, struct device_node *np) { struct pll_vote_clk *v, *peer; struct clk *c; u32 val, rc; phandle p; struct msmclk_data *drv; v = devm_kzalloc(dev, sizeof(*v), GFP_KERNEL); if (!v) { dt_err(np, "memory alloc failure\n"); return ERR_PTR(-ENOMEM); } drv = msmclk_parse_phandle(dev, np->parent->phandle); if (IS_ERR_OR_NULL(drv)) return ERR_CAST(drv); v->base = &drv->base; rc = of_property_read_u32(np, "qcom,en-offset", (u32 *)&v->en_reg); if (rc) { dt_err(np, "missing qcom,en-offset dt property\n"); return ERR_PTR(-EINVAL); } rc = of_property_read_u32(np, "qcom,en-bit", &val); if (rc) { dt_err(np, "missing qcom,en-bit dt property\n"); return ERR_PTR(-EINVAL); } v->en_mask = BIT(val); rc = of_property_read_u32(np, "qcom,status-offset", (u32 *)&v->status_reg); if (rc) { dt_err(np, "missing qcom,status-offset dt property\n"); return ERR_PTR(-EINVAL); } rc = of_property_read_u32(np, "qcom,status-bit", &val); if (rc) { dt_err(np, "missing qcom,status-bit dt property\n"); return ERR_PTR(-EINVAL); } v->status_mask = BIT(val); rc = of_property_read_u32(np, "qcom,pll-config-rate", &val); if (rc) { dt_err(np, "missing qcom,pll-config-rate dt property\n"); return ERR_PTR(-EINVAL); } v->c.rate = val; if (of_device_is_compatible(np, "qcom,active-only-pll")) v->soft_vote_mask = PLL_SOFT_VOTE_ACPU; else if (of_device_is_compatible(np, "qcom,sleep-active-pll")) v->soft_vote_mask = PLL_SOFT_VOTE_PRIMARY; if (of_device_is_compatible(np, "qcom,votable-pll")) { v->c.ops = &clk_ops_pll_vote; return msmclk_generic_clk_init(dev, np, &v->c); } rc = of_property_read_phandle_index(np, "qcom,peer", 0, &p); if (rc) { dt_err(np, "missing qcom,peer dt property\n"); return ERR_PTR(-EINVAL); } c = msmclk_lookup_phandle(dev, p); if (!IS_ERR_OR_NULL(c)) { v->soft_vote = devm_kzalloc(dev, sizeof(*v->soft_vote), GFP_KERNEL); if (!v->soft_vote) { dt_err(np, "memory alloc failure\n"); return ERR_PTR(-ENOMEM); } peer = to_pll_vote_clk(c); peer->soft_vote = v->soft_vote; } v->c.ops = &clk_ops_pll_acpu_vote; return msmclk_generic_clk_init(dev, np, &v->c); } MSMCLK_PARSER(votable_pll_clk_dt_parser, "qcom,active-only-pll", 0); MSMCLK_PARSER(votable_pll_clk_dt_parser, "qcom,sleep-active-pll", 1); MSMCLK_PARSER(votable_pll_clk_dt_parser, "qcom,votable-pll", 2);