162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR MIT) 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2018 NXP. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This driver supports the SCCG plls found in the imx8m SOCs 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Documentation for this SCCG pll can be found at: 862306a36Sopenharmony_ci * https://www.nxp.com/docs/en/reference-manual/IMX8MDQLQRM.pdf#page=834 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/clk-provider.h> 1262306a36Sopenharmony_ci#include <linux/err.h> 1362306a36Sopenharmony_ci#include <linux/export.h> 1462306a36Sopenharmony_ci#include <linux/io.h> 1562306a36Sopenharmony_ci#include <linux/iopoll.h> 1662306a36Sopenharmony_ci#include <linux/slab.h> 1762306a36Sopenharmony_ci#include <linux/bitfield.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "clk.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* PLL CFGs */ 2262306a36Sopenharmony_ci#define PLL_CFG0 0x0 2362306a36Sopenharmony_ci#define PLL_CFG1 0x4 2462306a36Sopenharmony_ci#define PLL_CFG2 0x8 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define PLL_DIVF1_MASK GENMASK(18, 13) 2762306a36Sopenharmony_ci#define PLL_DIVF2_MASK GENMASK(12, 7) 2862306a36Sopenharmony_ci#define PLL_DIVR1_MASK GENMASK(27, 25) 2962306a36Sopenharmony_ci#define PLL_DIVR2_MASK GENMASK(24, 19) 3062306a36Sopenharmony_ci#define PLL_DIVQ_MASK GENMASK(6, 1) 3162306a36Sopenharmony_ci#define PLL_REF_MASK GENMASK(2, 0) 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define PLL_LOCK_MASK BIT(31) 3462306a36Sopenharmony_ci#define PLL_PD_MASK BIT(7) 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* These are the specification limits for the SSCG PLL */ 3762306a36Sopenharmony_ci#define PLL_REF_MIN_FREQ 25000000UL 3862306a36Sopenharmony_ci#define PLL_REF_MAX_FREQ 235000000UL 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define PLL_STAGE1_MIN_FREQ 1600000000UL 4162306a36Sopenharmony_ci#define PLL_STAGE1_MAX_FREQ 2400000000UL 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define PLL_STAGE1_REF_MIN_FREQ 25000000UL 4462306a36Sopenharmony_ci#define PLL_STAGE1_REF_MAX_FREQ 54000000UL 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define PLL_STAGE2_MIN_FREQ 1200000000UL 4762306a36Sopenharmony_ci#define PLL_STAGE2_MAX_FREQ 2400000000UL 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define PLL_STAGE2_REF_MIN_FREQ 54000000UL 5062306a36Sopenharmony_ci#define PLL_STAGE2_REF_MAX_FREQ 75000000UL 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define PLL_OUT_MIN_FREQ 20000000UL 5362306a36Sopenharmony_ci#define PLL_OUT_MAX_FREQ 1200000000UL 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#define PLL_DIVR1_MAX 7 5662306a36Sopenharmony_ci#define PLL_DIVR2_MAX 63 5762306a36Sopenharmony_ci#define PLL_DIVF1_MAX 63 5862306a36Sopenharmony_ci#define PLL_DIVF2_MAX 63 5962306a36Sopenharmony_ci#define PLL_DIVQ_MAX 63 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define PLL_BYPASS_NONE 0x0 6262306a36Sopenharmony_ci#define PLL_BYPASS1 0x2 6362306a36Sopenharmony_ci#define PLL_BYPASS2 0x1 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define SSCG_PLL_BYPASS1_MASK BIT(5) 6662306a36Sopenharmony_ci#define SSCG_PLL_BYPASS2_MASK BIT(4) 6762306a36Sopenharmony_ci#define SSCG_PLL_BYPASS_MASK GENMASK(5, 4) 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#define PLL_SCCG_LOCK_TIMEOUT 70 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistruct clk_sscg_pll_setup { 7262306a36Sopenharmony_ci int divr1, divf1; 7362306a36Sopenharmony_ci int divr2, divf2; 7462306a36Sopenharmony_ci int divq; 7562306a36Sopenharmony_ci int bypass; 7662306a36Sopenharmony_ci uint64_t vco1; 7762306a36Sopenharmony_ci uint64_t vco2; 7862306a36Sopenharmony_ci uint64_t fout; 7962306a36Sopenharmony_ci uint64_t ref; 8062306a36Sopenharmony_ci uint64_t ref_div1; 8162306a36Sopenharmony_ci uint64_t ref_div2; 8262306a36Sopenharmony_ci uint64_t fout_request; 8362306a36Sopenharmony_ci int fout_error; 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistruct clk_sscg_pll { 8762306a36Sopenharmony_ci struct clk_hw hw; 8862306a36Sopenharmony_ci const struct clk_ops ops; 8962306a36Sopenharmony_ci void __iomem *base; 9062306a36Sopenharmony_ci struct clk_sscg_pll_setup setup; 9162306a36Sopenharmony_ci u8 parent; 9262306a36Sopenharmony_ci u8 bypass1; 9362306a36Sopenharmony_ci u8 bypass2; 9462306a36Sopenharmony_ci}; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci#define to_clk_sscg_pll(_hw) container_of(_hw, struct clk_sscg_pll, hw) 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic int clk_sscg_pll_wait_lock(struct clk_sscg_pll *pll) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci u32 val; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci val = readl_relaxed(pll->base + PLL_CFG0); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci /* don't wait for lock if all plls are bypassed */ 10562306a36Sopenharmony_ci if (!(val & SSCG_PLL_BYPASS2_MASK)) 10662306a36Sopenharmony_ci return readl_poll_timeout(pll->base, val, val & PLL_LOCK_MASK, 10762306a36Sopenharmony_ci 0, PLL_SCCG_LOCK_TIMEOUT); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci return 0; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic int clk_sscg_pll2_check_match(struct clk_sscg_pll_setup *setup, 11362306a36Sopenharmony_ci struct clk_sscg_pll_setup *temp_setup) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci int new_diff = temp_setup->fout - temp_setup->fout_request; 11662306a36Sopenharmony_ci int diff = temp_setup->fout_error; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if (abs(diff) > abs(new_diff)) { 11962306a36Sopenharmony_ci temp_setup->fout_error = new_diff; 12062306a36Sopenharmony_ci memcpy(setup, temp_setup, sizeof(struct clk_sscg_pll_setup)); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci if (temp_setup->fout_request == temp_setup->fout) 12362306a36Sopenharmony_ci return 0; 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci return -1; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic int clk_sscg_divq_lookup(struct clk_sscg_pll_setup *setup, 12962306a36Sopenharmony_ci struct clk_sscg_pll_setup *temp_setup) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci int ret = -EINVAL; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci for (temp_setup->divq = 0; temp_setup->divq <= PLL_DIVQ_MAX; 13462306a36Sopenharmony_ci temp_setup->divq++) { 13562306a36Sopenharmony_ci temp_setup->vco2 = temp_setup->vco1; 13662306a36Sopenharmony_ci do_div(temp_setup->vco2, temp_setup->divr2 + 1); 13762306a36Sopenharmony_ci temp_setup->vco2 *= 2; 13862306a36Sopenharmony_ci temp_setup->vco2 *= temp_setup->divf2 + 1; 13962306a36Sopenharmony_ci if (temp_setup->vco2 >= PLL_STAGE2_MIN_FREQ && 14062306a36Sopenharmony_ci temp_setup->vco2 <= PLL_STAGE2_MAX_FREQ) { 14162306a36Sopenharmony_ci temp_setup->fout = temp_setup->vco2; 14262306a36Sopenharmony_ci do_div(temp_setup->fout, 2 * (temp_setup->divq + 1)); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci ret = clk_sscg_pll2_check_match(setup, temp_setup); 14562306a36Sopenharmony_ci if (!ret) { 14662306a36Sopenharmony_ci temp_setup->bypass = PLL_BYPASS1; 14762306a36Sopenharmony_ci return ret; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci return ret; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic int clk_sscg_divf2_lookup(struct clk_sscg_pll_setup *setup, 15662306a36Sopenharmony_ci struct clk_sscg_pll_setup *temp_setup) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci int ret = -EINVAL; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci for (temp_setup->divf2 = 0; temp_setup->divf2 <= PLL_DIVF2_MAX; 16162306a36Sopenharmony_ci temp_setup->divf2++) { 16262306a36Sopenharmony_ci ret = clk_sscg_divq_lookup(setup, temp_setup); 16362306a36Sopenharmony_ci if (!ret) 16462306a36Sopenharmony_ci return ret; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci return ret; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic int clk_sscg_divr2_lookup(struct clk_sscg_pll_setup *setup, 17162306a36Sopenharmony_ci struct clk_sscg_pll_setup *temp_setup) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci int ret = -EINVAL; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci for (temp_setup->divr2 = 0; temp_setup->divr2 <= PLL_DIVR2_MAX; 17662306a36Sopenharmony_ci temp_setup->divr2++) { 17762306a36Sopenharmony_ci temp_setup->ref_div2 = temp_setup->vco1; 17862306a36Sopenharmony_ci do_div(temp_setup->ref_div2, temp_setup->divr2 + 1); 17962306a36Sopenharmony_ci if (temp_setup->ref_div2 >= PLL_STAGE2_REF_MIN_FREQ && 18062306a36Sopenharmony_ci temp_setup->ref_div2 <= PLL_STAGE2_REF_MAX_FREQ) { 18162306a36Sopenharmony_ci ret = clk_sscg_divf2_lookup(setup, temp_setup); 18262306a36Sopenharmony_ci if (!ret) 18362306a36Sopenharmony_ci return ret; 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci return ret; 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic int clk_sscg_pll2_find_setup(struct clk_sscg_pll_setup *setup, 19162306a36Sopenharmony_ci struct clk_sscg_pll_setup *temp_setup, 19262306a36Sopenharmony_ci uint64_t ref) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci int ret; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (ref < PLL_STAGE1_MIN_FREQ || ref > PLL_STAGE1_MAX_FREQ) 19762306a36Sopenharmony_ci return -EINVAL; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci temp_setup->vco1 = ref; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci ret = clk_sscg_divr2_lookup(setup, temp_setup); 20262306a36Sopenharmony_ci return ret; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic int clk_sscg_divf1_lookup(struct clk_sscg_pll_setup *setup, 20662306a36Sopenharmony_ci struct clk_sscg_pll_setup *temp_setup) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci int ret = -EINVAL; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci for (temp_setup->divf1 = 0; temp_setup->divf1 <= PLL_DIVF1_MAX; 21162306a36Sopenharmony_ci temp_setup->divf1++) { 21262306a36Sopenharmony_ci uint64_t vco1 = temp_setup->ref; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci do_div(vco1, temp_setup->divr1 + 1); 21562306a36Sopenharmony_ci vco1 *= 2; 21662306a36Sopenharmony_ci vco1 *= temp_setup->divf1 + 1; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci ret = clk_sscg_pll2_find_setup(setup, temp_setup, vco1); 21962306a36Sopenharmony_ci if (!ret) { 22062306a36Sopenharmony_ci temp_setup->bypass = PLL_BYPASS_NONE; 22162306a36Sopenharmony_ci return ret; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci return ret; 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic int clk_sscg_divr1_lookup(struct clk_sscg_pll_setup *setup, 22962306a36Sopenharmony_ci struct clk_sscg_pll_setup *temp_setup) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci int ret = -EINVAL; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci for (temp_setup->divr1 = 0; temp_setup->divr1 <= PLL_DIVR1_MAX; 23462306a36Sopenharmony_ci temp_setup->divr1++) { 23562306a36Sopenharmony_ci temp_setup->ref_div1 = temp_setup->ref; 23662306a36Sopenharmony_ci do_div(temp_setup->ref_div1, temp_setup->divr1 + 1); 23762306a36Sopenharmony_ci if (temp_setup->ref_div1 >= PLL_STAGE1_REF_MIN_FREQ && 23862306a36Sopenharmony_ci temp_setup->ref_div1 <= PLL_STAGE1_REF_MAX_FREQ) { 23962306a36Sopenharmony_ci ret = clk_sscg_divf1_lookup(setup, temp_setup); 24062306a36Sopenharmony_ci if (!ret) 24162306a36Sopenharmony_ci return ret; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci return ret; 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic int clk_sscg_pll1_find_setup(struct clk_sscg_pll_setup *setup, 24962306a36Sopenharmony_ci struct clk_sscg_pll_setup *temp_setup, 25062306a36Sopenharmony_ci uint64_t ref) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci int ret; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (ref < PLL_REF_MIN_FREQ || ref > PLL_REF_MAX_FREQ) 25562306a36Sopenharmony_ci return -EINVAL; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci temp_setup->ref = ref; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci ret = clk_sscg_divr1_lookup(setup, temp_setup); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci return ret; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic int clk_sscg_pll_find_setup(struct clk_sscg_pll_setup *setup, 26562306a36Sopenharmony_ci uint64_t prate, 26662306a36Sopenharmony_ci uint64_t rate, int try_bypass) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct clk_sscg_pll_setup temp_setup; 26962306a36Sopenharmony_ci int ret = -EINVAL; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci memset(&temp_setup, 0, sizeof(struct clk_sscg_pll_setup)); 27262306a36Sopenharmony_ci memset(setup, 0, sizeof(struct clk_sscg_pll_setup)); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci temp_setup.fout_error = PLL_OUT_MAX_FREQ; 27562306a36Sopenharmony_ci temp_setup.fout_request = rate; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci switch (try_bypass) { 27862306a36Sopenharmony_ci case PLL_BYPASS2: 27962306a36Sopenharmony_ci if (prate == rate) { 28062306a36Sopenharmony_ci setup->bypass = PLL_BYPASS2; 28162306a36Sopenharmony_ci setup->fout = rate; 28262306a36Sopenharmony_ci ret = 0; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci break; 28562306a36Sopenharmony_ci case PLL_BYPASS1: 28662306a36Sopenharmony_ci ret = clk_sscg_pll2_find_setup(setup, &temp_setup, prate); 28762306a36Sopenharmony_ci break; 28862306a36Sopenharmony_ci case PLL_BYPASS_NONE: 28962306a36Sopenharmony_ci ret = clk_sscg_pll1_find_setup(setup, &temp_setup, prate); 29062306a36Sopenharmony_ci break; 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci return ret; 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic int clk_sscg_pll_is_prepared(struct clk_hw *hw) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci struct clk_sscg_pll *pll = to_clk_sscg_pll(hw); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci u32 val = readl_relaxed(pll->base + PLL_CFG0); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci return (val & PLL_PD_MASK) ? 0 : 1; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic int clk_sscg_pll_prepare(struct clk_hw *hw) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci struct clk_sscg_pll *pll = to_clk_sscg_pll(hw); 30862306a36Sopenharmony_ci u32 val; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci val = readl_relaxed(pll->base + PLL_CFG0); 31162306a36Sopenharmony_ci val &= ~PLL_PD_MASK; 31262306a36Sopenharmony_ci writel_relaxed(val, pll->base + PLL_CFG0); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci return clk_sscg_pll_wait_lock(pll); 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic void clk_sscg_pll_unprepare(struct clk_hw *hw) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct clk_sscg_pll *pll = to_clk_sscg_pll(hw); 32062306a36Sopenharmony_ci u32 val; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci val = readl_relaxed(pll->base + PLL_CFG0); 32362306a36Sopenharmony_ci val |= PLL_PD_MASK; 32462306a36Sopenharmony_ci writel_relaxed(val, pll->base + PLL_CFG0); 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic unsigned long clk_sscg_pll_recalc_rate(struct clk_hw *hw, 32862306a36Sopenharmony_ci unsigned long parent_rate) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci struct clk_sscg_pll *pll = to_clk_sscg_pll(hw); 33162306a36Sopenharmony_ci u32 val, divr1, divf1, divr2, divf2, divq; 33262306a36Sopenharmony_ci u64 temp64; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci val = readl_relaxed(pll->base + PLL_CFG2); 33562306a36Sopenharmony_ci divr1 = FIELD_GET(PLL_DIVR1_MASK, val); 33662306a36Sopenharmony_ci divr2 = FIELD_GET(PLL_DIVR2_MASK, val); 33762306a36Sopenharmony_ci divf1 = FIELD_GET(PLL_DIVF1_MASK, val); 33862306a36Sopenharmony_ci divf2 = FIELD_GET(PLL_DIVF2_MASK, val); 33962306a36Sopenharmony_ci divq = FIELD_GET(PLL_DIVQ_MASK, val); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci temp64 = parent_rate; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci val = readl(pll->base + PLL_CFG0); 34462306a36Sopenharmony_ci if (val & SSCG_PLL_BYPASS2_MASK) { 34562306a36Sopenharmony_ci temp64 = parent_rate; 34662306a36Sopenharmony_ci } else if (val & SSCG_PLL_BYPASS1_MASK) { 34762306a36Sopenharmony_ci temp64 *= divf2; 34862306a36Sopenharmony_ci do_div(temp64, (divr2 + 1) * (divq + 1)); 34962306a36Sopenharmony_ci } else { 35062306a36Sopenharmony_ci temp64 *= 2; 35162306a36Sopenharmony_ci temp64 *= (divf1 + 1) * (divf2 + 1); 35262306a36Sopenharmony_ci do_div(temp64, (divr1 + 1) * (divr2 + 1) * (divq + 1)); 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return temp64; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic int clk_sscg_pll_set_rate(struct clk_hw *hw, unsigned long rate, 35962306a36Sopenharmony_ci unsigned long parent_rate) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci struct clk_sscg_pll *pll = to_clk_sscg_pll(hw); 36262306a36Sopenharmony_ci struct clk_sscg_pll_setup *setup = &pll->setup; 36362306a36Sopenharmony_ci u32 val; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* set bypass here too since the parent might be the same */ 36662306a36Sopenharmony_ci val = readl(pll->base + PLL_CFG0); 36762306a36Sopenharmony_ci val &= ~SSCG_PLL_BYPASS_MASK; 36862306a36Sopenharmony_ci val |= FIELD_PREP(SSCG_PLL_BYPASS_MASK, setup->bypass); 36962306a36Sopenharmony_ci writel(val, pll->base + PLL_CFG0); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci val = readl_relaxed(pll->base + PLL_CFG2); 37262306a36Sopenharmony_ci val &= ~(PLL_DIVF1_MASK | PLL_DIVF2_MASK); 37362306a36Sopenharmony_ci val &= ~(PLL_DIVR1_MASK | PLL_DIVR2_MASK | PLL_DIVQ_MASK); 37462306a36Sopenharmony_ci val |= FIELD_PREP(PLL_DIVF1_MASK, setup->divf1); 37562306a36Sopenharmony_ci val |= FIELD_PREP(PLL_DIVF2_MASK, setup->divf2); 37662306a36Sopenharmony_ci val |= FIELD_PREP(PLL_DIVR1_MASK, setup->divr1); 37762306a36Sopenharmony_ci val |= FIELD_PREP(PLL_DIVR2_MASK, setup->divr2); 37862306a36Sopenharmony_ci val |= FIELD_PREP(PLL_DIVQ_MASK, setup->divq); 37962306a36Sopenharmony_ci writel_relaxed(val, pll->base + PLL_CFG2); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci return clk_sscg_pll_wait_lock(pll); 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic u8 clk_sscg_pll_get_parent(struct clk_hw *hw) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci struct clk_sscg_pll *pll = to_clk_sscg_pll(hw); 38762306a36Sopenharmony_ci u32 val; 38862306a36Sopenharmony_ci u8 ret = pll->parent; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci val = readl(pll->base + PLL_CFG0); 39162306a36Sopenharmony_ci if (val & SSCG_PLL_BYPASS2_MASK) 39262306a36Sopenharmony_ci ret = pll->bypass2; 39362306a36Sopenharmony_ci else if (val & SSCG_PLL_BYPASS1_MASK) 39462306a36Sopenharmony_ci ret = pll->bypass1; 39562306a36Sopenharmony_ci return ret; 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic int clk_sscg_pll_set_parent(struct clk_hw *hw, u8 index) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci struct clk_sscg_pll *pll = to_clk_sscg_pll(hw); 40162306a36Sopenharmony_ci u32 val; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci val = readl(pll->base + PLL_CFG0); 40462306a36Sopenharmony_ci val &= ~SSCG_PLL_BYPASS_MASK; 40562306a36Sopenharmony_ci val |= FIELD_PREP(SSCG_PLL_BYPASS_MASK, pll->setup.bypass); 40662306a36Sopenharmony_ci writel(val, pll->base + PLL_CFG0); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci return clk_sscg_pll_wait_lock(pll); 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic int __clk_sscg_pll_determine_rate(struct clk_hw *hw, 41262306a36Sopenharmony_ci struct clk_rate_request *req, 41362306a36Sopenharmony_ci uint64_t min, 41462306a36Sopenharmony_ci uint64_t max, 41562306a36Sopenharmony_ci uint64_t rate, 41662306a36Sopenharmony_ci int bypass) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci struct clk_sscg_pll *pll = to_clk_sscg_pll(hw); 41962306a36Sopenharmony_ci struct clk_sscg_pll_setup *setup = &pll->setup; 42062306a36Sopenharmony_ci struct clk_hw *parent_hw = NULL; 42162306a36Sopenharmony_ci int bypass_parent_index; 42262306a36Sopenharmony_ci int ret; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci req->max_rate = max; 42562306a36Sopenharmony_ci req->min_rate = min; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci switch (bypass) { 42862306a36Sopenharmony_ci case PLL_BYPASS2: 42962306a36Sopenharmony_ci bypass_parent_index = pll->bypass2; 43062306a36Sopenharmony_ci break; 43162306a36Sopenharmony_ci case PLL_BYPASS1: 43262306a36Sopenharmony_ci bypass_parent_index = pll->bypass1; 43362306a36Sopenharmony_ci break; 43462306a36Sopenharmony_ci default: 43562306a36Sopenharmony_ci bypass_parent_index = pll->parent; 43662306a36Sopenharmony_ci break; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci parent_hw = clk_hw_get_parent_by_index(hw, bypass_parent_index); 44062306a36Sopenharmony_ci ret = __clk_determine_rate(parent_hw, req); 44162306a36Sopenharmony_ci if (!ret) { 44262306a36Sopenharmony_ci ret = clk_sscg_pll_find_setup(setup, req->rate, 44362306a36Sopenharmony_ci rate, bypass); 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci req->best_parent_hw = parent_hw; 44762306a36Sopenharmony_ci req->best_parent_rate = req->rate; 44862306a36Sopenharmony_ci req->rate = setup->fout; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci return ret; 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic int clk_sscg_pll_determine_rate(struct clk_hw *hw, 45462306a36Sopenharmony_ci struct clk_rate_request *req) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci struct clk_sscg_pll *pll = to_clk_sscg_pll(hw); 45762306a36Sopenharmony_ci struct clk_sscg_pll_setup *setup = &pll->setup; 45862306a36Sopenharmony_ci uint64_t rate = req->rate; 45962306a36Sopenharmony_ci uint64_t min = req->min_rate; 46062306a36Sopenharmony_ci uint64_t max = req->max_rate; 46162306a36Sopenharmony_ci int ret; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci if (rate < PLL_OUT_MIN_FREQ || rate > PLL_OUT_MAX_FREQ) 46462306a36Sopenharmony_ci return -EINVAL; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci ret = __clk_sscg_pll_determine_rate(hw, req, req->rate, req->rate, 46762306a36Sopenharmony_ci rate, PLL_BYPASS2); 46862306a36Sopenharmony_ci if (!ret) 46962306a36Sopenharmony_ci return ret; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci ret = __clk_sscg_pll_determine_rate(hw, req, PLL_STAGE1_REF_MIN_FREQ, 47262306a36Sopenharmony_ci PLL_STAGE1_REF_MAX_FREQ, rate, 47362306a36Sopenharmony_ci PLL_BYPASS1); 47462306a36Sopenharmony_ci if (!ret) 47562306a36Sopenharmony_ci return ret; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci ret = __clk_sscg_pll_determine_rate(hw, req, PLL_REF_MIN_FREQ, 47862306a36Sopenharmony_ci PLL_REF_MAX_FREQ, rate, 47962306a36Sopenharmony_ci PLL_BYPASS_NONE); 48062306a36Sopenharmony_ci if (!ret) 48162306a36Sopenharmony_ci return ret; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (setup->fout >= min && setup->fout <= max) 48462306a36Sopenharmony_ci ret = 0; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci return ret; 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic const struct clk_ops clk_sscg_pll_ops = { 49062306a36Sopenharmony_ci .prepare = clk_sscg_pll_prepare, 49162306a36Sopenharmony_ci .unprepare = clk_sscg_pll_unprepare, 49262306a36Sopenharmony_ci .is_prepared = clk_sscg_pll_is_prepared, 49362306a36Sopenharmony_ci .recalc_rate = clk_sscg_pll_recalc_rate, 49462306a36Sopenharmony_ci .set_rate = clk_sscg_pll_set_rate, 49562306a36Sopenharmony_ci .set_parent = clk_sscg_pll_set_parent, 49662306a36Sopenharmony_ci .get_parent = clk_sscg_pll_get_parent, 49762306a36Sopenharmony_ci .determine_rate = clk_sscg_pll_determine_rate, 49862306a36Sopenharmony_ci}; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistruct clk_hw *imx_clk_hw_sscg_pll(const char *name, 50162306a36Sopenharmony_ci const char * const *parent_names, 50262306a36Sopenharmony_ci u8 num_parents, 50362306a36Sopenharmony_ci u8 parent, u8 bypass1, u8 bypass2, 50462306a36Sopenharmony_ci void __iomem *base, 50562306a36Sopenharmony_ci unsigned long flags) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci struct clk_sscg_pll *pll; 50862306a36Sopenharmony_ci struct clk_init_data init; 50962306a36Sopenharmony_ci struct clk_hw *hw; 51062306a36Sopenharmony_ci int ret; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci pll = kzalloc(sizeof(*pll), GFP_KERNEL); 51362306a36Sopenharmony_ci if (!pll) 51462306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci pll->parent = parent; 51762306a36Sopenharmony_ci pll->bypass1 = bypass1; 51862306a36Sopenharmony_ci pll->bypass2 = bypass2; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci pll->base = base; 52162306a36Sopenharmony_ci init.name = name; 52262306a36Sopenharmony_ci init.ops = &clk_sscg_pll_ops; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci init.flags = flags; 52562306a36Sopenharmony_ci init.parent_names = parent_names; 52662306a36Sopenharmony_ci init.num_parents = num_parents; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci pll->hw.init = &init; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci hw = &pll->hw; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci ret = clk_hw_register(NULL, hw); 53362306a36Sopenharmony_ci if (ret) { 53462306a36Sopenharmony_ci kfree(pll); 53562306a36Sopenharmony_ci return ERR_PTR(ret); 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci return hw; 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(imx_clk_hw_sscg_pll); 541