clk: sifive: Add clock enable and disable ops
Add new functions "sifive_prci_clock_enable(), sifive_prci_clock_disable() and sifive_clk_is_enabled()" to enable or disable the PRCI clock Signed-off-by: Pragnesh Patel <pragnesh.patel@sifive.com> Tested-by: Zong Li <zong.li@sifive.com> Link: https://lore.kernel.org/r/20201209094916.17383-6-zong.li@sifive.com Signed-off-by: Stephen Boyd <sboyd@kernel.org>
This commit is contained in:
parent
263ac39085
commit
732374a0b4
@ -27,16 +27,19 @@
|
|||||||
|
|
||||||
static struct __prci_wrpll_data __prci_corepll_data = {
|
static struct __prci_wrpll_data __prci_corepll_data = {
|
||||||
.cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
|
.cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
|
||||||
|
.cfg1_offs = PRCI_COREPLLCFG1_OFFSET,
|
||||||
.enable_bypass = sifive_prci_coreclksel_use_hfclk,
|
.enable_bypass = sifive_prci_coreclksel_use_hfclk,
|
||||||
.disable_bypass = sifive_prci_coreclksel_use_corepll,
|
.disable_bypass = sifive_prci_coreclksel_use_corepll,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct __prci_wrpll_data __prci_ddrpll_data = {
|
static struct __prci_wrpll_data __prci_ddrpll_data = {
|
||||||
.cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
|
.cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
|
||||||
|
.cfg1_offs = PRCI_DDRPLLCFG1_OFFSET,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct __prci_wrpll_data __prci_gemgxlpll_data = {
|
static struct __prci_wrpll_data __prci_gemgxlpll_data = {
|
||||||
.cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
|
.cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
|
||||||
|
.cfg1_offs = PRCI_GEMGXLPLLCFG1_OFFSET,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Linux clock framework integration */
|
/* Linux clock framework integration */
|
||||||
@ -45,6 +48,9 @@ static const struct clk_ops sifive_fu540_prci_wrpll_clk_ops = {
|
|||||||
.set_rate = sifive_prci_wrpll_set_rate,
|
.set_rate = sifive_prci_wrpll_set_rate,
|
||||||
.round_rate = sifive_prci_wrpll_round_rate,
|
.round_rate = sifive_prci_wrpll_round_rate,
|
||||||
.recalc_rate = sifive_prci_wrpll_recalc_rate,
|
.recalc_rate = sifive_prci_wrpll_recalc_rate,
|
||||||
|
.enable = sifive_prci_clock_enable,
|
||||||
|
.disable = sifive_prci_clock_disable,
|
||||||
|
.is_enabled = sifive_clk_is_enabled,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct clk_ops sifive_fu540_prci_wrpll_ro_clk_ops = {
|
static const struct clk_ops sifive_fu540_prci_wrpll_ro_clk_ops = {
|
||||||
|
@ -15,32 +15,38 @@
|
|||||||
|
|
||||||
static struct __prci_wrpll_data __prci_corepll_data = {
|
static struct __prci_wrpll_data __prci_corepll_data = {
|
||||||
.cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
|
.cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
|
||||||
|
.cfg1_offs = PRCI_COREPLLCFG1_OFFSET,
|
||||||
.enable_bypass = sifive_prci_coreclksel_use_hfclk,
|
.enable_bypass = sifive_prci_coreclksel_use_hfclk,
|
||||||
.disable_bypass = sifive_prci_coreclksel_use_final_corepll,
|
.disable_bypass = sifive_prci_coreclksel_use_final_corepll,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct __prci_wrpll_data __prci_ddrpll_data = {
|
static struct __prci_wrpll_data __prci_ddrpll_data = {
|
||||||
.cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
|
.cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
|
||||||
|
.cfg1_offs = PRCI_DDRPLLCFG1_OFFSET,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct __prci_wrpll_data __prci_gemgxlpll_data = {
|
static struct __prci_wrpll_data __prci_gemgxlpll_data = {
|
||||||
.cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
|
.cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
|
||||||
|
.cfg1_offs = PRCI_GEMGXLPLLCFG1_OFFSET,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct __prci_wrpll_data __prci_dvfscorepll_data = {
|
static struct __prci_wrpll_data __prci_dvfscorepll_data = {
|
||||||
.cfg0_offs = PRCI_DVFSCOREPLLCFG0_OFFSET,
|
.cfg0_offs = PRCI_DVFSCOREPLLCFG0_OFFSET,
|
||||||
|
.cfg1_offs = PRCI_DVFSCOREPLLCFG1_OFFSET,
|
||||||
.enable_bypass = sifive_prci_corepllsel_use_corepll,
|
.enable_bypass = sifive_prci_corepllsel_use_corepll,
|
||||||
.disable_bypass = sifive_prci_corepllsel_use_dvfscorepll,
|
.disable_bypass = sifive_prci_corepllsel_use_dvfscorepll,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct __prci_wrpll_data __prci_hfpclkpll_data = {
|
static struct __prci_wrpll_data __prci_hfpclkpll_data = {
|
||||||
.cfg0_offs = PRCI_HFPCLKPLLCFG0_OFFSET,
|
.cfg0_offs = PRCI_HFPCLKPLLCFG0_OFFSET,
|
||||||
|
.cfg1_offs = PRCI_HFPCLKPLLCFG1_OFFSET,
|
||||||
.enable_bypass = sifive_prci_hfpclkpllsel_use_hfclk,
|
.enable_bypass = sifive_prci_hfpclkpllsel_use_hfclk,
|
||||||
.disable_bypass = sifive_prci_hfpclkpllsel_use_hfpclkpll,
|
.disable_bypass = sifive_prci_hfpclkpllsel_use_hfpclkpll,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct __prci_wrpll_data __prci_cltxpll_data = {
|
static struct __prci_wrpll_data __prci_cltxpll_data = {
|
||||||
.cfg0_offs = PRCI_CLTXPLLCFG0_OFFSET,
|
.cfg0_offs = PRCI_CLTXPLLCFG0_OFFSET,
|
||||||
|
.cfg1_offs = PRCI_CLTXPLLCFG1_OFFSET,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Linux clock framework integration */
|
/* Linux clock framework integration */
|
||||||
@ -49,6 +55,9 @@ static const struct clk_ops sifive_fu740_prci_wrpll_clk_ops = {
|
|||||||
.set_rate = sifive_prci_wrpll_set_rate,
|
.set_rate = sifive_prci_wrpll_set_rate,
|
||||||
.round_rate = sifive_prci_wrpll_round_rate,
|
.round_rate = sifive_prci_wrpll_round_rate,
|
||||||
.recalc_rate = sifive_prci_wrpll_recalc_rate,
|
.recalc_rate = sifive_prci_wrpll_recalc_rate,
|
||||||
|
.enable = sifive_prci_clock_enable,
|
||||||
|
.disable = sifive_prci_clock_disable,
|
||||||
|
.is_enabled = sifive_clk_is_enabled,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct clk_ops sifive_fu740_prci_wrpll_ro_clk_ops = {
|
static const struct clk_ops sifive_fu740_prci_wrpll_ro_clk_ops = {
|
||||||
|
@ -113,7 +113,7 @@ static u32 __prci_wrpll_pack(const struct wrpll_cfg *c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __prci_wrpll_read_cfg() - read the WRPLL configuration from the PRCI
|
* __prci_wrpll_read_cfg0() - read the WRPLL configuration from the PRCI
|
||||||
* @pd: PRCI context
|
* @pd: PRCI context
|
||||||
* @pwd: PRCI WRPLL metadata
|
* @pwd: PRCI WRPLL metadata
|
||||||
*
|
*
|
||||||
@ -124,14 +124,14 @@ static u32 __prci_wrpll_pack(const struct wrpll_cfg *c)
|
|||||||
* Context: Any context. Caller must prevent the records pointed to by
|
* Context: Any context. Caller must prevent the records pointed to by
|
||||||
* @pd and @pwd from changing during execution.
|
* @pd and @pwd from changing during execution.
|
||||||
*/
|
*/
|
||||||
static void __prci_wrpll_read_cfg(struct __prci_data *pd,
|
static void __prci_wrpll_read_cfg0(struct __prci_data *pd,
|
||||||
struct __prci_wrpll_data *pwd)
|
struct __prci_wrpll_data *pwd)
|
||||||
{
|
{
|
||||||
__prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs));
|
__prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __prci_wrpll_write_cfg() - write WRPLL configuration into the PRCI
|
* __prci_wrpll_write_cfg0() - write WRPLL configuration into the PRCI
|
||||||
* @pd: PRCI context
|
* @pd: PRCI context
|
||||||
* @pwd: PRCI WRPLL metadata
|
* @pwd: PRCI WRPLL metadata
|
||||||
* @c: WRPLL configuration record to write
|
* @c: WRPLL configuration record to write
|
||||||
@ -144,15 +144,29 @@ static void __prci_wrpll_read_cfg(struct __prci_data *pd,
|
|||||||
* Context: Any context. Caller must prevent the records pointed to by
|
* Context: Any context. Caller must prevent the records pointed to by
|
||||||
* @pd and @pwd from changing during execution.
|
* @pd and @pwd from changing during execution.
|
||||||
*/
|
*/
|
||||||
static void __prci_wrpll_write_cfg(struct __prci_data *pd,
|
static void __prci_wrpll_write_cfg0(struct __prci_data *pd,
|
||||||
struct __prci_wrpll_data *pwd,
|
struct __prci_wrpll_data *pwd,
|
||||||
struct wrpll_cfg *c)
|
struct wrpll_cfg *c)
|
||||||
{
|
{
|
||||||
__prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd);
|
__prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd);
|
||||||
|
|
||||||
memcpy(&pwd->c, c, sizeof(*c));
|
memcpy(&pwd->c, c, sizeof(*c));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __prci_wrpll_write_cfg1() - write Clock enable/disable configuration
|
||||||
|
* into the PRCI
|
||||||
|
* @pd: PRCI context
|
||||||
|
* @pwd: PRCI WRPLL metadata
|
||||||
|
* @enable: Clock enable or disable value
|
||||||
|
*/
|
||||||
|
static void __prci_wrpll_write_cfg1(struct __prci_data *pd,
|
||||||
|
struct __prci_wrpll_data *pwd,
|
||||||
|
u32 enable)
|
||||||
|
{
|
||||||
|
__prci_writel(enable, pwd->cfg1_offs, pd);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Linux clock framework integration
|
* Linux clock framework integration
|
||||||
*
|
*
|
||||||
@ -199,16 +213,61 @@ int sifive_prci_wrpll_set_rate(struct clk_hw *hw,
|
|||||||
if (pwd->enable_bypass)
|
if (pwd->enable_bypass)
|
||||||
pwd->enable_bypass(pd);
|
pwd->enable_bypass(pd);
|
||||||
|
|
||||||
__prci_wrpll_write_cfg(pd, pwd, &pwd->c);
|
__prci_wrpll_write_cfg0(pd, pwd, &pwd->c);
|
||||||
|
|
||||||
udelay(wrpll_calc_max_lock_us(&pwd->c));
|
udelay(wrpll_calc_max_lock_us(&pwd->c));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sifive_clk_is_enabled(struct clk_hw *hw)
|
||||||
|
{
|
||||||
|
struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
|
||||||
|
struct __prci_wrpll_data *pwd = pc->pwd;
|
||||||
|
struct __prci_data *pd = pc->pd;
|
||||||
|
u32 r;
|
||||||
|
|
||||||
|
r = __prci_readl(pd, pwd->cfg1_offs);
|
||||||
|
|
||||||
|
if (r & PRCI_COREPLLCFG1_CKE_MASK)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sifive_prci_clock_enable(struct clk_hw *hw)
|
||||||
|
{
|
||||||
|
struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
|
||||||
|
struct __prci_wrpll_data *pwd = pc->pwd;
|
||||||
|
struct __prci_data *pd = pc->pd;
|
||||||
|
|
||||||
|
if (sifive_clk_is_enabled(hw))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
__prci_wrpll_write_cfg1(pd, pwd, PRCI_COREPLLCFG1_CKE_MASK);
|
||||||
|
|
||||||
if (pwd->disable_bypass)
|
if (pwd->disable_bypass)
|
||||||
pwd->disable_bypass(pd);
|
pwd->disable_bypass(pd);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sifive_prci_clock_disable(struct clk_hw *hw)
|
||||||
|
{
|
||||||
|
struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
|
||||||
|
struct __prci_wrpll_data *pwd = pc->pwd;
|
||||||
|
struct __prci_data *pd = pc->pd;
|
||||||
|
u32 r;
|
||||||
|
|
||||||
|
if (pwd->enable_bypass)
|
||||||
|
pwd->enable_bypass(pd);
|
||||||
|
|
||||||
|
r = __prci_readl(pd, pwd->cfg1_offs);
|
||||||
|
r &= ~PRCI_COREPLLCFG1_CKE_MASK;
|
||||||
|
|
||||||
|
__prci_wrpll_write_cfg1(pd, pwd, r);
|
||||||
|
}
|
||||||
|
|
||||||
/* TLCLKSEL clock integration */
|
/* TLCLKSEL clock integration */
|
||||||
|
|
||||||
unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw,
|
unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw,
|
||||||
@ -427,7 +486,7 @@ static int __prci_register_clocks(struct device *dev, struct __prci_data *pd,
|
|||||||
pic->pd = pd;
|
pic->pd = pd;
|
||||||
|
|
||||||
if (pic->pwd)
|
if (pic->pwd)
|
||||||
__prci_wrpll_read_cfg(pd, pic->pwd);
|
__prci_wrpll_read_cfg0(pd, pic->pwd);
|
||||||
|
|
||||||
r = devm_clk_hw_register(dev, &pic->hw);
|
r = devm_clk_hw_register(dev, &pic->hw);
|
||||||
if (r) {
|
if (r) {
|
||||||
|
@ -40,6 +40,11 @@
|
|||||||
#define PRCI_COREPLLCFG0_LOCK_SHIFT 31
|
#define PRCI_COREPLLCFG0_LOCK_SHIFT 31
|
||||||
#define PRCI_COREPLLCFG0_LOCK_MASK (0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT)
|
#define PRCI_COREPLLCFG0_LOCK_MASK (0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT)
|
||||||
|
|
||||||
|
/* COREPLLCFG1 */
|
||||||
|
#define PRCI_COREPLLCFG1_OFFSET 0x8
|
||||||
|
#define PRCI_COREPLLCFG1_CKE_SHIFT 31
|
||||||
|
#define PRCI_COREPLLCFG1_CKE_MASK (0x1 << PRCI_COREPLLCFG1_CKE_SHIFT)
|
||||||
|
|
||||||
/* DDRPLLCFG0 */
|
/* DDRPLLCFG0 */
|
||||||
#define PRCI_DDRPLLCFG0_OFFSET 0xc
|
#define PRCI_DDRPLLCFG0_OFFSET 0xc
|
||||||
#define PRCI_DDRPLLCFG0_DIVR_SHIFT 0
|
#define PRCI_DDRPLLCFG0_DIVR_SHIFT 0
|
||||||
@ -220,6 +225,7 @@ struct __prci_data {
|
|||||||
* @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
|
* @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
|
||||||
* @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL)
|
* @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL)
|
||||||
* @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address
|
* @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address
|
||||||
|
* @cfg1_offs: WRPLL CFG1 register offset (in bytes) from the PRCI base address
|
||||||
*
|
*
|
||||||
* @enable_bypass and @disable_bypass are used for WRPLL instances
|
* @enable_bypass and @disable_bypass are used for WRPLL instances
|
||||||
* that contain a separate external glitchless clock mux downstream
|
* that contain a separate external glitchless clock mux downstream
|
||||||
@ -230,6 +236,7 @@ struct __prci_wrpll_data {
|
|||||||
void (*enable_bypass)(struct __prci_data *pd);
|
void (*enable_bypass)(struct __prci_data *pd);
|
||||||
void (*disable_bypass)(struct __prci_data *pd);
|
void (*disable_bypass)(struct __prci_data *pd);
|
||||||
u8 cfg0_offs;
|
u8 cfg0_offs;
|
||||||
|
u8 cfg1_offs;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -279,6 +286,9 @@ long sifive_prci_wrpll_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||||||
unsigned long *parent_rate);
|
unsigned long *parent_rate);
|
||||||
int sifive_prci_wrpll_set_rate(struct clk_hw *hw, unsigned long rate,
|
int sifive_prci_wrpll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||||
unsigned long parent_rate);
|
unsigned long parent_rate);
|
||||||
|
int sifive_clk_is_enabled(struct clk_hw *hw);
|
||||||
|
int sifive_prci_clock_enable(struct clk_hw *hw);
|
||||||
|
void sifive_prci_clock_disable(struct clk_hw *hw);
|
||||||
unsigned long sifive_prci_wrpll_recalc_rate(struct clk_hw *hw,
|
unsigned long sifive_prci_wrpll_recalc_rate(struct clk_hw *hw,
|
||||||
unsigned long parent_rate);
|
unsigned long parent_rate);
|
||||||
unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw,
|
unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw,
|
||||||
|
Loading…
Reference in New Issue
Block a user