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

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.com


Signed-off-by: default avatarStephen Boyd <sboyd@kernel.org>
parent 263ac390
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -27,16 +27,19 @@

static struct __prci_wrpll_data __prci_corepll_data = {
	.cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
	.cfg1_offs = PRCI_COREPLLCFG1_OFFSET,
	.enable_bypass = sifive_prci_coreclksel_use_hfclk,
	.disable_bypass = sifive_prci_coreclksel_use_corepll,
};

static struct __prci_wrpll_data __prci_ddrpll_data = {
	.cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
	.cfg1_offs = PRCI_DDRPLLCFG1_OFFSET,
};

static struct __prci_wrpll_data __prci_gemgxlpll_data = {
	.cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
	.cfg1_offs = PRCI_GEMGXLPLLCFG1_OFFSET,
};

/* 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,
	.round_rate = sifive_prci_wrpll_round_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 = {
+9 −0
Original line number Diff line number Diff line
@@ -15,32 +15,38 @@

static struct __prci_wrpll_data __prci_corepll_data = {
	.cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
	.cfg1_offs = PRCI_COREPLLCFG1_OFFSET,
	.enable_bypass = sifive_prci_coreclksel_use_hfclk,
	.disable_bypass = sifive_prci_coreclksel_use_final_corepll,
};

static struct __prci_wrpll_data __prci_ddrpll_data = {
	.cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
	.cfg1_offs = PRCI_DDRPLLCFG1_OFFSET,
};

static struct __prci_wrpll_data __prci_gemgxlpll_data = {
	.cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
	.cfg1_offs = PRCI_GEMGXLPLLCFG1_OFFSET,
};

static struct __prci_wrpll_data __prci_dvfscorepll_data = {
	.cfg0_offs = PRCI_DVFSCOREPLLCFG0_OFFSET,
	.cfg1_offs = PRCI_DVFSCOREPLLCFG1_OFFSET,
	.enable_bypass = sifive_prci_corepllsel_use_corepll,
	.disable_bypass = sifive_prci_corepllsel_use_dvfscorepll,
};

static struct __prci_wrpll_data __prci_hfpclkpll_data = {
	.cfg0_offs = PRCI_HFPCLKPLLCFG0_OFFSET,
	.cfg1_offs = PRCI_HFPCLKPLLCFG1_OFFSET,
	.enable_bypass = sifive_prci_hfpclkpllsel_use_hfclk,
	.disable_bypass = sifive_prci_hfpclkpllsel_use_hfpclkpll,
};

static struct __prci_wrpll_data __prci_cltxpll_data = {
	.cfg0_offs = PRCI_CLTXPLLCFG0_OFFSET,
	.cfg1_offs = PRCI_CLTXPLLCFG1_OFFSET,
};

/* 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,
	.round_rate = sifive_prci_wrpll_round_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 = {
+68 −9
Original line number Diff line number Diff line
@@ -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
 * @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
 *          @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)
{
	__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
 * @pwd: PRCI WRPLL metadata
 * @c: WRPLL configuration record to write
@@ -144,7 +144,7 @@ static void __prci_wrpll_read_cfg(struct __prci_data *pd,
 * Context: Any context.  Caller must prevent the records pointed to by
 *          @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 wrpll_cfg *c)
{
@@ -153,6 +153,20 @@ static void __prci_wrpll_write_cfg(struct __prci_data *pd,
	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
 *
@@ -199,16 +213,61 @@ int sifive_prci_wrpll_set_rate(struct clk_hw *hw,
	if (pwd->enable_bypass)
		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));

	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)
		pwd->disable_bypass(pd);

	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 */

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;

		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);
		if (r) {
+10 −0
Original line number Diff line number Diff line
@@ -40,6 +40,11 @@
#define PRCI_COREPLLCFG0_LOCK_SHIFT	31
#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 */
#define PRCI_DDRPLLCFG0_OFFSET		0xc
#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)
 * @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
 * @cfg1_offs: WRPLL CFG1 register offset (in bytes) from the PRCI base address
 *
 * @enable_bypass and @disable_bypass are used for WRPLL instances
 * 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 (*disable_bypass)(struct __prci_data *pd);
	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);
int sifive_prci_wrpll_set_rate(struct clk_hw *hw, unsigned long 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 parent_rate);
unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw,