mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 01:53:29 +02:00
clk: thead: th1520-ap: Support setting PLL rates
TH1520 ships several PLLs that could operate in either integer or fractional mode. However, the TRM only lists a few configuration whose stability is considered guaranteed. Add a table-lookup rate determination logic to support PLL rate setting, and fill up frequency-configuration tables for AP-subsystem PLLs. Reviewed-by: Drew Fustini <fustini@kernel.org> Signed-off-by: Yao Zi <ziyao@disroot.org> Signed-off-by: Drew Fustini <fustini@kernel.org>
This commit is contained in:
parent
b436f8a82a
commit
238cc6316a
|
|
@ -22,6 +22,7 @@
|
|||
#define TH1520_PLL_REFDIV GENMASK(5, 0)
|
||||
#define TH1520_PLL_BYPASS BIT(30)
|
||||
#define TH1520_PLL_VCO_RST BIT(29)
|
||||
#define TH1520_PLL_DACPD BIT(25)
|
||||
#define TH1520_PLL_DSMPD BIT(24)
|
||||
#define TH1520_PLL_FRAC GENMASK(23, 0)
|
||||
#define TH1520_PLL_FRAC_BITS 24
|
||||
|
|
@ -72,9 +73,19 @@ struct ccu_div {
|
|||
struct ccu_common common;
|
||||
};
|
||||
|
||||
struct ccu_pll_cfg {
|
||||
unsigned long freq;
|
||||
u32 fbdiv;
|
||||
u32 frac;
|
||||
u32 postdiv1;
|
||||
u32 postdiv2;
|
||||
};
|
||||
|
||||
struct ccu_pll {
|
||||
struct ccu_common common;
|
||||
u32 lock_sts_mask;
|
||||
int cfgnum;
|
||||
const struct ccu_pll_cfg *cfgs;
|
||||
};
|
||||
|
||||
#define TH_CCU_ARG(_shift, _width) \
|
||||
|
|
@ -391,17 +402,102 @@ static unsigned long ccu_pll_recalc_rate(struct clk_hw *hw,
|
|||
return rate;
|
||||
}
|
||||
|
||||
static const struct ccu_pll_cfg *ccu_pll_lookup_best_cfg(struct ccu_pll *pll,
|
||||
unsigned long rate)
|
||||
{
|
||||
unsigned long best_delta = ULONG_MAX;
|
||||
const struct ccu_pll_cfg *best_cfg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pll->cfgnum; i++) {
|
||||
const struct ccu_pll_cfg *cfg = &pll->cfgs[i];
|
||||
unsigned long delta;
|
||||
|
||||
delta = abs_diff(cfg->freq, rate);
|
||||
if (delta < best_delta) {
|
||||
best_delta = delta;
|
||||
best_cfg = cfg;
|
||||
}
|
||||
}
|
||||
|
||||
return best_cfg;
|
||||
}
|
||||
|
||||
static int ccu_pll_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct ccu_pll *pll = hw_to_ccu_pll(hw);
|
||||
|
||||
req->rate = ccu_pll_lookup_best_cfg(pll, req->rate)->freq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ccu_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct ccu_pll *pll = hw_to_ccu_pll(hw);
|
||||
const struct ccu_pll_cfg *cfg;
|
||||
|
||||
cfg = ccu_pll_lookup_best_cfg(pll, rate);
|
||||
|
||||
ccu_pll_disable(hw);
|
||||
|
||||
regmap_write(pll->common.map, pll->common.cfg0,
|
||||
FIELD_PREP(TH1520_PLL_REFDIV, 1) |
|
||||
FIELD_PREP(TH1520_PLL_FBDIV, cfg->fbdiv) |
|
||||
FIELD_PREP(TH1520_PLL_POSTDIV1, cfg->postdiv1) |
|
||||
FIELD_PREP(TH1520_PLL_POSTDIV2, cfg->postdiv2));
|
||||
|
||||
regmap_update_bits(pll->common.map, pll->common.cfg1,
|
||||
TH1520_PLL_DACPD | TH1520_PLL_DSMPD |
|
||||
TH1520_PLL_FRAC,
|
||||
cfg->frac ? cfg->frac :
|
||||
TH1520_PLL_DACPD | TH1520_PLL_DSMPD);
|
||||
|
||||
return ccu_pll_enable(hw);
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_pll_ops = {
|
||||
.disable = ccu_pll_disable,
|
||||
.enable = ccu_pll_enable,
|
||||
.is_enabled = ccu_pll_is_enabled,
|
||||
.recalc_rate = ccu_pll_recalc_rate,
|
||||
.determine_rate = ccu_pll_determine_rate,
|
||||
.set_rate = ccu_pll_set_rate,
|
||||
};
|
||||
|
||||
static const struct clk_parent_data osc_24m_clk[] = {
|
||||
{ .index = 0 }
|
||||
};
|
||||
|
||||
static const struct ccu_pll_cfg cpu_pll_cfgs[] = {
|
||||
{ 125000000, 125, 0, 6, 4 },
|
||||
{ 200000000, 125, 0, 5, 3 },
|
||||
{ 300000000, 125, 0, 5, 2 },
|
||||
{ 400000000, 100, 0, 3, 2 },
|
||||
{ 500000000, 125, 0, 6, 1 },
|
||||
{ 600000000, 125, 0, 5, 1 },
|
||||
{ 702000000, 117, 0, 4, 1 },
|
||||
{ 800000000, 100, 0, 3, 1 },
|
||||
{ 900000000, 75, 0, 2, 1 },
|
||||
{ 1000000000, 125, 0, 3, 1 },
|
||||
{ 1104000000, 92, 0, 2, 1 },
|
||||
{ 1200000000, 100, 0, 2, 1 },
|
||||
{ 1296000000, 108, 0, 2, 1 },
|
||||
{ 1404000000, 117, 0, 2, 1 },
|
||||
{ 1500000000, 125, 0, 2, 1 },
|
||||
{ 1608000000, 67, 0, 1, 1 },
|
||||
{ 1704000000, 71, 0, 1, 1 },
|
||||
{ 1800000000, 75, 0, 1, 1 },
|
||||
{ 1896000000, 79, 0, 1, 1 },
|
||||
{ 1992000000, 83, 0, 1, 1 },
|
||||
{ 2112000000, 88, 0, 1, 1 },
|
||||
{ 2208000000, 92, 0, 1, 1 },
|
||||
{ 2304000000, 96, 0, 1, 1 },
|
||||
{ 2400000000, 100, 0, 1, 1 },
|
||||
};
|
||||
|
||||
static struct ccu_pll cpu_pll0_clk = {
|
||||
.common = {
|
||||
.clkid = CLK_CPU_PLL0,
|
||||
|
|
@ -413,6 +509,8 @@ static struct ccu_pll cpu_pll0_clk = {
|
|||
CLK_IS_CRITICAL),
|
||||
},
|
||||
.lock_sts_mask = BIT(1),
|
||||
.cfgnum = ARRAY_SIZE(cpu_pll_cfgs),
|
||||
.cfgs = cpu_pll_cfgs,
|
||||
};
|
||||
|
||||
static struct ccu_pll cpu_pll1_clk = {
|
||||
|
|
@ -426,6 +524,16 @@ static struct ccu_pll cpu_pll1_clk = {
|
|||
CLK_IS_CRITICAL),
|
||||
},
|
||||
.lock_sts_mask = BIT(4),
|
||||
.cfgnum = ARRAY_SIZE(cpu_pll_cfgs),
|
||||
.cfgs = cpu_pll_cfgs,
|
||||
};
|
||||
|
||||
static const struct ccu_pll_cfg gmac_pll_cfg = {
|
||||
.freq = 1000000000,
|
||||
.fbdiv = 125,
|
||||
.frac = 0,
|
||||
.postdiv1 = 3,
|
||||
.postdiv2 = 1,
|
||||
};
|
||||
|
||||
static struct ccu_pll gmac_pll_clk = {
|
||||
|
|
@ -439,6 +547,8 @@ static struct ccu_pll gmac_pll_clk = {
|
|||
CLK_IS_CRITICAL),
|
||||
},
|
||||
.lock_sts_mask = BIT(3),
|
||||
.cfgnum = 1,
|
||||
.cfgs = &gmac_pll_cfg,
|
||||
};
|
||||
|
||||
static const struct clk_hw *gmac_pll_clk_parent[] = {
|
||||
|
|
@ -449,6 +559,14 @@ static const struct clk_parent_data gmac_pll_clk_pd[] = {
|
|||
{ .hw = &gmac_pll_clk.common.hw }
|
||||
};
|
||||
|
||||
static const struct ccu_pll_cfg video_pll_cfg = {
|
||||
.freq = 792000000,
|
||||
.fbdiv = 99,
|
||||
.frac = 0,
|
||||
.postdiv1 = 3,
|
||||
.postdiv2 = 1,
|
||||
};
|
||||
|
||||
static struct ccu_pll video_pll_clk = {
|
||||
.common = {
|
||||
.clkid = CLK_VIDEO_PLL,
|
||||
|
|
@ -460,6 +578,8 @@ static struct ccu_pll video_pll_clk = {
|
|||
CLK_IS_CRITICAL),
|
||||
},
|
||||
.lock_sts_mask = BIT(7),
|
||||
.cfgnum = 1,
|
||||
.cfgs = &video_pll_cfg,
|
||||
};
|
||||
|
||||
static const struct clk_hw *video_pll_clk_parent[] = {
|
||||
|
|
@ -470,6 +590,14 @@ static const struct clk_parent_data video_pll_clk_pd[] = {
|
|||
{ .hw = &video_pll_clk.common.hw }
|
||||
};
|
||||
|
||||
static const struct ccu_pll_cfg dpu_pll_cfg = {
|
||||
.freq = 1188000000,
|
||||
.fbdiv = 99,
|
||||
.frac = 0,
|
||||
.postdiv1 = 2,
|
||||
.postdiv2 = 1,
|
||||
};
|
||||
|
||||
static struct ccu_pll dpu0_pll_clk = {
|
||||
.common = {
|
||||
.clkid = CLK_DPU0_PLL,
|
||||
|
|
@ -481,6 +609,8 @@ static struct ccu_pll dpu0_pll_clk = {
|
|||
0),
|
||||
},
|
||||
.lock_sts_mask = BIT(8),
|
||||
.cfgnum = 1,
|
||||
.cfgs = &dpu_pll_cfg,
|
||||
};
|
||||
|
||||
static const struct clk_hw *dpu0_pll_clk_parent[] = {
|
||||
|
|
@ -498,12 +628,22 @@ static struct ccu_pll dpu1_pll_clk = {
|
|||
0),
|
||||
},
|
||||
.lock_sts_mask = BIT(9),
|
||||
.cfgnum = 1,
|
||||
.cfgs = &dpu_pll_cfg,
|
||||
};
|
||||
|
||||
static const struct clk_hw *dpu1_pll_clk_parent[] = {
|
||||
&dpu1_pll_clk.common.hw
|
||||
};
|
||||
|
||||
static const struct ccu_pll_cfg tee_pll_cfg = {
|
||||
.freq = 792000000,
|
||||
.fbdiv = 99,
|
||||
.frac = 0,
|
||||
.postdiv1 = 3,
|
||||
.postdiv2 = 1,
|
||||
};
|
||||
|
||||
static struct ccu_pll tee_pll_clk = {
|
||||
.common = {
|
||||
.clkid = CLK_TEE_PLL,
|
||||
|
|
@ -515,6 +655,8 @@ static struct ccu_pll tee_pll_clk = {
|
|||
CLK_IS_CRITICAL),
|
||||
},
|
||||
.lock_sts_mask = BIT(10),
|
||||
.cfgnum = 1,
|
||||
.cfgs = &tee_pll_cfg,
|
||||
};
|
||||
|
||||
static const struct clk_parent_data c910_i0_parents[] = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user