Commit 732374a0 authored by Pragnesh Patel's avatar Pragnesh Patel Committed by Stephen Boyd

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: default avatarPragnesh Patel <pragnesh.patel@sifive.com>
Tested-by: default avatarZong Li <zong.li@sifive.com>
Link: https://lore.kernel.org/r/20201209094916.17383-6-zong.li@sifive.comSigned-off-by: default avatarStephen Boyd <sboyd@kernel.org>
parent 263ac390
...@@ -27,16 +27,19 @@ ...@@ -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 = { ...@@ -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 @@ ...@@ -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 = { ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 @@ ...@@ -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 { ...@@ -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 { ...@@ -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, ...@@ -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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment