162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Toshiba Visconti PLL driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2021 TOSHIBA CORPORATION 662306a36Sopenharmony_ci * Copyright (c) 2021 Toshiba Electronic Devices & Storage Corporation 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/bitfield.h> 1262306a36Sopenharmony_ci#include <linux/clk-provider.h> 1362306a36Sopenharmony_ci#include <linux/delay.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/io.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "pll.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistruct visconti_pll { 2062306a36Sopenharmony_ci struct clk_hw hw; 2162306a36Sopenharmony_ci void __iomem *pll_base; 2262306a36Sopenharmony_ci spinlock_t *lock; 2362306a36Sopenharmony_ci unsigned long flags; 2462306a36Sopenharmony_ci const struct visconti_pll_rate_table *rate_table; 2562306a36Sopenharmony_ci size_t rate_count; 2662306a36Sopenharmony_ci struct visconti_pll_provider *ctx; 2762306a36Sopenharmony_ci}; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define PLL_CONF_REG 0x0000 3062306a36Sopenharmony_ci#define PLL_CTRL_REG 0x0004 3162306a36Sopenharmony_ci#define PLL_FRACMODE_REG 0x0010 3262306a36Sopenharmony_ci#define PLL_INTIN_REG 0x0014 3362306a36Sopenharmony_ci#define PLL_FRACIN_REG 0x0018 3462306a36Sopenharmony_ci#define PLL_REFDIV_REG 0x001c 3562306a36Sopenharmony_ci#define PLL_POSTDIV_REG 0x0020 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define PLL_CONFIG_SEL BIT(0) 3862306a36Sopenharmony_ci#define PLL_PLLEN BIT(4) 3962306a36Sopenharmony_ci#define PLL_BYPASS BIT(16) 4062306a36Sopenharmony_ci#define PLL_INTIN_MASK GENMASK(11, 0) 4162306a36Sopenharmony_ci#define PLL_FRACIN_MASK GENMASK(23, 0) 4262306a36Sopenharmony_ci#define PLL_REFDIV_MASK GENMASK(5, 0) 4362306a36Sopenharmony_ci#define PLL_POSTDIV_MASK GENMASK(2, 0) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define PLL0_FRACMODE_DACEN BIT(4) 4662306a36Sopenharmony_ci#define PLL0_FRACMODE_DSMEN BIT(0) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define PLL_CREATE_FRACMODE(table) (table->dacen << 4 | table->dsmen) 4962306a36Sopenharmony_ci#define PLL_CREATE_OSTDIV(table) (table->postdiv2 << 4 | table->postdiv1) 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic inline struct visconti_pll *to_visconti_pll(struct clk_hw *hw) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci return container_of(hw, struct visconti_pll, hw); 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic void visconti_pll_get_params(struct visconti_pll *pll, 5762306a36Sopenharmony_ci struct visconti_pll_rate_table *rate_table) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci u32 postdiv, val; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci val = readl(pll->pll_base + PLL_FRACMODE_REG); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci rate_table->dacen = FIELD_GET(PLL0_FRACMODE_DACEN, val); 6462306a36Sopenharmony_ci rate_table->dsmen = FIELD_GET(PLL0_FRACMODE_DSMEN, val); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci rate_table->fracin = readl(pll->pll_base + PLL_FRACIN_REG) & PLL_FRACIN_MASK; 6762306a36Sopenharmony_ci rate_table->intin = readl(pll->pll_base + PLL_INTIN_REG) & PLL_INTIN_MASK; 6862306a36Sopenharmony_ci rate_table->refdiv = readl(pll->pll_base + PLL_REFDIV_REG) & PLL_REFDIV_MASK; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci postdiv = readl(pll->pll_base + PLL_POSTDIV_REG); 7162306a36Sopenharmony_ci rate_table->postdiv1 = postdiv & PLL_POSTDIV_MASK; 7262306a36Sopenharmony_ci rate_table->postdiv2 = (postdiv >> 4) & PLL_POSTDIV_MASK; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic const struct visconti_pll_rate_table *visconti_get_pll_settings(struct visconti_pll *pll, 7662306a36Sopenharmony_ci unsigned long rate) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci const struct visconti_pll_rate_table *rate_table = pll->rate_table; 7962306a36Sopenharmony_ci int i; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci for (i = 0; i < pll->rate_count; i++) 8262306a36Sopenharmony_ci if (rate == rate_table[i].rate) 8362306a36Sopenharmony_ci return &rate_table[i]; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci return NULL; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic unsigned long visconti_get_pll_rate_from_data(struct visconti_pll *pll, 8962306a36Sopenharmony_ci const struct visconti_pll_rate_table *rate) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci const struct visconti_pll_rate_table *rate_table = pll->rate_table; 9262306a36Sopenharmony_ci int i; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci for (i = 0; i < pll->rate_count; i++) 9562306a36Sopenharmony_ci if (memcmp(&rate_table[i].dacen, &rate->dacen, 9662306a36Sopenharmony_ci sizeof(*rate) - sizeof(unsigned long)) == 0) 9762306a36Sopenharmony_ci return rate_table[i].rate; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* set default */ 10062306a36Sopenharmony_ci return rate_table[0].rate; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic long visconti_pll_round_rate(struct clk_hw *hw, 10462306a36Sopenharmony_ci unsigned long rate, unsigned long *prate) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci struct visconti_pll *pll = to_visconti_pll(hw); 10762306a36Sopenharmony_ci const struct visconti_pll_rate_table *rate_table = pll->rate_table; 10862306a36Sopenharmony_ci int i; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* Assumming rate_table is in descending order */ 11162306a36Sopenharmony_ci for (i = 0; i < pll->rate_count; i++) 11262306a36Sopenharmony_ci if (rate >= rate_table[i].rate) 11362306a36Sopenharmony_ci return rate_table[i].rate; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* return minimum supported value */ 11662306a36Sopenharmony_ci return rate_table[i - 1].rate; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic unsigned long visconti_pll_recalc_rate(struct clk_hw *hw, 12062306a36Sopenharmony_ci unsigned long parent_rate) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct visconti_pll *pll = to_visconti_pll(hw); 12362306a36Sopenharmony_ci struct visconti_pll_rate_table rate_table; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci memset(&rate_table, 0, sizeof(rate_table)); 12662306a36Sopenharmony_ci visconti_pll_get_params(pll, &rate_table); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci return visconti_get_pll_rate_from_data(pll, &rate_table); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic int visconti_pll_set_params(struct visconti_pll *pll, 13262306a36Sopenharmony_ci const struct visconti_pll_rate_table *rate_table) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci writel(PLL_CREATE_FRACMODE(rate_table), pll->pll_base + PLL_FRACMODE_REG); 13562306a36Sopenharmony_ci writel(PLL_CREATE_OSTDIV(rate_table), pll->pll_base + PLL_POSTDIV_REG); 13662306a36Sopenharmony_ci writel(rate_table->intin, pll->pll_base + PLL_INTIN_REG); 13762306a36Sopenharmony_ci writel(rate_table->fracin, pll->pll_base + PLL_FRACIN_REG); 13862306a36Sopenharmony_ci writel(rate_table->refdiv, pll->pll_base + PLL_REFDIV_REG); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci return 0; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic int visconti_pll_set_rate(struct clk_hw *hw, unsigned long rate, 14462306a36Sopenharmony_ci unsigned long parent_rate) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci struct visconti_pll *pll = to_visconti_pll(hw); 14762306a36Sopenharmony_ci const struct visconti_pll_rate_table *rate_table; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci rate_table = visconti_get_pll_settings(pll, rate); 15062306a36Sopenharmony_ci if (!rate_table) 15162306a36Sopenharmony_ci return -EINVAL; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci return visconti_pll_set_params(pll, rate_table); 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic int visconti_pll_is_enabled(struct clk_hw *hw) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci struct visconti_pll *pll = to_visconti_pll(hw); 15962306a36Sopenharmony_ci u32 reg; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci reg = readl(pll->pll_base + PLL_CTRL_REG); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci return (reg & PLL_PLLEN); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic int visconti_pll_enable(struct clk_hw *hw) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct visconti_pll *pll = to_visconti_pll(hw); 16962306a36Sopenharmony_ci const struct visconti_pll_rate_table *rate_table = pll->rate_table; 17062306a36Sopenharmony_ci unsigned long flags; 17162306a36Sopenharmony_ci u32 reg; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (visconti_pll_is_enabled(hw)) 17462306a36Sopenharmony_ci return 0; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci spin_lock_irqsave(pll->lock, flags); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci writel(PLL_CONFIG_SEL, pll->pll_base + PLL_CONF_REG); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci reg = readl(pll->pll_base + PLL_CTRL_REG); 18162306a36Sopenharmony_ci reg |= PLL_BYPASS; 18262306a36Sopenharmony_ci writel(reg, pll->pll_base + PLL_CTRL_REG); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci visconti_pll_set_params(pll, &rate_table[0]); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci reg = readl(pll->pll_base + PLL_CTRL_REG); 18762306a36Sopenharmony_ci reg &= ~PLL_PLLEN; 18862306a36Sopenharmony_ci writel(reg, pll->pll_base + PLL_CTRL_REG); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci udelay(1); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci reg = readl(pll->pll_base + PLL_CTRL_REG); 19362306a36Sopenharmony_ci reg |= PLL_PLLEN; 19462306a36Sopenharmony_ci writel(reg, pll->pll_base + PLL_CTRL_REG); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci udelay(40); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci reg = readl(pll->pll_base + PLL_CTRL_REG); 19962306a36Sopenharmony_ci reg &= ~PLL_BYPASS; 20062306a36Sopenharmony_ci writel(reg, pll->pll_base + PLL_CTRL_REG); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci spin_unlock_irqrestore(pll->lock, flags); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci return 0; 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic void visconti_pll_disable(struct clk_hw *hw) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci struct visconti_pll *pll = to_visconti_pll(hw); 21062306a36Sopenharmony_ci unsigned long flags; 21162306a36Sopenharmony_ci u32 reg; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (!visconti_pll_is_enabled(hw)) 21462306a36Sopenharmony_ci return; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci spin_lock_irqsave(pll->lock, flags); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci writel(PLL_CONFIG_SEL, pll->pll_base + PLL_CONF_REG); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci reg = readl(pll->pll_base + PLL_CTRL_REG); 22162306a36Sopenharmony_ci reg |= PLL_BYPASS; 22262306a36Sopenharmony_ci writel(reg, pll->pll_base + PLL_CTRL_REG); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci reg = readl(pll->pll_base + PLL_CTRL_REG); 22562306a36Sopenharmony_ci reg &= ~PLL_PLLEN; 22662306a36Sopenharmony_ci writel(reg, pll->pll_base + PLL_CTRL_REG); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci spin_unlock_irqrestore(pll->lock, flags); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic const struct clk_ops visconti_pll_ops = { 23262306a36Sopenharmony_ci .enable = visconti_pll_enable, 23362306a36Sopenharmony_ci .disable = visconti_pll_disable, 23462306a36Sopenharmony_ci .is_enabled = visconti_pll_is_enabled, 23562306a36Sopenharmony_ci .round_rate = visconti_pll_round_rate, 23662306a36Sopenharmony_ci .recalc_rate = visconti_pll_recalc_rate, 23762306a36Sopenharmony_ci .set_rate = visconti_pll_set_rate, 23862306a36Sopenharmony_ci}; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic struct clk_hw *visconti_register_pll(struct visconti_pll_provider *ctx, 24162306a36Sopenharmony_ci const char *name, 24262306a36Sopenharmony_ci const char *parent_name, 24362306a36Sopenharmony_ci int offset, 24462306a36Sopenharmony_ci const struct visconti_pll_rate_table *rate_table, 24562306a36Sopenharmony_ci spinlock_t *lock) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci struct clk_init_data init; 24862306a36Sopenharmony_ci struct visconti_pll *pll; 24962306a36Sopenharmony_ci struct clk_hw *pll_hw_clk; 25062306a36Sopenharmony_ci size_t len; 25162306a36Sopenharmony_ci int ret; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci pll = kzalloc(sizeof(*pll), GFP_KERNEL); 25462306a36Sopenharmony_ci if (!pll) 25562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci init.name = name; 25862306a36Sopenharmony_ci init.flags = CLK_IGNORE_UNUSED; 25962306a36Sopenharmony_ci init.parent_names = &parent_name; 26062306a36Sopenharmony_ci init.num_parents = 1; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci for (len = 0; rate_table[len].rate != 0; ) 26362306a36Sopenharmony_ci len++; 26462306a36Sopenharmony_ci pll->rate_count = len; 26562306a36Sopenharmony_ci pll->rate_table = kmemdup(rate_table, 26662306a36Sopenharmony_ci pll->rate_count * sizeof(struct visconti_pll_rate_table), 26762306a36Sopenharmony_ci GFP_KERNEL); 26862306a36Sopenharmony_ci WARN(!pll->rate_table, "%s: could not allocate rate table for %s\n", __func__, name); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci init.ops = &visconti_pll_ops; 27162306a36Sopenharmony_ci pll->hw.init = &init; 27262306a36Sopenharmony_ci pll->pll_base = ctx->reg_base + offset; 27362306a36Sopenharmony_ci pll->lock = lock; 27462306a36Sopenharmony_ci pll->ctx = ctx; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci pll_hw_clk = &pll->hw; 27762306a36Sopenharmony_ci ret = clk_hw_register(NULL, &pll->hw); 27862306a36Sopenharmony_ci if (ret) { 27962306a36Sopenharmony_ci pr_err("failed to register pll clock %s : %d\n", name, ret); 28062306a36Sopenharmony_ci kfree(pll->rate_table); 28162306a36Sopenharmony_ci kfree(pll); 28262306a36Sopenharmony_ci pll_hw_clk = ERR_PTR(ret); 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci return pll_hw_clk; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic void visconti_pll_add_lookup(struct visconti_pll_provider *ctx, 28962306a36Sopenharmony_ci struct clk_hw *hw_clk, 29062306a36Sopenharmony_ci unsigned int id) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci if (id) 29362306a36Sopenharmony_ci ctx->clk_data.hws[id] = hw_clk; 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_civoid __init visconti_register_plls(struct visconti_pll_provider *ctx, 29762306a36Sopenharmony_ci const struct visconti_pll_info *list, 29862306a36Sopenharmony_ci unsigned int nr_plls, 29962306a36Sopenharmony_ci spinlock_t *lock) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci int idx; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci for (idx = 0; idx < nr_plls; idx++, list++) { 30462306a36Sopenharmony_ci struct clk_hw *clk; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci clk = visconti_register_pll(ctx, 30762306a36Sopenharmony_ci list->name, 30862306a36Sopenharmony_ci list->parent, 30962306a36Sopenharmony_ci list->base_reg, 31062306a36Sopenharmony_ci list->rate_table, 31162306a36Sopenharmony_ci lock); 31262306a36Sopenharmony_ci if (IS_ERR(clk)) { 31362306a36Sopenharmony_ci pr_err("failed to register clock %s\n", list->name); 31462306a36Sopenharmony_ci continue; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci visconti_pll_add_lookup(ctx, clk, list->id); 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistruct visconti_pll_provider * __init visconti_init_pll(struct device_node *np, 32262306a36Sopenharmony_ci void __iomem *base, 32362306a36Sopenharmony_ci unsigned long nr_plls) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct visconti_pll_provider *ctx; 32662306a36Sopenharmony_ci int i; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci ctx = kzalloc(struct_size(ctx, clk_data.hws, nr_plls), GFP_KERNEL); 32962306a36Sopenharmony_ci if (!ctx) 33062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci for (i = 0; i < nr_plls; ++i) 33362306a36Sopenharmony_ci ctx->clk_data.hws[i] = ERR_PTR(-ENOENT); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci ctx->node = np; 33662306a36Sopenharmony_ci ctx->reg_base = base; 33762306a36Sopenharmony_ci ctx->clk_data.num = nr_plls; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci return ctx; 34062306a36Sopenharmony_ci} 341