410 lines
9.7 KiB
C
410 lines
9.7 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2021, Artinchip Technology Co., Ltd
|
|
*/
|
|
#include <linux/clk.h>
|
|
#include <linux/clk-provider.h>
|
|
#include <linux/err.h>
|
|
#include <linux/io.h>
|
|
#include <linux/of.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/jiffies.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/delay.h>
|
|
#include "clk-aic.h"
|
|
|
|
#define PLL_LOCK_BIT (17)
|
|
#define PLL_EN_BIT (16)
|
|
|
|
#define PLL_FACTORN_BIT (8)
|
|
#define PLL_FACTORN_MASK (0xff)
|
|
#define PLL_FACTORN_MIN (14)
|
|
#define PLL_FACTORN_MAX (199)
|
|
|
|
#define PLL_FACTORM_BIT (4)
|
|
#define PLL_FACTORM_MASK (0x3)
|
|
#define PLL_FACTORM_MIN (0)
|
|
#define PLL_FACTORM_MAX (3)
|
|
#define PLL_FACTORM_EN_BIT (19)
|
|
|
|
#define PLL_FACTORP_BIT (0)
|
|
#define PLL_FACTORP_MASK (0x1)
|
|
#define PLL_FACTORP_MIN (0)
|
|
#define PLL_FACTORP_MAX (1)
|
|
|
|
#define PLL_DITHER_EN_BIT (24)
|
|
#define PLL_FRAC_EN_BIT (20)
|
|
#define PLL_FRAC_DIV_BIT (0)
|
|
#define PLL_FRAC_DIV_MASK (0x1ffff)
|
|
|
|
#define PLL_OUT_MUX (20)
|
|
#define PLL_OUT_SYS (18)
|
|
|
|
#define PLL_SDM_AMP_BIT (0)
|
|
#define PLL_SDM_FREQ_BIT (17)
|
|
#define PLL_SDM_STEP_BIT (20)
|
|
#define PLL_SDM_MODE_BIT (29)
|
|
#define PLL_SDM_EN_BIT (31)
|
|
|
|
#define PLL_SDM_AMP_MAX (0x20000)
|
|
#define PLL_SDM_SPREAD_PPM (10000)
|
|
#define PLL_SDM_SPREAD_FREQ (33000)
|
|
|
|
struct clk_pll {
|
|
struct clk_hw hw;
|
|
const char *name;
|
|
enum aic_pll_type type;
|
|
void __iomem *gen_reg;
|
|
void __iomem *fra_reg;
|
|
void __iomem *sdm_reg;
|
|
unsigned long min_rate;
|
|
unsigned long max_rate;
|
|
#ifdef CONFIG_DEBUG_ON_FPGA_BOARD_ARTINCHIP
|
|
unsigned long id;
|
|
#endif
|
|
};
|
|
|
|
/* ALL chips:
|
|
* Other vco of clock not change
|
|
* The vco of pll_fra2 range from (768M~1560M) to (360M~1584M)
|
|
*/
|
|
static const struct pll_vco vco_arr[] = {
|
|
{360000000, 1584000000, "pll_fra2"},
|
|
{768000000, 1560000000, "other"},
|
|
};
|
|
|
|
#define to_clk_pll(_hw) container_of(_hw, struct clk_pll, hw)
|
|
|
|
static int clk_pll_wait_lock(struct clk_pll *pll)
|
|
{
|
|
udelay(100);
|
|
return 0;
|
|
}
|
|
|
|
static void clk_pll_bypass(struct clk_pll *pll, bool bypass)
|
|
{
|
|
u32 val;
|
|
|
|
val = readl(pll->gen_reg);
|
|
val &= ~(1 << PLL_OUT_MUX);
|
|
val |= (!bypass << PLL_OUT_MUX);
|
|
writel(val, pll->gen_reg);
|
|
}
|
|
|
|
static int clk_pll_prepare(struct clk_hw *hw)
|
|
{
|
|
struct clk_pll *pll = to_clk_pll(hw);
|
|
u32 val;
|
|
|
|
val = readl(pll->gen_reg);
|
|
val |= (1 << PLL_OUT_SYS | 1 << PLL_EN_BIT);
|
|
writel(val, pll->gen_reg);
|
|
|
|
return clk_pll_wait_lock(pll);
|
|
}
|
|
|
|
static void clk_pll_unprepare(struct clk_hw *hw)
|
|
{
|
|
struct clk_pll *pll = to_clk_pll(hw);
|
|
u32 val;
|
|
|
|
val = readl(pll->gen_reg);
|
|
val &= ~(1 << PLL_OUT_SYS | 1 << PLL_EN_BIT);
|
|
writel(val, pll->gen_reg);
|
|
}
|
|
|
|
static int clk_pll_is_prepared(struct clk_hw *hw)
|
|
{
|
|
struct clk_pll *pll = to_clk_pll(hw);
|
|
u32 reg_val = readl(pll->gen_reg);
|
|
|
|
if ((reg_val & (1 << PLL_EN_BIT)) &&
|
|
(reg_val & (1 << PLL_OUT_SYS)))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void clk_vco_select(struct clk_pll *pll,
|
|
unsigned long *min, unsigned long *max)
|
|
{
|
|
int i;
|
|
const struct pll_vco *vco;
|
|
|
|
for (i = 0; i < (ARRAY_SIZE(vco_arr) - 1); i++) {
|
|
vco = &vco_arr[i];
|
|
if (strcmp(vco->name, pll->name) == 0) {
|
|
*min = vco->vco_min;
|
|
*max = vco->vco_max;
|
|
return;
|
|
}
|
|
}
|
|
*max = vco_arr[ARRAY_SIZE(vco_arr) - 1].vco_max;
|
|
*min = vco_arr[ARRAY_SIZE(vco_arr) - 1].vco_min;
|
|
}
|
|
|
|
static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
|
|
unsigned long parent_rate)
|
|
{
|
|
struct clk_pll *pll = to_clk_pll(hw);
|
|
u32 factor_n, factor_m, factor_p, fra_in;
|
|
u64 rate, rate_int, rate_fra;
|
|
u8 fra_en = 0;
|
|
|
|
/* PLL output mux is CLK_24M */
|
|
if (!((readl(pll->gen_reg) >> PLL_OUT_MUX) & 0x1))
|
|
return 24000000;
|
|
|
|
factor_n = (readl(pll->gen_reg) >> PLL_FACTORN_BIT) & PLL_FACTORN_MASK;
|
|
factor_m = (readl(pll->gen_reg) >> PLL_FACTORM_BIT) & PLL_FACTORM_MASK;
|
|
factor_p = (readl(pll->gen_reg) >> PLL_FACTORP_BIT) & PLL_FACTORP_MASK;
|
|
if (pll->type == AIC_PLL_FRA)
|
|
fra_en = (readl(pll->fra_reg) >> PLL_FRAC_EN_BIT) & 0x1;
|
|
|
|
if (pll->type != AIC_PLL_FRA || !fra_en)
|
|
rate = parent_rate / (factor_p + 1) *
|
|
(factor_n + 1) / (factor_m + 1);
|
|
else {
|
|
fra_in = readl(pll->fra_reg) & PLL_FRAC_DIV_MASK;
|
|
rate_int = parent_rate / (factor_p + 1) *
|
|
(factor_n + 1) / (factor_m + 1);
|
|
rate_fra = (u64)parent_rate / (factor_p + 1) * fra_in;
|
|
do_div(rate_fra, PLL_FRAC_DIV_MASK * (factor_m + 1));
|
|
rate = rate_int + rate_fra;
|
|
}
|
|
#ifdef CONFIG_DEBUG_ON_FPGA_BOARD_ARTINCHIP
|
|
rate = fpga_board_rate[pll->id];
|
|
#endif
|
|
return rate;
|
|
}
|
|
|
|
static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
|
unsigned long *prate)
|
|
{
|
|
struct clk_pll *pll = to_clk_pll(hw);
|
|
u32 factor_n, factor_m, factor_p;
|
|
long rrate, vco_rate;
|
|
unsigned long pll_vco_min, pll_vco_max;
|
|
unsigned long parent_rate = *prate;
|
|
|
|
clk_vco_select(pll, &pll_vco_min, &pll_vco_max);
|
|
|
|
if (pll->type != AIC_PLL_INT) {
|
|
if (rate < pll->min_rate)
|
|
return pll->min_rate;
|
|
else if (pll->max_rate && rate > pll->max_rate)
|
|
return pll->max_rate;
|
|
else if (pll->type == AIC_PLL_FRA)
|
|
return rate;
|
|
}
|
|
|
|
/* The frequency constraint of PLL_VCO is between 768M and 1560M
|
|
* But the PLL_VCO of pll_fra2 is between 360M and 1584M
|
|
*/
|
|
if (rate < pll_vco_min)
|
|
factor_m = DIV_ROUND_UP(pll_vco_min, rate) - 1;
|
|
else
|
|
factor_m = 0;
|
|
|
|
if (factor_m > PLL_FACTORM_MASK)
|
|
factor_m = PLL_FACTORM_MASK;
|
|
|
|
vco_rate = (factor_m + 1) * rate;
|
|
if (vco_rate > pll_vco_max)
|
|
vco_rate = pll_vco_max;
|
|
|
|
factor_p = (vco_rate % parent_rate) ? 1 : 0;
|
|
if (!factor_p)
|
|
return rate;
|
|
else if (!(vco_rate % (parent_rate / (factor_p + 1))))
|
|
return rate;
|
|
|
|
factor_n = vco_rate / parent_rate * (factor_p + 1) - 1;
|
|
|
|
rrate = parent_rate / (factor_p + 1) * (factor_n + 1) / (factor_m + 1);
|
|
|
|
#ifdef CONFIG_DEBUG_ON_FPGA_BOARD_ARTINCHIP
|
|
rrate = fpga_board_rate[pll->id];
|
|
#endif
|
|
return rrate;
|
|
}
|
|
|
|
static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
|
unsigned long parent_rate)
|
|
{
|
|
u32 factor_n, factor_m, factor_p, reg_val;
|
|
u64 val, fra_in = 0;
|
|
u8 fra_en, factor_m_en;
|
|
unsigned long vco_rate, pll_vco_min, pll_vco_max;
|
|
u32 ppm_max, sdm_amp, sdm_en = 0;
|
|
u64 sdm_step;
|
|
struct clk_pll *pll = to_clk_pll(hw);
|
|
|
|
clk_vco_select(pll, &pll_vco_min, &pll_vco_max);
|
|
|
|
if (rate == 24000000) {
|
|
val = readl(pll->gen_reg);
|
|
val &= ~(1 << PLL_OUT_MUX);
|
|
writel(val, pll->gen_reg);
|
|
return 0;
|
|
}
|
|
|
|
/* Switch the output of PLL to 24MHz */
|
|
clk_pll_bypass(pll, true);
|
|
/* Calculate PLL parameters.
|
|
* The frequency constraint of PLL_VCO is between 768M and 1560M
|
|
* But the PLL_VCO of pll_fra2 is between 360M and 1584M
|
|
*/
|
|
if (rate < pll_vco_min)
|
|
factor_m = DIV_ROUND_UP(pll_vco_min, rate) - 1;
|
|
else
|
|
factor_m = 0;
|
|
|
|
if (factor_m > PLL_FACTORM_MASK)
|
|
factor_m = PLL_FACTORM_MASK;
|
|
|
|
if (factor_m)
|
|
factor_m_en = 1;
|
|
else
|
|
factor_m_en = 0;
|
|
|
|
vco_rate = (factor_m + 1) * rate;
|
|
if (vco_rate > pll_vco_max)
|
|
vco_rate = pll_vco_max;
|
|
|
|
factor_p = (vco_rate % parent_rate) ? 1 : 0;
|
|
factor_n = vco_rate * (factor_p + 1) / parent_rate - 1;
|
|
|
|
reg_val = readl(pll->gen_reg);
|
|
reg_val &= ~0xFFFF;
|
|
reg_val |= (factor_m_en << PLL_FACTORM_EN_BIT) |
|
|
(factor_n << PLL_FACTORN_BIT) |
|
|
(factor_m << PLL_FACTORM_BIT) |
|
|
(factor_p << PLL_FACTORP_BIT);
|
|
writel(reg_val, pll->gen_reg);
|
|
|
|
if (pll->type == AIC_PLL_FRA) {
|
|
val = rate % (parent_rate * (factor_n + 1) /
|
|
(factor_m + 1) / (factor_p + 1));
|
|
fra_en = val ? 1 : 0;
|
|
if (fra_en) {
|
|
fra_in = val * (factor_p + 1) *
|
|
(factor_m + 1) * PLL_FRAC_DIV_MASK;
|
|
do_div(fra_in, parent_rate);
|
|
}
|
|
/* Configure fractional division */
|
|
writel(fra_en << PLL_FRAC_EN_BIT | fra_in, pll->fra_reg);
|
|
/* when using decimal divsion, do not configure spreading parameters */
|
|
sdm_en = (1UL << PLL_SDM_EN_BIT) | (2UL << PLL_SDM_MODE_BIT);
|
|
writel(sdm_en, pll->sdm_reg);
|
|
}
|
|
|
|
if (pll->type == AIC_PLL_SDM) {
|
|
sdm_en = readl(pll->sdm_reg);
|
|
sdm_en >>= 31;
|
|
|
|
if (sdm_en) {
|
|
ppm_max = 1000000 / (factor_n + 1);
|
|
/* 1% spread */
|
|
if (ppm_max < PLL_SDM_SPREAD_PPM)
|
|
sdm_amp = 0;
|
|
else
|
|
sdm_amp = PLL_SDM_AMP_MAX -
|
|
PLL_SDM_SPREAD_PPM *
|
|
PLL_SDM_AMP_MAX / ppm_max;
|
|
|
|
/* SDM uses triangular wave, 33KHz by default */
|
|
sdm_step = (PLL_SDM_AMP_MAX - sdm_amp) * 2 *
|
|
PLL_SDM_SPREAD_FREQ;
|
|
do_div(sdm_step, parent_rate);
|
|
if (sdm_step > 511)
|
|
sdm_step = 511;
|
|
|
|
reg_val = (1UL << PLL_SDM_EN_BIT) |
|
|
(2 << PLL_SDM_MODE_BIT) |
|
|
(sdm_step << PLL_SDM_STEP_BIT) |
|
|
(3 << PLL_SDM_FREQ_BIT) |
|
|
(sdm_amp << PLL_SDM_AMP_BIT);
|
|
|
|
writel(reg_val, pll->sdm_reg);
|
|
}
|
|
}
|
|
|
|
if (!clk_pll_wait_lock(pll))
|
|
clk_pll_bypass(pll, false);
|
|
else {
|
|
pr_err("%s not lock\n", pll->name);
|
|
return -EAGAIN;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct clk_ops clk_pll_ops = {
|
|
.prepare = clk_pll_prepare,
|
|
.unprepare = clk_pll_unprepare,
|
|
.is_prepared = clk_pll_is_prepared,
|
|
.recalc_rate = clk_pll_recalc_rate,
|
|
.round_rate = clk_pll_round_rate,
|
|
.set_rate = clk_pll_set_rate,
|
|
};
|
|
|
|
struct clk_hw *aic_clk_hw_pll(void __iomem *base, const struct pll_clk_cfg *cfg)
|
|
{
|
|
struct clk_init_data init;
|
|
struct clk_pll *pll;
|
|
struct clk_hw *hw;
|
|
int ret;
|
|
|
|
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
|
|
if (!pll)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
switch (cfg->type) {
|
|
case AIC_PLL_INT:
|
|
pll->fra_reg = 0;
|
|
pll->sdm_reg = 0;
|
|
break;
|
|
case AIC_PLL_FRA:
|
|
pll->fra_reg = base + cfg->offset_fra;
|
|
pll->sdm_reg = base + cfg->offset_sdm;
|
|
break;
|
|
case AIC_PLL_SDM:
|
|
pll->sdm_reg = base + cfg->offset_sdm;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
pll->gen_reg = base + cfg->offset_gen;
|
|
pll->name = cfg->name;
|
|
pll->type = cfg->type;
|
|
#ifdef CONFIG_DEBUG_ON_FPGA_BOARD_ARTINCHIP
|
|
pll->id = cfg->id;
|
|
#endif
|
|
pll->min_rate = cfg->min_rate;
|
|
pll->max_rate = cfg->max_rate;
|
|
|
|
init.name = cfg->name;
|
|
init.ops = &clk_pll_ops;
|
|
init.flags = cfg->flags;
|
|
init.parent_names = cfg->parent_names;
|
|
init.num_parents = cfg->num_parents;
|
|
|
|
pll->hw.init = &init;
|
|
hw = &pll->hw;
|
|
|
|
ret = clk_hw_register(NULL, hw);
|
|
if (ret) {
|
|
kfree(pll);
|
|
return ERR_PTR(ret);
|
|
}
|
|
|
|
if (pll->min_rate || pll->max_rate)
|
|
clk_hw_set_rate_range(hw, pll->min_rate, pll->max_rate);
|
|
|
|
return hw;
|
|
}
|