162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2013 Samsung Electronics Co., Ltd. 462306a36Sopenharmony_ci * Copyright (c) 2013 Linaro Ltd. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This file contains the utility functions to register the pll clocks. 762306a36Sopenharmony_ci*/ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/errno.h> 1062306a36Sopenharmony_ci#include <linux/hrtimer.h> 1162306a36Sopenharmony_ci#include <linux/iopoll.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci#include <linux/timekeeping.h> 1562306a36Sopenharmony_ci#include <linux/clk-provider.h> 1662306a36Sopenharmony_ci#include <linux/io.h> 1762306a36Sopenharmony_ci#include "clk.h" 1862306a36Sopenharmony_ci#include "clk-pll.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define PLL_TIMEOUT_US 20000U 2162306a36Sopenharmony_ci#define PLL_TIMEOUT_LOOPS 1000000U 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct samsung_clk_pll { 2462306a36Sopenharmony_ci struct clk_hw hw; 2562306a36Sopenharmony_ci void __iomem *lock_reg; 2662306a36Sopenharmony_ci void __iomem *con_reg; 2762306a36Sopenharmony_ci /* PLL enable control bit offset in @con_reg register */ 2862306a36Sopenharmony_ci unsigned short enable_offs; 2962306a36Sopenharmony_ci /* PLL lock status bit offset in @con_reg register */ 3062306a36Sopenharmony_ci unsigned short lock_offs; 3162306a36Sopenharmony_ci enum samsung_pll_type type; 3262306a36Sopenharmony_ci unsigned int rate_count; 3362306a36Sopenharmony_ci const struct samsung_pll_rate_table *rate_table; 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define to_clk_pll(_hw) container_of(_hw, struct samsung_clk_pll, hw) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic const struct samsung_pll_rate_table *samsung_get_pll_settings( 3962306a36Sopenharmony_ci struct samsung_clk_pll *pll, unsigned long rate) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci const struct samsung_pll_rate_table *rate_table = pll->rate_table; 4262306a36Sopenharmony_ci int i; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci for (i = 0; i < pll->rate_count; i++) { 4562306a36Sopenharmony_ci if (rate == rate_table[i].rate) 4662306a36Sopenharmony_ci return &rate_table[i]; 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci return NULL; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic long samsung_pll_round_rate(struct clk_hw *hw, 5362306a36Sopenharmony_ci unsigned long drate, unsigned long *prate) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 5662306a36Sopenharmony_ci const struct samsung_pll_rate_table *rate_table = pll->rate_table; 5762306a36Sopenharmony_ci int i; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci /* Assumming rate_table is in descending order */ 6062306a36Sopenharmony_ci for (i = 0; i < pll->rate_count; i++) { 6162306a36Sopenharmony_ci if (drate >= rate_table[i].rate) 6262306a36Sopenharmony_ci return rate_table[i].rate; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci /* return minimum supported value */ 6662306a36Sopenharmony_ci return rate_table[i - 1].rate; 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic bool pll_early_timeout = true; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic int __init samsung_pll_disable_early_timeout(void) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci pll_early_timeout = false; 7462306a36Sopenharmony_ci return 0; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ciarch_initcall(samsung_pll_disable_early_timeout); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* Wait until the PLL is locked */ 7962306a36Sopenharmony_cistatic int samsung_pll_lock_wait(struct samsung_clk_pll *pll, 8062306a36Sopenharmony_ci unsigned int reg_mask) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci int i, ret; 8362306a36Sopenharmony_ci u32 val; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* 8662306a36Sopenharmony_ci * This function might be called when the timekeeping API can't be used 8762306a36Sopenharmony_ci * to detect timeouts. One situation is when the clocksource is not yet 8862306a36Sopenharmony_ci * initialized, another when the timekeeping is suspended. udelay() also 8962306a36Sopenharmony_ci * cannot be used when the clocksource is not running on arm64, since 9062306a36Sopenharmony_ci * the current timer is used as cycle counter. So a simple busy loop 9162306a36Sopenharmony_ci * is used here in that special cases. The limit of iterations has been 9262306a36Sopenharmony_ci * derived from experimental measurements of various PLLs on multiple 9362306a36Sopenharmony_ci * Exynos SoC variants. Single register read time was usually in range 9462306a36Sopenharmony_ci * 0.4...1.5 us, never less than 0.4 us. 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_ci if (pll_early_timeout || timekeeping_suspended) { 9762306a36Sopenharmony_ci i = PLL_TIMEOUT_LOOPS; 9862306a36Sopenharmony_ci while (i-- > 0) { 9962306a36Sopenharmony_ci if (readl_relaxed(pll->con_reg) & reg_mask) 10062306a36Sopenharmony_ci return 0; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci cpu_relax(); 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci ret = -ETIMEDOUT; 10562306a36Sopenharmony_ci } else { 10662306a36Sopenharmony_ci ret = readl_relaxed_poll_timeout_atomic(pll->con_reg, val, 10762306a36Sopenharmony_ci val & reg_mask, 0, PLL_TIMEOUT_US); 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if (ret < 0) 11162306a36Sopenharmony_ci pr_err("Could not lock PLL %s\n", clk_hw_get_name(&pll->hw)); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return ret; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic int samsung_pll3xxx_enable(struct clk_hw *hw) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 11962306a36Sopenharmony_ci u32 tmp; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci tmp = readl_relaxed(pll->con_reg); 12262306a36Sopenharmony_ci tmp |= BIT(pll->enable_offs); 12362306a36Sopenharmony_ci writel_relaxed(tmp, pll->con_reg); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return samsung_pll_lock_wait(pll, BIT(pll->lock_offs)); 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic void samsung_pll3xxx_disable(struct clk_hw *hw) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 13162306a36Sopenharmony_ci u32 tmp; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci tmp = readl_relaxed(pll->con_reg); 13462306a36Sopenharmony_ci tmp &= ~BIT(pll->enable_offs); 13562306a36Sopenharmony_ci writel_relaxed(tmp, pll->con_reg); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci/* 13962306a36Sopenharmony_ci * PLL2126 Clock Type 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci#define PLL2126_MDIV_MASK (0xff) 14362306a36Sopenharmony_ci#define PLL2126_PDIV_MASK (0x3f) 14462306a36Sopenharmony_ci#define PLL2126_SDIV_MASK (0x3) 14562306a36Sopenharmony_ci#define PLL2126_MDIV_SHIFT (16) 14662306a36Sopenharmony_ci#define PLL2126_PDIV_SHIFT (8) 14762306a36Sopenharmony_ci#define PLL2126_SDIV_SHIFT (0) 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic unsigned long samsung_pll2126_recalc_rate(struct clk_hw *hw, 15062306a36Sopenharmony_ci unsigned long parent_rate) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 15362306a36Sopenharmony_ci u32 pll_con, mdiv, pdiv, sdiv; 15462306a36Sopenharmony_ci u64 fvco = parent_rate; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci pll_con = readl_relaxed(pll->con_reg); 15762306a36Sopenharmony_ci mdiv = (pll_con >> PLL2126_MDIV_SHIFT) & PLL2126_MDIV_MASK; 15862306a36Sopenharmony_ci pdiv = (pll_con >> PLL2126_PDIV_SHIFT) & PLL2126_PDIV_MASK; 15962306a36Sopenharmony_ci sdiv = (pll_con >> PLL2126_SDIV_SHIFT) & PLL2126_SDIV_MASK; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci fvco *= (mdiv + 8); 16262306a36Sopenharmony_ci do_div(fvco, (pdiv + 2) << sdiv); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci return (unsigned long)fvco; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic const struct clk_ops samsung_pll2126_clk_ops = { 16862306a36Sopenharmony_ci .recalc_rate = samsung_pll2126_recalc_rate, 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/* 17262306a36Sopenharmony_ci * PLL3000 Clock Type 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci#define PLL3000_MDIV_MASK (0xff) 17662306a36Sopenharmony_ci#define PLL3000_PDIV_MASK (0x3) 17762306a36Sopenharmony_ci#define PLL3000_SDIV_MASK (0x3) 17862306a36Sopenharmony_ci#define PLL3000_MDIV_SHIFT (16) 17962306a36Sopenharmony_ci#define PLL3000_PDIV_SHIFT (8) 18062306a36Sopenharmony_ci#define PLL3000_SDIV_SHIFT (0) 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic unsigned long samsung_pll3000_recalc_rate(struct clk_hw *hw, 18362306a36Sopenharmony_ci unsigned long parent_rate) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 18662306a36Sopenharmony_ci u32 pll_con, mdiv, pdiv, sdiv; 18762306a36Sopenharmony_ci u64 fvco = parent_rate; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci pll_con = readl_relaxed(pll->con_reg); 19062306a36Sopenharmony_ci mdiv = (pll_con >> PLL3000_MDIV_SHIFT) & PLL3000_MDIV_MASK; 19162306a36Sopenharmony_ci pdiv = (pll_con >> PLL3000_PDIV_SHIFT) & PLL3000_PDIV_MASK; 19262306a36Sopenharmony_ci sdiv = (pll_con >> PLL3000_SDIV_SHIFT) & PLL3000_SDIV_MASK; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci fvco *= (2 * (mdiv + 8)); 19562306a36Sopenharmony_ci do_div(fvco, pdiv << sdiv); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci return (unsigned long)fvco; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic const struct clk_ops samsung_pll3000_clk_ops = { 20162306a36Sopenharmony_ci .recalc_rate = samsung_pll3000_recalc_rate, 20262306a36Sopenharmony_ci}; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci/* 20562306a36Sopenharmony_ci * PLL35xx Clock Type 20662306a36Sopenharmony_ci */ 20762306a36Sopenharmony_ci/* Maximum lock time can be 270 * PDIV cycles */ 20862306a36Sopenharmony_ci#define PLL35XX_LOCK_FACTOR (270) 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci#define PLL35XX_MDIV_MASK (0x3FF) 21162306a36Sopenharmony_ci#define PLL35XX_PDIV_MASK (0x3F) 21262306a36Sopenharmony_ci#define PLL35XX_SDIV_MASK (0x7) 21362306a36Sopenharmony_ci#define PLL35XX_MDIV_SHIFT (16) 21462306a36Sopenharmony_ci#define PLL35XX_PDIV_SHIFT (8) 21562306a36Sopenharmony_ci#define PLL35XX_SDIV_SHIFT (0) 21662306a36Sopenharmony_ci#define PLL35XX_LOCK_STAT_SHIFT (29) 21762306a36Sopenharmony_ci#define PLL35XX_ENABLE_SHIFT (31) 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw, 22062306a36Sopenharmony_ci unsigned long parent_rate) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 22362306a36Sopenharmony_ci u32 mdiv, pdiv, sdiv, pll_con; 22462306a36Sopenharmony_ci u64 fvco = parent_rate; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci pll_con = readl_relaxed(pll->con_reg); 22762306a36Sopenharmony_ci mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK; 22862306a36Sopenharmony_ci pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK; 22962306a36Sopenharmony_ci sdiv = (pll_con >> PLL35XX_SDIV_SHIFT) & PLL35XX_SDIV_MASK; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci fvco *= mdiv; 23262306a36Sopenharmony_ci do_div(fvco, (pdiv << sdiv)); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci return (unsigned long)fvco; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic inline bool samsung_pll35xx_mp_change( 23862306a36Sopenharmony_ci const struct samsung_pll_rate_table *rate, u32 pll_con) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci u32 old_mdiv, old_pdiv; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci old_mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK; 24362306a36Sopenharmony_ci old_pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv); 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate, 24962306a36Sopenharmony_ci unsigned long prate) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 25262306a36Sopenharmony_ci const struct samsung_pll_rate_table *rate; 25362306a36Sopenharmony_ci u32 tmp; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* Get required rate settings from table */ 25662306a36Sopenharmony_ci rate = samsung_get_pll_settings(pll, drate); 25762306a36Sopenharmony_ci if (!rate) { 25862306a36Sopenharmony_ci pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, 25962306a36Sopenharmony_ci drate, clk_hw_get_name(hw)); 26062306a36Sopenharmony_ci return -EINVAL; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci tmp = readl_relaxed(pll->con_reg); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (!(samsung_pll35xx_mp_change(rate, tmp))) { 26662306a36Sopenharmony_ci /* If only s change, change just s value only*/ 26762306a36Sopenharmony_ci tmp &= ~(PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT); 26862306a36Sopenharmony_ci tmp |= rate->sdiv << PLL35XX_SDIV_SHIFT; 26962306a36Sopenharmony_ci writel_relaxed(tmp, pll->con_reg); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci return 0; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* Set PLL lock time. */ 27562306a36Sopenharmony_ci writel_relaxed(rate->pdiv * PLL35XX_LOCK_FACTOR, 27662306a36Sopenharmony_ci pll->lock_reg); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* Change PLL PMS values */ 27962306a36Sopenharmony_ci tmp &= ~((PLL35XX_MDIV_MASK << PLL35XX_MDIV_SHIFT) | 28062306a36Sopenharmony_ci (PLL35XX_PDIV_MASK << PLL35XX_PDIV_SHIFT) | 28162306a36Sopenharmony_ci (PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT)); 28262306a36Sopenharmony_ci tmp |= (rate->mdiv << PLL35XX_MDIV_SHIFT) | 28362306a36Sopenharmony_ci (rate->pdiv << PLL35XX_PDIV_SHIFT) | 28462306a36Sopenharmony_ci (rate->sdiv << PLL35XX_SDIV_SHIFT); 28562306a36Sopenharmony_ci writel_relaxed(tmp, pll->con_reg); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci /* Wait for PLL lock if the PLL is enabled */ 28862306a36Sopenharmony_ci if (tmp & BIT(pll->enable_offs)) 28962306a36Sopenharmony_ci return samsung_pll_lock_wait(pll, BIT(pll->lock_offs)); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci return 0; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic const struct clk_ops samsung_pll35xx_clk_ops = { 29562306a36Sopenharmony_ci .recalc_rate = samsung_pll35xx_recalc_rate, 29662306a36Sopenharmony_ci .round_rate = samsung_pll_round_rate, 29762306a36Sopenharmony_ci .set_rate = samsung_pll35xx_set_rate, 29862306a36Sopenharmony_ci .enable = samsung_pll3xxx_enable, 29962306a36Sopenharmony_ci .disable = samsung_pll3xxx_disable, 30062306a36Sopenharmony_ci}; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic const struct clk_ops samsung_pll35xx_clk_min_ops = { 30362306a36Sopenharmony_ci .recalc_rate = samsung_pll35xx_recalc_rate, 30462306a36Sopenharmony_ci}; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci/* 30762306a36Sopenharmony_ci * PLL36xx Clock Type 30862306a36Sopenharmony_ci */ 30962306a36Sopenharmony_ci/* Maximum lock time can be 3000 * PDIV cycles */ 31062306a36Sopenharmony_ci#define PLL36XX_LOCK_FACTOR (3000) 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci#define PLL36XX_KDIV_MASK (0xFFFF) 31362306a36Sopenharmony_ci#define PLL36XX_MDIV_MASK (0x1FF) 31462306a36Sopenharmony_ci#define PLL36XX_PDIV_MASK (0x3F) 31562306a36Sopenharmony_ci#define PLL36XX_SDIV_MASK (0x7) 31662306a36Sopenharmony_ci#define PLL36XX_MDIV_SHIFT (16) 31762306a36Sopenharmony_ci#define PLL36XX_PDIV_SHIFT (8) 31862306a36Sopenharmony_ci#define PLL36XX_SDIV_SHIFT (0) 31962306a36Sopenharmony_ci#define PLL36XX_KDIV_SHIFT (0) 32062306a36Sopenharmony_ci#define PLL36XX_LOCK_STAT_SHIFT (29) 32162306a36Sopenharmony_ci#define PLL36XX_ENABLE_SHIFT (31) 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw, 32462306a36Sopenharmony_ci unsigned long parent_rate) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 32762306a36Sopenharmony_ci u32 mdiv, pdiv, sdiv, pll_con0, pll_con1; 32862306a36Sopenharmony_ci s16 kdiv; 32962306a36Sopenharmony_ci u64 fvco = parent_rate; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci pll_con0 = readl_relaxed(pll->con_reg); 33262306a36Sopenharmony_ci pll_con1 = readl_relaxed(pll->con_reg + 4); 33362306a36Sopenharmony_ci mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK; 33462306a36Sopenharmony_ci pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK; 33562306a36Sopenharmony_ci sdiv = (pll_con0 >> PLL36XX_SDIV_SHIFT) & PLL36XX_SDIV_MASK; 33662306a36Sopenharmony_ci kdiv = (s16)(pll_con1 & PLL36XX_KDIV_MASK); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci fvco *= (mdiv << 16) + kdiv; 33962306a36Sopenharmony_ci do_div(fvco, (pdiv << sdiv)); 34062306a36Sopenharmony_ci fvco >>= 16; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci return (unsigned long)fvco; 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic inline bool samsung_pll36xx_mpk_change( 34662306a36Sopenharmony_ci const struct samsung_pll_rate_table *rate, u32 pll_con0, u32 pll_con1) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci u32 old_mdiv, old_pdiv, old_kdiv; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci old_mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK; 35162306a36Sopenharmony_ci old_pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK; 35262306a36Sopenharmony_ci old_kdiv = (pll_con1 >> PLL36XX_KDIV_SHIFT) & PLL36XX_KDIV_MASK; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv || 35562306a36Sopenharmony_ci rate->kdiv != old_kdiv); 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate, 35962306a36Sopenharmony_ci unsigned long parent_rate) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 36262306a36Sopenharmony_ci u32 pll_con0, pll_con1; 36362306a36Sopenharmony_ci const struct samsung_pll_rate_table *rate; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci rate = samsung_get_pll_settings(pll, drate); 36662306a36Sopenharmony_ci if (!rate) { 36762306a36Sopenharmony_ci pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, 36862306a36Sopenharmony_ci drate, clk_hw_get_name(hw)); 36962306a36Sopenharmony_ci return -EINVAL; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci pll_con0 = readl_relaxed(pll->con_reg); 37362306a36Sopenharmony_ci pll_con1 = readl_relaxed(pll->con_reg + 4); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (!(samsung_pll36xx_mpk_change(rate, pll_con0, pll_con1))) { 37662306a36Sopenharmony_ci /* If only s change, change just s value only*/ 37762306a36Sopenharmony_ci pll_con0 &= ~(PLL36XX_SDIV_MASK << PLL36XX_SDIV_SHIFT); 37862306a36Sopenharmony_ci pll_con0 |= (rate->sdiv << PLL36XX_SDIV_SHIFT); 37962306a36Sopenharmony_ci writel_relaxed(pll_con0, pll->con_reg); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci return 0; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* Set PLL lock time. */ 38562306a36Sopenharmony_ci writel_relaxed(rate->pdiv * PLL36XX_LOCK_FACTOR, pll->lock_reg); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* Change PLL PMS values */ 38862306a36Sopenharmony_ci pll_con0 &= ~((PLL36XX_MDIV_MASK << PLL36XX_MDIV_SHIFT) | 38962306a36Sopenharmony_ci (PLL36XX_PDIV_MASK << PLL36XX_PDIV_SHIFT) | 39062306a36Sopenharmony_ci (PLL36XX_SDIV_MASK << PLL36XX_SDIV_SHIFT)); 39162306a36Sopenharmony_ci pll_con0 |= (rate->mdiv << PLL36XX_MDIV_SHIFT) | 39262306a36Sopenharmony_ci (rate->pdiv << PLL36XX_PDIV_SHIFT) | 39362306a36Sopenharmony_ci (rate->sdiv << PLL36XX_SDIV_SHIFT); 39462306a36Sopenharmony_ci writel_relaxed(pll_con0, pll->con_reg); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci pll_con1 &= ~(PLL36XX_KDIV_MASK << PLL36XX_KDIV_SHIFT); 39762306a36Sopenharmony_ci pll_con1 |= rate->kdiv << PLL36XX_KDIV_SHIFT; 39862306a36Sopenharmony_ci writel_relaxed(pll_con1, pll->con_reg + 4); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (pll_con0 & BIT(pll->enable_offs)) 40162306a36Sopenharmony_ci return samsung_pll_lock_wait(pll, BIT(pll->lock_offs)); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci return 0; 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic const struct clk_ops samsung_pll36xx_clk_ops = { 40762306a36Sopenharmony_ci .recalc_rate = samsung_pll36xx_recalc_rate, 40862306a36Sopenharmony_ci .set_rate = samsung_pll36xx_set_rate, 40962306a36Sopenharmony_ci .round_rate = samsung_pll_round_rate, 41062306a36Sopenharmony_ci .enable = samsung_pll3xxx_enable, 41162306a36Sopenharmony_ci .disable = samsung_pll3xxx_disable, 41262306a36Sopenharmony_ci}; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic const struct clk_ops samsung_pll36xx_clk_min_ops = { 41562306a36Sopenharmony_ci .recalc_rate = samsung_pll36xx_recalc_rate, 41662306a36Sopenharmony_ci}; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci/* 41962306a36Sopenharmony_ci * PLL0822x Clock Type 42062306a36Sopenharmony_ci */ 42162306a36Sopenharmony_ci/* Maximum lock time can be 150 * PDIV cycles */ 42262306a36Sopenharmony_ci#define PLL0822X_LOCK_FACTOR (150) 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci#define PLL0822X_MDIV_MASK (0x3FF) 42562306a36Sopenharmony_ci#define PLL0822X_PDIV_MASK (0x3F) 42662306a36Sopenharmony_ci#define PLL0822X_SDIV_MASK (0x7) 42762306a36Sopenharmony_ci#define PLL0822X_MDIV_SHIFT (16) 42862306a36Sopenharmony_ci#define PLL0822X_PDIV_SHIFT (8) 42962306a36Sopenharmony_ci#define PLL0822X_SDIV_SHIFT (0) 43062306a36Sopenharmony_ci#define PLL0822X_LOCK_STAT_SHIFT (29) 43162306a36Sopenharmony_ci#define PLL0822X_ENABLE_SHIFT (31) 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic unsigned long samsung_pll0822x_recalc_rate(struct clk_hw *hw, 43462306a36Sopenharmony_ci unsigned long parent_rate) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 43762306a36Sopenharmony_ci u32 mdiv, pdiv, sdiv, pll_con3; 43862306a36Sopenharmony_ci u64 fvco = parent_rate; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci pll_con3 = readl_relaxed(pll->con_reg); 44162306a36Sopenharmony_ci mdiv = (pll_con3 >> PLL0822X_MDIV_SHIFT) & PLL0822X_MDIV_MASK; 44262306a36Sopenharmony_ci pdiv = (pll_con3 >> PLL0822X_PDIV_SHIFT) & PLL0822X_PDIV_MASK; 44362306a36Sopenharmony_ci sdiv = (pll_con3 >> PLL0822X_SDIV_SHIFT) & PLL0822X_SDIV_MASK; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci fvco *= mdiv; 44662306a36Sopenharmony_ci do_div(fvco, (pdiv << sdiv)); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci return (unsigned long)fvco; 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic int samsung_pll0822x_set_rate(struct clk_hw *hw, unsigned long drate, 45262306a36Sopenharmony_ci unsigned long prate) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci const struct samsung_pll_rate_table *rate; 45562306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 45662306a36Sopenharmony_ci u32 pll_con3; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci /* Get required rate settings from table */ 45962306a36Sopenharmony_ci rate = samsung_get_pll_settings(pll, drate); 46062306a36Sopenharmony_ci if (!rate) { 46162306a36Sopenharmony_ci pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, 46262306a36Sopenharmony_ci drate, clk_hw_get_name(hw)); 46362306a36Sopenharmony_ci return -EINVAL; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci /* Change PLL PMS values */ 46762306a36Sopenharmony_ci pll_con3 = readl_relaxed(pll->con_reg); 46862306a36Sopenharmony_ci pll_con3 &= ~((PLL0822X_MDIV_MASK << PLL0822X_MDIV_SHIFT) | 46962306a36Sopenharmony_ci (PLL0822X_PDIV_MASK << PLL0822X_PDIV_SHIFT) | 47062306a36Sopenharmony_ci (PLL0822X_SDIV_MASK << PLL0822X_SDIV_SHIFT)); 47162306a36Sopenharmony_ci pll_con3 |= (rate->mdiv << PLL0822X_MDIV_SHIFT) | 47262306a36Sopenharmony_ci (rate->pdiv << PLL0822X_PDIV_SHIFT) | 47362306a36Sopenharmony_ci (rate->sdiv << PLL0822X_SDIV_SHIFT); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* Set PLL lock time */ 47662306a36Sopenharmony_ci writel_relaxed(rate->pdiv * PLL0822X_LOCK_FACTOR, 47762306a36Sopenharmony_ci pll->lock_reg); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci /* Write PMS values */ 48062306a36Sopenharmony_ci writel_relaxed(pll_con3, pll->con_reg); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* Wait for PLL lock if the PLL is enabled */ 48362306a36Sopenharmony_ci if (pll_con3 & BIT(pll->enable_offs)) 48462306a36Sopenharmony_ci return samsung_pll_lock_wait(pll, BIT(pll->lock_offs)); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci return 0; 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic const struct clk_ops samsung_pll0822x_clk_ops = { 49062306a36Sopenharmony_ci .recalc_rate = samsung_pll0822x_recalc_rate, 49162306a36Sopenharmony_ci .round_rate = samsung_pll_round_rate, 49262306a36Sopenharmony_ci .set_rate = samsung_pll0822x_set_rate, 49362306a36Sopenharmony_ci .enable = samsung_pll3xxx_enable, 49462306a36Sopenharmony_ci .disable = samsung_pll3xxx_disable, 49562306a36Sopenharmony_ci}; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic const struct clk_ops samsung_pll0822x_clk_min_ops = { 49862306a36Sopenharmony_ci .recalc_rate = samsung_pll0822x_recalc_rate, 49962306a36Sopenharmony_ci}; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci/* 50262306a36Sopenharmony_ci * PLL0831x Clock Type 50362306a36Sopenharmony_ci */ 50462306a36Sopenharmony_ci/* Maximum lock time can be 500 * PDIV cycles */ 50562306a36Sopenharmony_ci#define PLL0831X_LOCK_FACTOR (500) 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci#define PLL0831X_KDIV_MASK (0xFFFF) 50862306a36Sopenharmony_ci#define PLL0831X_MDIV_MASK (0x1FF) 50962306a36Sopenharmony_ci#define PLL0831X_PDIV_MASK (0x3F) 51062306a36Sopenharmony_ci#define PLL0831X_SDIV_MASK (0x7) 51162306a36Sopenharmony_ci#define PLL0831X_MDIV_SHIFT (16) 51262306a36Sopenharmony_ci#define PLL0831X_PDIV_SHIFT (8) 51362306a36Sopenharmony_ci#define PLL0831X_SDIV_SHIFT (0) 51462306a36Sopenharmony_ci#define PLL0831X_KDIV_SHIFT (0) 51562306a36Sopenharmony_ci#define PLL0831X_LOCK_STAT_SHIFT (29) 51662306a36Sopenharmony_ci#define PLL0831X_ENABLE_SHIFT (31) 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic unsigned long samsung_pll0831x_recalc_rate(struct clk_hw *hw, 51962306a36Sopenharmony_ci unsigned long parent_rate) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 52262306a36Sopenharmony_ci u32 mdiv, pdiv, sdiv, pll_con3, pll_con5; 52362306a36Sopenharmony_ci s16 kdiv; 52462306a36Sopenharmony_ci u64 fvco = parent_rate; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci pll_con3 = readl_relaxed(pll->con_reg); 52762306a36Sopenharmony_ci pll_con5 = readl_relaxed(pll->con_reg + 8); 52862306a36Sopenharmony_ci mdiv = (pll_con3 >> PLL0831X_MDIV_SHIFT) & PLL0831X_MDIV_MASK; 52962306a36Sopenharmony_ci pdiv = (pll_con3 >> PLL0831X_PDIV_SHIFT) & PLL0831X_PDIV_MASK; 53062306a36Sopenharmony_ci sdiv = (pll_con3 >> PLL0831X_SDIV_SHIFT) & PLL0831X_SDIV_MASK; 53162306a36Sopenharmony_ci kdiv = (s16)((pll_con5 >> PLL0831X_KDIV_SHIFT) & PLL0831X_KDIV_MASK); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci fvco *= (mdiv << 16) + kdiv; 53462306a36Sopenharmony_ci do_div(fvco, (pdiv << sdiv)); 53562306a36Sopenharmony_ci fvco >>= 16; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci return (unsigned long)fvco; 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic int samsung_pll0831x_set_rate(struct clk_hw *hw, unsigned long drate, 54162306a36Sopenharmony_ci unsigned long parent_rate) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci const struct samsung_pll_rate_table *rate; 54462306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 54562306a36Sopenharmony_ci u32 pll_con3, pll_con5; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* Get required rate settings from table */ 54862306a36Sopenharmony_ci rate = samsung_get_pll_settings(pll, drate); 54962306a36Sopenharmony_ci if (!rate) { 55062306a36Sopenharmony_ci pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, 55162306a36Sopenharmony_ci drate, clk_hw_get_name(hw)); 55262306a36Sopenharmony_ci return -EINVAL; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci pll_con3 = readl_relaxed(pll->con_reg); 55662306a36Sopenharmony_ci pll_con5 = readl_relaxed(pll->con_reg + 8); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci /* Change PLL PMSK values */ 55962306a36Sopenharmony_ci pll_con3 &= ~((PLL0831X_MDIV_MASK << PLL0831X_MDIV_SHIFT) | 56062306a36Sopenharmony_ci (PLL0831X_PDIV_MASK << PLL0831X_PDIV_SHIFT) | 56162306a36Sopenharmony_ci (PLL0831X_SDIV_MASK << PLL0831X_SDIV_SHIFT)); 56262306a36Sopenharmony_ci pll_con3 |= (rate->mdiv << PLL0831X_MDIV_SHIFT) | 56362306a36Sopenharmony_ci (rate->pdiv << PLL0831X_PDIV_SHIFT) | 56462306a36Sopenharmony_ci (rate->sdiv << PLL0831X_SDIV_SHIFT); 56562306a36Sopenharmony_ci pll_con5 &= ~(PLL0831X_KDIV_MASK << PLL0831X_KDIV_SHIFT); 56662306a36Sopenharmony_ci /* 56762306a36Sopenharmony_ci * kdiv is 16-bit 2's complement (s16), but stored as unsigned int. 56862306a36Sopenharmony_ci * Cast it to u16 to avoid leading 0xffff's in case of negative value. 56962306a36Sopenharmony_ci */ 57062306a36Sopenharmony_ci pll_con5 |= ((u16)rate->kdiv << PLL0831X_KDIV_SHIFT); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci /* Set PLL lock time */ 57362306a36Sopenharmony_ci writel_relaxed(rate->pdiv * PLL0831X_LOCK_FACTOR, pll->lock_reg); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci /* Write PMSK values */ 57662306a36Sopenharmony_ci writel_relaxed(pll_con3, pll->con_reg); 57762306a36Sopenharmony_ci writel_relaxed(pll_con5, pll->con_reg + 8); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci /* Wait for PLL lock if the PLL is enabled */ 58062306a36Sopenharmony_ci if (pll_con3 & BIT(pll->enable_offs)) 58162306a36Sopenharmony_ci return samsung_pll_lock_wait(pll, BIT(pll->lock_offs)); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci return 0; 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic const struct clk_ops samsung_pll0831x_clk_ops = { 58762306a36Sopenharmony_ci .recalc_rate = samsung_pll0831x_recalc_rate, 58862306a36Sopenharmony_ci .set_rate = samsung_pll0831x_set_rate, 58962306a36Sopenharmony_ci .round_rate = samsung_pll_round_rate, 59062306a36Sopenharmony_ci .enable = samsung_pll3xxx_enable, 59162306a36Sopenharmony_ci .disable = samsung_pll3xxx_disable, 59262306a36Sopenharmony_ci}; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_cistatic const struct clk_ops samsung_pll0831x_clk_min_ops = { 59562306a36Sopenharmony_ci .recalc_rate = samsung_pll0831x_recalc_rate, 59662306a36Sopenharmony_ci}; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci/* 59962306a36Sopenharmony_ci * PLL45xx Clock Type 60062306a36Sopenharmony_ci */ 60162306a36Sopenharmony_ci#define PLL4502_LOCK_FACTOR 400 60262306a36Sopenharmony_ci#define PLL4508_LOCK_FACTOR 240 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci#define PLL45XX_MDIV_MASK (0x3FF) 60562306a36Sopenharmony_ci#define PLL45XX_PDIV_MASK (0x3F) 60662306a36Sopenharmony_ci#define PLL45XX_SDIV_MASK (0x7) 60762306a36Sopenharmony_ci#define PLL45XX_AFC_MASK (0x1F) 60862306a36Sopenharmony_ci#define PLL45XX_MDIV_SHIFT (16) 60962306a36Sopenharmony_ci#define PLL45XX_PDIV_SHIFT (8) 61062306a36Sopenharmony_ci#define PLL45XX_SDIV_SHIFT (0) 61162306a36Sopenharmony_ci#define PLL45XX_AFC_SHIFT (0) 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci#define PLL45XX_ENABLE BIT(31) 61462306a36Sopenharmony_ci#define PLL45XX_LOCKED BIT(29) 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_cistatic unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw, 61762306a36Sopenharmony_ci unsigned long parent_rate) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 62062306a36Sopenharmony_ci u32 mdiv, pdiv, sdiv, pll_con; 62162306a36Sopenharmony_ci u64 fvco = parent_rate; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci pll_con = readl_relaxed(pll->con_reg); 62462306a36Sopenharmony_ci mdiv = (pll_con >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK; 62562306a36Sopenharmony_ci pdiv = (pll_con >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK; 62662306a36Sopenharmony_ci sdiv = (pll_con >> PLL45XX_SDIV_SHIFT) & PLL45XX_SDIV_MASK; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci if (pll->type == pll_4508) 62962306a36Sopenharmony_ci sdiv = sdiv - 1; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci fvco *= mdiv; 63262306a36Sopenharmony_ci do_div(fvco, (pdiv << sdiv)); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci return (unsigned long)fvco; 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_cistatic bool samsung_pll45xx_mp_change(u32 pll_con0, u32 pll_con1, 63862306a36Sopenharmony_ci const struct samsung_pll_rate_table *rate) 63962306a36Sopenharmony_ci{ 64062306a36Sopenharmony_ci u32 old_mdiv, old_pdiv, old_afc; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci old_mdiv = (pll_con0 >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK; 64362306a36Sopenharmony_ci old_pdiv = (pll_con0 >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK; 64462306a36Sopenharmony_ci old_afc = (pll_con1 >> PLL45XX_AFC_SHIFT) & PLL45XX_AFC_MASK; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci return (old_mdiv != rate->mdiv || old_pdiv != rate->pdiv 64762306a36Sopenharmony_ci || old_afc != rate->afc); 64862306a36Sopenharmony_ci} 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_cistatic int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate, 65162306a36Sopenharmony_ci unsigned long prate) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 65462306a36Sopenharmony_ci const struct samsung_pll_rate_table *rate; 65562306a36Sopenharmony_ci u32 con0, con1; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* Get required rate settings from table */ 65862306a36Sopenharmony_ci rate = samsung_get_pll_settings(pll, drate); 65962306a36Sopenharmony_ci if (!rate) { 66062306a36Sopenharmony_ci pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, 66162306a36Sopenharmony_ci drate, clk_hw_get_name(hw)); 66262306a36Sopenharmony_ci return -EINVAL; 66362306a36Sopenharmony_ci } 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci con0 = readl_relaxed(pll->con_reg); 66662306a36Sopenharmony_ci con1 = readl_relaxed(pll->con_reg + 0x4); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci if (!(samsung_pll45xx_mp_change(con0, con1, rate))) { 66962306a36Sopenharmony_ci /* If only s change, change just s value only*/ 67062306a36Sopenharmony_ci con0 &= ~(PLL45XX_SDIV_MASK << PLL45XX_SDIV_SHIFT); 67162306a36Sopenharmony_ci con0 |= rate->sdiv << PLL45XX_SDIV_SHIFT; 67262306a36Sopenharmony_ci writel_relaxed(con0, pll->con_reg); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci return 0; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci /* Set PLL PMS values. */ 67862306a36Sopenharmony_ci con0 &= ~((PLL45XX_MDIV_MASK << PLL45XX_MDIV_SHIFT) | 67962306a36Sopenharmony_ci (PLL45XX_PDIV_MASK << PLL45XX_PDIV_SHIFT) | 68062306a36Sopenharmony_ci (PLL45XX_SDIV_MASK << PLL45XX_SDIV_SHIFT)); 68162306a36Sopenharmony_ci con0 |= (rate->mdiv << PLL45XX_MDIV_SHIFT) | 68262306a36Sopenharmony_ci (rate->pdiv << PLL45XX_PDIV_SHIFT) | 68362306a36Sopenharmony_ci (rate->sdiv << PLL45XX_SDIV_SHIFT); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci /* Set PLL AFC value. */ 68662306a36Sopenharmony_ci con1 = readl_relaxed(pll->con_reg + 0x4); 68762306a36Sopenharmony_ci con1 &= ~(PLL45XX_AFC_MASK << PLL45XX_AFC_SHIFT); 68862306a36Sopenharmony_ci con1 |= (rate->afc << PLL45XX_AFC_SHIFT); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci /* Set PLL lock time. */ 69162306a36Sopenharmony_ci switch (pll->type) { 69262306a36Sopenharmony_ci case pll_4502: 69362306a36Sopenharmony_ci writel_relaxed(rate->pdiv * PLL4502_LOCK_FACTOR, pll->lock_reg); 69462306a36Sopenharmony_ci break; 69562306a36Sopenharmony_ci case pll_4508: 69662306a36Sopenharmony_ci writel_relaxed(rate->pdiv * PLL4508_LOCK_FACTOR, pll->lock_reg); 69762306a36Sopenharmony_ci break; 69862306a36Sopenharmony_ci default: 69962306a36Sopenharmony_ci break; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci /* Set new configuration. */ 70362306a36Sopenharmony_ci writel_relaxed(con1, pll->con_reg + 0x4); 70462306a36Sopenharmony_ci writel_relaxed(con0, pll->con_reg); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci /* Wait for PLL lock */ 70762306a36Sopenharmony_ci return samsung_pll_lock_wait(pll, PLL45XX_LOCKED); 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cistatic const struct clk_ops samsung_pll45xx_clk_ops = { 71162306a36Sopenharmony_ci .recalc_rate = samsung_pll45xx_recalc_rate, 71262306a36Sopenharmony_ci .round_rate = samsung_pll_round_rate, 71362306a36Sopenharmony_ci .set_rate = samsung_pll45xx_set_rate, 71462306a36Sopenharmony_ci}; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic const struct clk_ops samsung_pll45xx_clk_min_ops = { 71762306a36Sopenharmony_ci .recalc_rate = samsung_pll45xx_recalc_rate, 71862306a36Sopenharmony_ci}; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci/* 72162306a36Sopenharmony_ci * PLL46xx Clock Type 72262306a36Sopenharmony_ci */ 72362306a36Sopenharmony_ci#define PLL46XX_LOCK_FACTOR 3000 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci#define PLL46XX_VSEL_MASK (1) 72662306a36Sopenharmony_ci#define PLL46XX_MDIV_MASK (0x1FF) 72762306a36Sopenharmony_ci#define PLL1460X_MDIV_MASK (0x3FF) 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci#define PLL46XX_PDIV_MASK (0x3F) 73062306a36Sopenharmony_ci#define PLL46XX_SDIV_MASK (0x7) 73162306a36Sopenharmony_ci#define PLL46XX_VSEL_SHIFT (27) 73262306a36Sopenharmony_ci#define PLL46XX_MDIV_SHIFT (16) 73362306a36Sopenharmony_ci#define PLL46XX_PDIV_SHIFT (8) 73462306a36Sopenharmony_ci#define PLL46XX_SDIV_SHIFT (0) 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci#define PLL46XX_KDIV_MASK (0xFFFF) 73762306a36Sopenharmony_ci#define PLL4650C_KDIV_MASK (0xFFF) 73862306a36Sopenharmony_ci#define PLL46XX_KDIV_SHIFT (0) 73962306a36Sopenharmony_ci#define PLL46XX_MFR_MASK (0x3F) 74062306a36Sopenharmony_ci#define PLL46XX_MRR_MASK (0x1F) 74162306a36Sopenharmony_ci#define PLL46XX_KDIV_SHIFT (0) 74262306a36Sopenharmony_ci#define PLL46XX_MFR_SHIFT (16) 74362306a36Sopenharmony_ci#define PLL46XX_MRR_SHIFT (24) 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci#define PLL46XX_ENABLE BIT(31) 74662306a36Sopenharmony_ci#define PLL46XX_LOCKED BIT(29) 74762306a36Sopenharmony_ci#define PLL46XX_VSEL BIT(27) 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_cistatic unsigned long samsung_pll46xx_recalc_rate(struct clk_hw *hw, 75062306a36Sopenharmony_ci unsigned long parent_rate) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 75362306a36Sopenharmony_ci u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1, shift; 75462306a36Sopenharmony_ci u64 fvco = parent_rate; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci pll_con0 = readl_relaxed(pll->con_reg); 75762306a36Sopenharmony_ci pll_con1 = readl_relaxed(pll->con_reg + 4); 75862306a36Sopenharmony_ci mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & ((pll->type == pll_1460x) ? 75962306a36Sopenharmony_ci PLL1460X_MDIV_MASK : PLL46XX_MDIV_MASK); 76062306a36Sopenharmony_ci pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK; 76162306a36Sopenharmony_ci sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK; 76262306a36Sopenharmony_ci kdiv = pll->type == pll_4650c ? pll_con1 & PLL4650C_KDIV_MASK : 76362306a36Sopenharmony_ci pll_con1 & PLL46XX_KDIV_MASK; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci shift = ((pll->type == pll_4600) || (pll->type == pll_1460x)) ? 16 : 10; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci fvco *= (mdiv << shift) + kdiv; 76862306a36Sopenharmony_ci do_div(fvco, (pdiv << sdiv)); 76962306a36Sopenharmony_ci fvco >>= shift; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci return (unsigned long)fvco; 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic bool samsung_pll46xx_mpk_change(u32 pll_con0, u32 pll_con1, 77562306a36Sopenharmony_ci const struct samsung_pll_rate_table *rate) 77662306a36Sopenharmony_ci{ 77762306a36Sopenharmony_ci u32 old_mdiv, old_pdiv, old_kdiv; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci old_mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK; 78062306a36Sopenharmony_ci old_pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK; 78162306a36Sopenharmony_ci old_kdiv = (pll_con1 >> PLL46XX_KDIV_SHIFT) & PLL46XX_KDIV_MASK; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci return (old_mdiv != rate->mdiv || old_pdiv != rate->pdiv 78462306a36Sopenharmony_ci || old_kdiv != rate->kdiv); 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_cistatic int samsung_pll46xx_set_rate(struct clk_hw *hw, unsigned long drate, 78862306a36Sopenharmony_ci unsigned long prate) 78962306a36Sopenharmony_ci{ 79062306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 79162306a36Sopenharmony_ci const struct samsung_pll_rate_table *rate; 79262306a36Sopenharmony_ci u32 con0, con1, lock; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci /* Get required rate settings from table */ 79562306a36Sopenharmony_ci rate = samsung_get_pll_settings(pll, drate); 79662306a36Sopenharmony_ci if (!rate) { 79762306a36Sopenharmony_ci pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, 79862306a36Sopenharmony_ci drate, clk_hw_get_name(hw)); 79962306a36Sopenharmony_ci return -EINVAL; 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci con0 = readl_relaxed(pll->con_reg); 80362306a36Sopenharmony_ci con1 = readl_relaxed(pll->con_reg + 0x4); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci if (!(samsung_pll46xx_mpk_change(con0, con1, rate))) { 80662306a36Sopenharmony_ci /* If only s change, change just s value only*/ 80762306a36Sopenharmony_ci con0 &= ~(PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT); 80862306a36Sopenharmony_ci con0 |= rate->sdiv << PLL46XX_SDIV_SHIFT; 80962306a36Sopenharmony_ci writel_relaxed(con0, pll->con_reg); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci return 0; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci /* Set PLL lock time. */ 81562306a36Sopenharmony_ci lock = rate->pdiv * PLL46XX_LOCK_FACTOR; 81662306a36Sopenharmony_ci if (lock > 0xffff) 81762306a36Sopenharmony_ci /* Maximum lock time bitfield is 16-bit. */ 81862306a36Sopenharmony_ci lock = 0xffff; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci /* Set PLL PMS and VSEL values. */ 82162306a36Sopenharmony_ci if (pll->type == pll_1460x) { 82262306a36Sopenharmony_ci con0 &= ~((PLL1460X_MDIV_MASK << PLL46XX_MDIV_SHIFT) | 82362306a36Sopenharmony_ci (PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT) | 82462306a36Sopenharmony_ci (PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT)); 82562306a36Sopenharmony_ci } else { 82662306a36Sopenharmony_ci con0 &= ~((PLL46XX_MDIV_MASK << PLL46XX_MDIV_SHIFT) | 82762306a36Sopenharmony_ci (PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT) | 82862306a36Sopenharmony_ci (PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT) | 82962306a36Sopenharmony_ci (PLL46XX_VSEL_MASK << PLL46XX_VSEL_SHIFT)); 83062306a36Sopenharmony_ci con0 |= rate->vsel << PLL46XX_VSEL_SHIFT; 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci con0 |= (rate->mdiv << PLL46XX_MDIV_SHIFT) | 83462306a36Sopenharmony_ci (rate->pdiv << PLL46XX_PDIV_SHIFT) | 83562306a36Sopenharmony_ci (rate->sdiv << PLL46XX_SDIV_SHIFT); 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci /* Set PLL K, MFR and MRR values. */ 83862306a36Sopenharmony_ci con1 = readl_relaxed(pll->con_reg + 0x4); 83962306a36Sopenharmony_ci con1 &= ~((PLL46XX_KDIV_MASK << PLL46XX_KDIV_SHIFT) | 84062306a36Sopenharmony_ci (PLL46XX_MFR_MASK << PLL46XX_MFR_SHIFT) | 84162306a36Sopenharmony_ci (PLL46XX_MRR_MASK << PLL46XX_MRR_SHIFT)); 84262306a36Sopenharmony_ci con1 |= (rate->kdiv << PLL46XX_KDIV_SHIFT) | 84362306a36Sopenharmony_ci (rate->mfr << PLL46XX_MFR_SHIFT) | 84462306a36Sopenharmony_ci (rate->mrr << PLL46XX_MRR_SHIFT); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci /* Write configuration to PLL */ 84762306a36Sopenharmony_ci writel_relaxed(lock, pll->lock_reg); 84862306a36Sopenharmony_ci writel_relaxed(con0, pll->con_reg); 84962306a36Sopenharmony_ci writel_relaxed(con1, pll->con_reg + 0x4); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci /* Wait for PLL lock */ 85262306a36Sopenharmony_ci return samsung_pll_lock_wait(pll, PLL46XX_LOCKED); 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_cistatic const struct clk_ops samsung_pll46xx_clk_ops = { 85662306a36Sopenharmony_ci .recalc_rate = samsung_pll46xx_recalc_rate, 85762306a36Sopenharmony_ci .round_rate = samsung_pll_round_rate, 85862306a36Sopenharmony_ci .set_rate = samsung_pll46xx_set_rate, 85962306a36Sopenharmony_ci}; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_cistatic const struct clk_ops samsung_pll46xx_clk_min_ops = { 86262306a36Sopenharmony_ci .recalc_rate = samsung_pll46xx_recalc_rate, 86362306a36Sopenharmony_ci}; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci/* 86662306a36Sopenharmony_ci * PLL6552 Clock Type 86762306a36Sopenharmony_ci */ 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci#define PLL6552_MDIV_MASK 0x3ff 87062306a36Sopenharmony_ci#define PLL6552_PDIV_MASK 0x3f 87162306a36Sopenharmony_ci#define PLL6552_SDIV_MASK 0x7 87262306a36Sopenharmony_ci#define PLL6552_MDIV_SHIFT 16 87362306a36Sopenharmony_ci#define PLL6552_MDIV_SHIFT_2416 14 87462306a36Sopenharmony_ci#define PLL6552_PDIV_SHIFT 8 87562306a36Sopenharmony_ci#define PLL6552_PDIV_SHIFT_2416 5 87662306a36Sopenharmony_ci#define PLL6552_SDIV_SHIFT 0 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_cistatic unsigned long samsung_pll6552_recalc_rate(struct clk_hw *hw, 87962306a36Sopenharmony_ci unsigned long parent_rate) 88062306a36Sopenharmony_ci{ 88162306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 88262306a36Sopenharmony_ci u32 mdiv, pdiv, sdiv, pll_con; 88362306a36Sopenharmony_ci u64 fvco = parent_rate; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci pll_con = readl_relaxed(pll->con_reg); 88662306a36Sopenharmony_ci if (pll->type == pll_6552_s3c2416) { 88762306a36Sopenharmony_ci mdiv = (pll_con >> PLL6552_MDIV_SHIFT_2416) & PLL6552_MDIV_MASK; 88862306a36Sopenharmony_ci pdiv = (pll_con >> PLL6552_PDIV_SHIFT_2416) & PLL6552_PDIV_MASK; 88962306a36Sopenharmony_ci } else { 89062306a36Sopenharmony_ci mdiv = (pll_con >> PLL6552_MDIV_SHIFT) & PLL6552_MDIV_MASK; 89162306a36Sopenharmony_ci pdiv = (pll_con >> PLL6552_PDIV_SHIFT) & PLL6552_PDIV_MASK; 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci sdiv = (pll_con >> PLL6552_SDIV_SHIFT) & PLL6552_SDIV_MASK; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci fvco *= mdiv; 89662306a36Sopenharmony_ci do_div(fvco, (pdiv << sdiv)); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci return (unsigned long)fvco; 89962306a36Sopenharmony_ci} 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_cistatic const struct clk_ops samsung_pll6552_clk_ops = { 90262306a36Sopenharmony_ci .recalc_rate = samsung_pll6552_recalc_rate, 90362306a36Sopenharmony_ci}; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci/* 90662306a36Sopenharmony_ci * PLL6553 Clock Type 90762306a36Sopenharmony_ci */ 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci#define PLL6553_MDIV_MASK 0xff 91062306a36Sopenharmony_ci#define PLL6553_PDIV_MASK 0x3f 91162306a36Sopenharmony_ci#define PLL6553_SDIV_MASK 0x7 91262306a36Sopenharmony_ci#define PLL6553_KDIV_MASK 0xffff 91362306a36Sopenharmony_ci#define PLL6553_MDIV_SHIFT 16 91462306a36Sopenharmony_ci#define PLL6553_PDIV_SHIFT 8 91562306a36Sopenharmony_ci#define PLL6553_SDIV_SHIFT 0 91662306a36Sopenharmony_ci#define PLL6553_KDIV_SHIFT 0 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_cistatic unsigned long samsung_pll6553_recalc_rate(struct clk_hw *hw, 91962306a36Sopenharmony_ci unsigned long parent_rate) 92062306a36Sopenharmony_ci{ 92162306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 92262306a36Sopenharmony_ci u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1; 92362306a36Sopenharmony_ci u64 fvco = parent_rate; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci pll_con0 = readl_relaxed(pll->con_reg); 92662306a36Sopenharmony_ci pll_con1 = readl_relaxed(pll->con_reg + 0x4); 92762306a36Sopenharmony_ci mdiv = (pll_con0 >> PLL6553_MDIV_SHIFT) & PLL6553_MDIV_MASK; 92862306a36Sopenharmony_ci pdiv = (pll_con0 >> PLL6553_PDIV_SHIFT) & PLL6553_PDIV_MASK; 92962306a36Sopenharmony_ci sdiv = (pll_con0 >> PLL6553_SDIV_SHIFT) & PLL6553_SDIV_MASK; 93062306a36Sopenharmony_ci kdiv = (pll_con1 >> PLL6553_KDIV_SHIFT) & PLL6553_KDIV_MASK; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci fvco *= (mdiv << 16) + kdiv; 93362306a36Sopenharmony_ci do_div(fvco, (pdiv << sdiv)); 93462306a36Sopenharmony_ci fvco >>= 16; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci return (unsigned long)fvco; 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_cistatic const struct clk_ops samsung_pll6553_clk_ops = { 94062306a36Sopenharmony_ci .recalc_rate = samsung_pll6553_recalc_rate, 94162306a36Sopenharmony_ci}; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci/* 94462306a36Sopenharmony_ci * PLL2550x Clock Type 94562306a36Sopenharmony_ci */ 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci#define PLL2550X_R_MASK (0x1) 94862306a36Sopenharmony_ci#define PLL2550X_P_MASK (0x3F) 94962306a36Sopenharmony_ci#define PLL2550X_M_MASK (0x3FF) 95062306a36Sopenharmony_ci#define PLL2550X_S_MASK (0x7) 95162306a36Sopenharmony_ci#define PLL2550X_R_SHIFT (20) 95262306a36Sopenharmony_ci#define PLL2550X_P_SHIFT (14) 95362306a36Sopenharmony_ci#define PLL2550X_M_SHIFT (4) 95462306a36Sopenharmony_ci#define PLL2550X_S_SHIFT (0) 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_cistatic unsigned long samsung_pll2550x_recalc_rate(struct clk_hw *hw, 95762306a36Sopenharmony_ci unsigned long parent_rate) 95862306a36Sopenharmony_ci{ 95962306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 96062306a36Sopenharmony_ci u32 r, p, m, s, pll_stat; 96162306a36Sopenharmony_ci u64 fvco = parent_rate; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci pll_stat = readl_relaxed(pll->con_reg); 96462306a36Sopenharmony_ci r = (pll_stat >> PLL2550X_R_SHIFT) & PLL2550X_R_MASK; 96562306a36Sopenharmony_ci if (!r) 96662306a36Sopenharmony_ci return 0; 96762306a36Sopenharmony_ci p = (pll_stat >> PLL2550X_P_SHIFT) & PLL2550X_P_MASK; 96862306a36Sopenharmony_ci m = (pll_stat >> PLL2550X_M_SHIFT) & PLL2550X_M_MASK; 96962306a36Sopenharmony_ci s = (pll_stat >> PLL2550X_S_SHIFT) & PLL2550X_S_MASK; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci fvco *= m; 97262306a36Sopenharmony_ci do_div(fvco, (p << s)); 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci return (unsigned long)fvco; 97562306a36Sopenharmony_ci} 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_cistatic const struct clk_ops samsung_pll2550x_clk_ops = { 97862306a36Sopenharmony_ci .recalc_rate = samsung_pll2550x_recalc_rate, 97962306a36Sopenharmony_ci}; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci/* 98262306a36Sopenharmony_ci * PLL2550xx Clock Type 98362306a36Sopenharmony_ci */ 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci/* Maximum lock time can be 270 * PDIV cycles */ 98662306a36Sopenharmony_ci#define PLL2550XX_LOCK_FACTOR 270 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci#define PLL2550XX_M_MASK 0x3FF 98962306a36Sopenharmony_ci#define PLL2550XX_P_MASK 0x3F 99062306a36Sopenharmony_ci#define PLL2550XX_S_MASK 0x7 99162306a36Sopenharmony_ci#define PLL2550XX_LOCK_STAT_MASK 0x1 99262306a36Sopenharmony_ci#define PLL2550XX_M_SHIFT 9 99362306a36Sopenharmony_ci#define PLL2550XX_P_SHIFT 3 99462306a36Sopenharmony_ci#define PLL2550XX_S_SHIFT 0 99562306a36Sopenharmony_ci#define PLL2550XX_LOCK_STAT_SHIFT 21 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_cistatic unsigned long samsung_pll2550xx_recalc_rate(struct clk_hw *hw, 99862306a36Sopenharmony_ci unsigned long parent_rate) 99962306a36Sopenharmony_ci{ 100062306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 100162306a36Sopenharmony_ci u32 mdiv, pdiv, sdiv, pll_con; 100262306a36Sopenharmony_ci u64 fvco = parent_rate; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci pll_con = readl_relaxed(pll->con_reg); 100562306a36Sopenharmony_ci mdiv = (pll_con >> PLL2550XX_M_SHIFT) & PLL2550XX_M_MASK; 100662306a36Sopenharmony_ci pdiv = (pll_con >> PLL2550XX_P_SHIFT) & PLL2550XX_P_MASK; 100762306a36Sopenharmony_ci sdiv = (pll_con >> PLL2550XX_S_SHIFT) & PLL2550XX_S_MASK; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci fvco *= mdiv; 101062306a36Sopenharmony_ci do_div(fvco, (pdiv << sdiv)); 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci return (unsigned long)fvco; 101362306a36Sopenharmony_ci} 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_cistatic inline bool samsung_pll2550xx_mp_change(u32 mdiv, u32 pdiv, u32 pll_con) 101662306a36Sopenharmony_ci{ 101762306a36Sopenharmony_ci u32 old_mdiv, old_pdiv; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci old_mdiv = (pll_con >> PLL2550XX_M_SHIFT) & PLL2550XX_M_MASK; 102062306a36Sopenharmony_ci old_pdiv = (pll_con >> PLL2550XX_P_SHIFT) & PLL2550XX_P_MASK; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci return mdiv != old_mdiv || pdiv != old_pdiv; 102362306a36Sopenharmony_ci} 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_cistatic int samsung_pll2550xx_set_rate(struct clk_hw *hw, unsigned long drate, 102662306a36Sopenharmony_ci unsigned long prate) 102762306a36Sopenharmony_ci{ 102862306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 102962306a36Sopenharmony_ci const struct samsung_pll_rate_table *rate; 103062306a36Sopenharmony_ci u32 tmp; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci /* Get required rate settings from table */ 103362306a36Sopenharmony_ci rate = samsung_get_pll_settings(pll, drate); 103462306a36Sopenharmony_ci if (!rate) { 103562306a36Sopenharmony_ci pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, 103662306a36Sopenharmony_ci drate, clk_hw_get_name(hw)); 103762306a36Sopenharmony_ci return -EINVAL; 103862306a36Sopenharmony_ci } 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci tmp = readl_relaxed(pll->con_reg); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci if (!(samsung_pll2550xx_mp_change(rate->mdiv, rate->pdiv, tmp))) { 104362306a36Sopenharmony_ci /* If only s change, change just s value only*/ 104462306a36Sopenharmony_ci tmp &= ~(PLL2550XX_S_MASK << PLL2550XX_S_SHIFT); 104562306a36Sopenharmony_ci tmp |= rate->sdiv << PLL2550XX_S_SHIFT; 104662306a36Sopenharmony_ci writel_relaxed(tmp, pll->con_reg); 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci return 0; 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci /* Set PLL lock time. */ 105262306a36Sopenharmony_ci writel_relaxed(rate->pdiv * PLL2550XX_LOCK_FACTOR, pll->lock_reg); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci /* Change PLL PMS values */ 105562306a36Sopenharmony_ci tmp &= ~((PLL2550XX_M_MASK << PLL2550XX_M_SHIFT) | 105662306a36Sopenharmony_ci (PLL2550XX_P_MASK << PLL2550XX_P_SHIFT) | 105762306a36Sopenharmony_ci (PLL2550XX_S_MASK << PLL2550XX_S_SHIFT)); 105862306a36Sopenharmony_ci tmp |= (rate->mdiv << PLL2550XX_M_SHIFT) | 105962306a36Sopenharmony_ci (rate->pdiv << PLL2550XX_P_SHIFT) | 106062306a36Sopenharmony_ci (rate->sdiv << PLL2550XX_S_SHIFT); 106162306a36Sopenharmony_ci writel_relaxed(tmp, pll->con_reg); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci /* Wait for PLL lock */ 106462306a36Sopenharmony_ci return samsung_pll_lock_wait(pll, 106562306a36Sopenharmony_ci PLL2550XX_LOCK_STAT_MASK << PLL2550XX_LOCK_STAT_SHIFT); 106662306a36Sopenharmony_ci} 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_cistatic const struct clk_ops samsung_pll2550xx_clk_ops = { 106962306a36Sopenharmony_ci .recalc_rate = samsung_pll2550xx_recalc_rate, 107062306a36Sopenharmony_ci .round_rate = samsung_pll_round_rate, 107162306a36Sopenharmony_ci .set_rate = samsung_pll2550xx_set_rate, 107262306a36Sopenharmony_ci}; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_cistatic const struct clk_ops samsung_pll2550xx_clk_min_ops = { 107562306a36Sopenharmony_ci .recalc_rate = samsung_pll2550xx_recalc_rate, 107662306a36Sopenharmony_ci}; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci/* 107962306a36Sopenharmony_ci * PLL2650x Clock Type 108062306a36Sopenharmony_ci */ 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci/* Maximum lock time can be 3000 * PDIV cycles */ 108362306a36Sopenharmony_ci#define PLL2650X_LOCK_FACTOR 3000 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci#define PLL2650X_M_MASK 0x1ff 108662306a36Sopenharmony_ci#define PLL2650X_P_MASK 0x3f 108762306a36Sopenharmony_ci#define PLL2650X_S_MASK 0x7 108862306a36Sopenharmony_ci#define PLL2650X_K_MASK 0xffff 108962306a36Sopenharmony_ci#define PLL2650X_LOCK_STAT_MASK 0x1 109062306a36Sopenharmony_ci#define PLL2650X_M_SHIFT 16 109162306a36Sopenharmony_ci#define PLL2650X_P_SHIFT 8 109262306a36Sopenharmony_ci#define PLL2650X_S_SHIFT 0 109362306a36Sopenharmony_ci#define PLL2650X_K_SHIFT 0 109462306a36Sopenharmony_ci#define PLL2650X_LOCK_STAT_SHIFT 29 109562306a36Sopenharmony_ci#define PLL2650X_PLL_ENABLE_SHIFT 31 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_cistatic unsigned long samsung_pll2650x_recalc_rate(struct clk_hw *hw, 109862306a36Sopenharmony_ci unsigned long parent_rate) 109962306a36Sopenharmony_ci{ 110062306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 110162306a36Sopenharmony_ci u64 fout = parent_rate; 110262306a36Sopenharmony_ci u32 mdiv, pdiv, sdiv, pll_con0, pll_con1; 110362306a36Sopenharmony_ci s16 kdiv; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci pll_con0 = readl_relaxed(pll->con_reg); 110662306a36Sopenharmony_ci mdiv = (pll_con0 >> PLL2650X_M_SHIFT) & PLL2650X_M_MASK; 110762306a36Sopenharmony_ci pdiv = (pll_con0 >> PLL2650X_P_SHIFT) & PLL2650X_P_MASK; 110862306a36Sopenharmony_ci sdiv = (pll_con0 >> PLL2650X_S_SHIFT) & PLL2650X_S_MASK; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci pll_con1 = readl_relaxed(pll->con_reg + 4); 111162306a36Sopenharmony_ci kdiv = (s16)((pll_con1 >> PLL2650X_K_SHIFT) & PLL2650X_K_MASK); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci fout *= (mdiv << 16) + kdiv; 111462306a36Sopenharmony_ci do_div(fout, (pdiv << sdiv)); 111562306a36Sopenharmony_ci fout >>= 16; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci return (unsigned long)fout; 111862306a36Sopenharmony_ci} 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_cistatic int samsung_pll2650x_set_rate(struct clk_hw *hw, unsigned long drate, 112162306a36Sopenharmony_ci unsigned long prate) 112262306a36Sopenharmony_ci{ 112362306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 112462306a36Sopenharmony_ci const struct samsung_pll_rate_table *rate; 112562306a36Sopenharmony_ci u32 con0, con1; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci /* Get required rate settings from table */ 112862306a36Sopenharmony_ci rate = samsung_get_pll_settings(pll, drate); 112962306a36Sopenharmony_ci if (!rate) { 113062306a36Sopenharmony_ci pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, 113162306a36Sopenharmony_ci drate, clk_hw_get_name(hw)); 113262306a36Sopenharmony_ci return -EINVAL; 113362306a36Sopenharmony_ci } 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci con0 = readl_relaxed(pll->con_reg); 113662306a36Sopenharmony_ci con1 = readl_relaxed(pll->con_reg + 4); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci /* Set PLL lock time. */ 113962306a36Sopenharmony_ci writel_relaxed(rate->pdiv * PLL2650X_LOCK_FACTOR, pll->lock_reg); 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci /* Change PLL PMS values */ 114262306a36Sopenharmony_ci con0 &= ~((PLL2650X_M_MASK << PLL2650X_M_SHIFT) | 114362306a36Sopenharmony_ci (PLL2650X_P_MASK << PLL2650X_P_SHIFT) | 114462306a36Sopenharmony_ci (PLL2650X_S_MASK << PLL2650X_S_SHIFT)); 114562306a36Sopenharmony_ci con0 |= (rate->mdiv << PLL2650X_M_SHIFT) | 114662306a36Sopenharmony_ci (rate->pdiv << PLL2650X_P_SHIFT) | 114762306a36Sopenharmony_ci (rate->sdiv << PLL2650X_S_SHIFT); 114862306a36Sopenharmony_ci con0 |= (1 << PLL2650X_PLL_ENABLE_SHIFT); 114962306a36Sopenharmony_ci writel_relaxed(con0, pll->con_reg); 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci con1 &= ~(PLL2650X_K_MASK << PLL2650X_K_SHIFT); 115262306a36Sopenharmony_ci con1 |= ((rate->kdiv & PLL2650X_K_MASK) << PLL2650X_K_SHIFT); 115362306a36Sopenharmony_ci writel_relaxed(con1, pll->con_reg + 4); 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci /* Wait for PLL lock */ 115662306a36Sopenharmony_ci return samsung_pll_lock_wait(pll, 115762306a36Sopenharmony_ci PLL2650X_LOCK_STAT_MASK << PLL2650X_LOCK_STAT_SHIFT); 115862306a36Sopenharmony_ci} 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_cistatic const struct clk_ops samsung_pll2650x_clk_ops = { 116162306a36Sopenharmony_ci .recalc_rate = samsung_pll2650x_recalc_rate, 116262306a36Sopenharmony_ci .round_rate = samsung_pll_round_rate, 116362306a36Sopenharmony_ci .set_rate = samsung_pll2650x_set_rate, 116462306a36Sopenharmony_ci}; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_cistatic const struct clk_ops samsung_pll2650x_clk_min_ops = { 116762306a36Sopenharmony_ci .recalc_rate = samsung_pll2650x_recalc_rate, 116862306a36Sopenharmony_ci}; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci/* 117162306a36Sopenharmony_ci * PLL2650XX Clock Type 117262306a36Sopenharmony_ci */ 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci/* Maximum lock time can be 3000 * PDIV cycles */ 117562306a36Sopenharmony_ci#define PLL2650XX_LOCK_FACTOR 3000 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci#define PLL2650XX_MDIV_SHIFT 9 117862306a36Sopenharmony_ci#define PLL2650XX_PDIV_SHIFT 3 117962306a36Sopenharmony_ci#define PLL2650XX_SDIV_SHIFT 0 118062306a36Sopenharmony_ci#define PLL2650XX_KDIV_SHIFT 0 118162306a36Sopenharmony_ci#define PLL2650XX_MDIV_MASK 0x1ff 118262306a36Sopenharmony_ci#define PLL2650XX_PDIV_MASK 0x3f 118362306a36Sopenharmony_ci#define PLL2650XX_SDIV_MASK 0x7 118462306a36Sopenharmony_ci#define PLL2650XX_KDIV_MASK 0xffff 118562306a36Sopenharmony_ci#define PLL2650XX_PLL_ENABLE_SHIFT 23 118662306a36Sopenharmony_ci#define PLL2650XX_PLL_LOCKTIME_SHIFT 21 118762306a36Sopenharmony_ci#define PLL2650XX_PLL_FOUTMASK_SHIFT 31 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_cistatic unsigned long samsung_pll2650xx_recalc_rate(struct clk_hw *hw, 119062306a36Sopenharmony_ci unsigned long parent_rate) 119162306a36Sopenharmony_ci{ 119262306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 119362306a36Sopenharmony_ci u32 mdiv, pdiv, sdiv, pll_con0, pll_con2; 119462306a36Sopenharmony_ci s16 kdiv; 119562306a36Sopenharmony_ci u64 fvco = parent_rate; 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci pll_con0 = readl_relaxed(pll->con_reg); 119862306a36Sopenharmony_ci pll_con2 = readl_relaxed(pll->con_reg + 8); 119962306a36Sopenharmony_ci mdiv = (pll_con0 >> PLL2650XX_MDIV_SHIFT) & PLL2650XX_MDIV_MASK; 120062306a36Sopenharmony_ci pdiv = (pll_con0 >> PLL2650XX_PDIV_SHIFT) & PLL2650XX_PDIV_MASK; 120162306a36Sopenharmony_ci sdiv = (pll_con0 >> PLL2650XX_SDIV_SHIFT) & PLL2650XX_SDIV_MASK; 120262306a36Sopenharmony_ci kdiv = (s16)(pll_con2 & PLL2650XX_KDIV_MASK); 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci fvco *= (mdiv << 16) + kdiv; 120562306a36Sopenharmony_ci do_div(fvco, (pdiv << sdiv)); 120662306a36Sopenharmony_ci fvco >>= 16; 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci return (unsigned long)fvco; 120962306a36Sopenharmony_ci} 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_cistatic int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long drate, 121262306a36Sopenharmony_ci unsigned long parent_rate) 121362306a36Sopenharmony_ci{ 121462306a36Sopenharmony_ci struct samsung_clk_pll *pll = to_clk_pll(hw); 121562306a36Sopenharmony_ci u32 pll_con0, pll_con2; 121662306a36Sopenharmony_ci const struct samsung_pll_rate_table *rate; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci rate = samsung_get_pll_settings(pll, drate); 121962306a36Sopenharmony_ci if (!rate) { 122062306a36Sopenharmony_ci pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, 122162306a36Sopenharmony_ci drate, clk_hw_get_name(hw)); 122262306a36Sopenharmony_ci return -EINVAL; 122362306a36Sopenharmony_ci } 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci pll_con0 = readl_relaxed(pll->con_reg); 122662306a36Sopenharmony_ci pll_con2 = readl_relaxed(pll->con_reg + 8); 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci /* Change PLL PMS values */ 122962306a36Sopenharmony_ci pll_con0 &= ~(PLL2650XX_MDIV_MASK << PLL2650XX_MDIV_SHIFT | 123062306a36Sopenharmony_ci PLL2650XX_PDIV_MASK << PLL2650XX_PDIV_SHIFT | 123162306a36Sopenharmony_ci PLL2650XX_SDIV_MASK << PLL2650XX_SDIV_SHIFT); 123262306a36Sopenharmony_ci pll_con0 |= rate->mdiv << PLL2650XX_MDIV_SHIFT; 123362306a36Sopenharmony_ci pll_con0 |= rate->pdiv << PLL2650XX_PDIV_SHIFT; 123462306a36Sopenharmony_ci pll_con0 |= rate->sdiv << PLL2650XX_SDIV_SHIFT; 123562306a36Sopenharmony_ci pll_con0 |= 1 << PLL2650XX_PLL_ENABLE_SHIFT; 123662306a36Sopenharmony_ci pll_con0 |= 1 << PLL2650XX_PLL_FOUTMASK_SHIFT; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci pll_con2 &= ~(PLL2650XX_KDIV_MASK << PLL2650XX_KDIV_SHIFT); 123962306a36Sopenharmony_ci pll_con2 |= ((~(rate->kdiv) + 1) & PLL2650XX_KDIV_MASK) 124062306a36Sopenharmony_ci << PLL2650XX_KDIV_SHIFT; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci /* Set PLL lock time. */ 124362306a36Sopenharmony_ci writel_relaxed(PLL2650XX_LOCK_FACTOR * rate->pdiv, pll->lock_reg); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci writel_relaxed(pll_con0, pll->con_reg); 124662306a36Sopenharmony_ci writel_relaxed(pll_con2, pll->con_reg + 8); 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci return samsung_pll_lock_wait(pll, 0x1 << PLL2650XX_PLL_LOCKTIME_SHIFT); 124962306a36Sopenharmony_ci} 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_cistatic const struct clk_ops samsung_pll2650xx_clk_ops = { 125262306a36Sopenharmony_ci .recalc_rate = samsung_pll2650xx_recalc_rate, 125362306a36Sopenharmony_ci .set_rate = samsung_pll2650xx_set_rate, 125462306a36Sopenharmony_ci .round_rate = samsung_pll_round_rate, 125562306a36Sopenharmony_ci}; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_cistatic const struct clk_ops samsung_pll2650xx_clk_min_ops = { 125862306a36Sopenharmony_ci .recalc_rate = samsung_pll2650xx_recalc_rate, 125962306a36Sopenharmony_ci}; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_cistatic void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, 126262306a36Sopenharmony_ci const struct samsung_pll_clock *pll_clk) 126362306a36Sopenharmony_ci{ 126462306a36Sopenharmony_ci struct samsung_clk_pll *pll; 126562306a36Sopenharmony_ci struct clk_init_data init; 126662306a36Sopenharmony_ci int ret, len; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci pll = kzalloc(sizeof(*pll), GFP_KERNEL); 126962306a36Sopenharmony_ci if (!pll) { 127062306a36Sopenharmony_ci pr_err("%s: could not allocate pll clk %s\n", 127162306a36Sopenharmony_ci __func__, pll_clk->name); 127262306a36Sopenharmony_ci return; 127362306a36Sopenharmony_ci } 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci init.name = pll_clk->name; 127662306a36Sopenharmony_ci init.flags = pll_clk->flags; 127762306a36Sopenharmony_ci init.parent_names = &pll_clk->parent_name; 127862306a36Sopenharmony_ci init.num_parents = 1; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci if (pll_clk->rate_table) { 128162306a36Sopenharmony_ci /* find count of rates in rate_table */ 128262306a36Sopenharmony_ci for (len = 0; pll_clk->rate_table[len].rate != 0; ) 128362306a36Sopenharmony_ci len++; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci pll->rate_count = len; 128662306a36Sopenharmony_ci pll->rate_table = kmemdup(pll_clk->rate_table, 128762306a36Sopenharmony_ci pll->rate_count * 128862306a36Sopenharmony_ci sizeof(struct samsung_pll_rate_table), 128962306a36Sopenharmony_ci GFP_KERNEL); 129062306a36Sopenharmony_ci WARN(!pll->rate_table, 129162306a36Sopenharmony_ci "%s: could not allocate rate table for %s\n", 129262306a36Sopenharmony_ci __func__, pll_clk->name); 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci switch (pll_clk->type) { 129662306a36Sopenharmony_ci case pll_2126: 129762306a36Sopenharmony_ci init.ops = &samsung_pll2126_clk_ops; 129862306a36Sopenharmony_ci break; 129962306a36Sopenharmony_ci case pll_3000: 130062306a36Sopenharmony_ci init.ops = &samsung_pll3000_clk_ops; 130162306a36Sopenharmony_ci break; 130262306a36Sopenharmony_ci /* clk_ops for 35xx and 2550 are similar */ 130362306a36Sopenharmony_ci case pll_35xx: 130462306a36Sopenharmony_ci case pll_2550: 130562306a36Sopenharmony_ci case pll_1450x: 130662306a36Sopenharmony_ci case pll_1451x: 130762306a36Sopenharmony_ci case pll_1452x: 130862306a36Sopenharmony_ci case pll_142xx: 130962306a36Sopenharmony_ci pll->enable_offs = PLL35XX_ENABLE_SHIFT; 131062306a36Sopenharmony_ci pll->lock_offs = PLL35XX_LOCK_STAT_SHIFT; 131162306a36Sopenharmony_ci if (!pll->rate_table) 131262306a36Sopenharmony_ci init.ops = &samsung_pll35xx_clk_min_ops; 131362306a36Sopenharmony_ci else 131462306a36Sopenharmony_ci init.ops = &samsung_pll35xx_clk_ops; 131562306a36Sopenharmony_ci break; 131662306a36Sopenharmony_ci case pll_1417x: 131762306a36Sopenharmony_ci case pll_0818x: 131862306a36Sopenharmony_ci case pll_0822x: 131962306a36Sopenharmony_ci pll->enable_offs = PLL0822X_ENABLE_SHIFT; 132062306a36Sopenharmony_ci pll->lock_offs = PLL0822X_LOCK_STAT_SHIFT; 132162306a36Sopenharmony_ci if (!pll->rate_table) 132262306a36Sopenharmony_ci init.ops = &samsung_pll0822x_clk_min_ops; 132362306a36Sopenharmony_ci else 132462306a36Sopenharmony_ci init.ops = &samsung_pll0822x_clk_ops; 132562306a36Sopenharmony_ci break; 132662306a36Sopenharmony_ci case pll_4500: 132762306a36Sopenharmony_ci init.ops = &samsung_pll45xx_clk_min_ops; 132862306a36Sopenharmony_ci break; 132962306a36Sopenharmony_ci case pll_4502: 133062306a36Sopenharmony_ci case pll_4508: 133162306a36Sopenharmony_ci if (!pll->rate_table) 133262306a36Sopenharmony_ci init.ops = &samsung_pll45xx_clk_min_ops; 133362306a36Sopenharmony_ci else 133462306a36Sopenharmony_ci init.ops = &samsung_pll45xx_clk_ops; 133562306a36Sopenharmony_ci break; 133662306a36Sopenharmony_ci /* clk_ops for 36xx and 2650 are similar */ 133762306a36Sopenharmony_ci case pll_36xx: 133862306a36Sopenharmony_ci case pll_2650: 133962306a36Sopenharmony_ci pll->enable_offs = PLL36XX_ENABLE_SHIFT; 134062306a36Sopenharmony_ci pll->lock_offs = PLL36XX_LOCK_STAT_SHIFT; 134162306a36Sopenharmony_ci if (!pll->rate_table) 134262306a36Sopenharmony_ci init.ops = &samsung_pll36xx_clk_min_ops; 134362306a36Sopenharmony_ci else 134462306a36Sopenharmony_ci init.ops = &samsung_pll36xx_clk_ops; 134562306a36Sopenharmony_ci break; 134662306a36Sopenharmony_ci case pll_0831x: 134762306a36Sopenharmony_ci pll->enable_offs = PLL0831X_ENABLE_SHIFT; 134862306a36Sopenharmony_ci pll->lock_offs = PLL0831X_LOCK_STAT_SHIFT; 134962306a36Sopenharmony_ci if (!pll->rate_table) 135062306a36Sopenharmony_ci init.ops = &samsung_pll0831x_clk_min_ops; 135162306a36Sopenharmony_ci else 135262306a36Sopenharmony_ci init.ops = &samsung_pll0831x_clk_ops; 135362306a36Sopenharmony_ci break; 135462306a36Sopenharmony_ci case pll_6552: 135562306a36Sopenharmony_ci case pll_6552_s3c2416: 135662306a36Sopenharmony_ci init.ops = &samsung_pll6552_clk_ops; 135762306a36Sopenharmony_ci break; 135862306a36Sopenharmony_ci case pll_6553: 135962306a36Sopenharmony_ci init.ops = &samsung_pll6553_clk_ops; 136062306a36Sopenharmony_ci break; 136162306a36Sopenharmony_ci case pll_4600: 136262306a36Sopenharmony_ci case pll_4650: 136362306a36Sopenharmony_ci case pll_4650c: 136462306a36Sopenharmony_ci case pll_1460x: 136562306a36Sopenharmony_ci if (!pll->rate_table) 136662306a36Sopenharmony_ci init.ops = &samsung_pll46xx_clk_min_ops; 136762306a36Sopenharmony_ci else 136862306a36Sopenharmony_ci init.ops = &samsung_pll46xx_clk_ops; 136962306a36Sopenharmony_ci break; 137062306a36Sopenharmony_ci case pll_2550x: 137162306a36Sopenharmony_ci init.ops = &samsung_pll2550x_clk_ops; 137262306a36Sopenharmony_ci break; 137362306a36Sopenharmony_ci case pll_2550xx: 137462306a36Sopenharmony_ci if (!pll->rate_table) 137562306a36Sopenharmony_ci init.ops = &samsung_pll2550xx_clk_min_ops; 137662306a36Sopenharmony_ci else 137762306a36Sopenharmony_ci init.ops = &samsung_pll2550xx_clk_ops; 137862306a36Sopenharmony_ci break; 137962306a36Sopenharmony_ci case pll_2650x: 138062306a36Sopenharmony_ci if (!pll->rate_table) 138162306a36Sopenharmony_ci init.ops = &samsung_pll2650x_clk_min_ops; 138262306a36Sopenharmony_ci else 138362306a36Sopenharmony_ci init.ops = &samsung_pll2650x_clk_ops; 138462306a36Sopenharmony_ci break; 138562306a36Sopenharmony_ci case pll_2650xx: 138662306a36Sopenharmony_ci if (!pll->rate_table) 138762306a36Sopenharmony_ci init.ops = &samsung_pll2650xx_clk_min_ops; 138862306a36Sopenharmony_ci else 138962306a36Sopenharmony_ci init.ops = &samsung_pll2650xx_clk_ops; 139062306a36Sopenharmony_ci break; 139162306a36Sopenharmony_ci default: 139262306a36Sopenharmony_ci pr_warn("%s: Unknown pll type for pll clk %s\n", 139362306a36Sopenharmony_ci __func__, pll_clk->name); 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci pll->hw.init = &init; 139762306a36Sopenharmony_ci pll->type = pll_clk->type; 139862306a36Sopenharmony_ci pll->lock_reg = ctx->reg_base + pll_clk->lock_offset; 139962306a36Sopenharmony_ci pll->con_reg = ctx->reg_base + pll_clk->con_offset; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci ret = clk_hw_register(ctx->dev, &pll->hw); 140262306a36Sopenharmony_ci if (ret) { 140362306a36Sopenharmony_ci pr_err("%s: failed to register pll clock %s : %d\n", 140462306a36Sopenharmony_ci __func__, pll_clk->name, ret); 140562306a36Sopenharmony_ci kfree(pll->rate_table); 140662306a36Sopenharmony_ci kfree(pll); 140762306a36Sopenharmony_ci return; 140862306a36Sopenharmony_ci } 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci samsung_clk_add_lookup(ctx, &pll->hw, pll_clk->id); 141162306a36Sopenharmony_ci} 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_civoid __init samsung_clk_register_pll(struct samsung_clk_provider *ctx, 141462306a36Sopenharmony_ci const struct samsung_pll_clock *pll_list, 141562306a36Sopenharmony_ci unsigned int nr_pll) 141662306a36Sopenharmony_ci{ 141762306a36Sopenharmony_ci int cnt; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci for (cnt = 0; cnt < nr_pll; cnt++) 142062306a36Sopenharmony_ci _samsung_clk_register_pll(ctx, &pll_list[cnt]); 142162306a36Sopenharmony_ci} 1422