Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a758a13d authored by Amit Nischal's avatar Amit Nischal Committed by Chetan C R
Browse files

clk: qcom: Add support to initialize & handle dynamic update for alpha plls



Add support to do initial configuration for alpha plls and votable
alpha PLLs need to have the fsm mode enabled as part of the
initialization using flag 'SUPPORTS_FSM_MODE'.

Alpha PLLs can support two kinds of input signals, normal and latched.
The normal input is directly passed to the core, while the latched input
requires a latch and acknowledge sequence to be performed for the
changed input to propagate.

Alpha PLLs can support dynamic update with both kind of input signals.
The ones which support this using a latched interface however need to
follow the latch/wait-for-ack sequence to be performed when the rate
changes. Mark these with a new flag 'SUPPORTS_DYNAMIC_UPDATE' to handle
this as part of clk_alpha_pll_set_rate().

PLLs could require post div to be set at runtime, add a vco_data which
could be used for these settings.

Change-Id: Ia0b9a2a52a3b33b7b68409c19c460d717eb5c1e2
Signed-off-by: default avatarAmit Nischal <anischal@codeaurora.org>
Signed-off-by: default avatarTaniya Das <tdas@codeaurora.org>
parent f24a5982
Loading
Loading
Loading
Loading
+134 −42
Original line number Diff line number Diff line
@@ -23,11 +23,14 @@
#define PLL_LOCK_COUNT_MASK	0x3f
#define PLL_BIAS_COUNT_SHIFT	14
#define PLL_BIAS_COUNT_MASK	0x3f
#define PLL_BIAS_COUNT_VAL	0x6
#define PLL_LATCH_INTERFACE	BIT(11)
#define PLL_VOTE_FSM_ENA	BIT(20)
#define PLL_FSM_ENA		BIT(20)
#define PLL_VOTE_FSM_RESET	BIT(21)
#define PLL_UPDATE		BIT(22)
#define PLL_UPDATE_BYPASS	BIT(23)
#define PLL_ALPHA_EN		BIT(24)
#define PLL_OFFLINE_ACK		BIT(28)
#define ALPHA_PLL_ACK_LATCH	BIT(29)
#define PLL_ACTIVE_FLAG		BIT(30)
@@ -251,14 +254,21 @@ static int wait_for_pll(struct clk_alpha_pll *pll, u32 mask, bool inverse,
#define wait_for_pll_update_ack_clear(pll) \
	wait_for_pll(pll, ALPHA_PLL_ACK_LATCH, 1, "update_ack_clear")

#define wait_for_pll_latch_ack(pll) \
	wait_for_pll(pll, ALPHA_PLL_ACK_LATCH, 0, "latch ack")

void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
			     const struct alpha_pll_config *config)
{
	u32 val, mask;

	if (config->l)
		regmap_write(regmap, PLL_L_VAL(pll), config->l);
	if (config->alpha)
		regmap_write(regmap, PLL_ALPHA_VAL(pll), config->alpha);
	regmap_write(regmap, PLL_CONFIG_CTL(pll), config->config_ctl_val);
	if (config->config_ctl_val)
		regmap_write(regmap, PLL_CONFIG_CTL(pll),
				config->config_ctl_val);

	if (pll_has_64bit_config(pll))
		regmap_write(regmap, PLL_CONFIG_CTL_U(pll),
@@ -267,6 +277,10 @@ void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
	if (pll_alpha_width(pll) > 32)
		regmap_write(regmap, PLL_ALPHA_VAL_U(pll), config->alpha_hi);

	if (config->main_output_mask || config->aux_output_mask ||
		config->aux2_output_mask || config->early_output_mask ||
		config->pre_div_val || config->vco_val ||
		config->alpha_en_mask) {
		val = config->main_output_mask;
		val |= config->aux_output_mask;
		val |= config->aux2_output_mask;
@@ -284,7 +298,7 @@ void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
		mask |= config->alpha_en_mask;

		regmap_update_bits(regmap, PLL_USER_CTL(pll), mask, val);

	}

	if (config->post_div_mask) {
		mask = config->post_div_mask;
@@ -292,6 +306,17 @@ void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
		regmap_update_bits(regmap, PLL_USER_CTL(pll), mask, val);
	}

	/* Do not bypass the latch interface */
	if (pll->flags & SUPPORTS_SLEW)
		regmap_update_bits(regmap, PLL_USER_CTL_U(pll),
		PLL_LATCH_INTERFACE, (u32)~PLL_LATCH_INTERFACE);

	if (pll->flags & SUPPORTS_DYNAMIC_UPDATE) {
		regmap_update_bits(regmap, PLL_MODE(pll),
				 PLL_UPDATE_BYPASS,
				 PLL_UPDATE_BYPASS);
	}

	if (config->test_ctl_mask) {
		mask = config->test_ctl_mask;
		val = config->test_ctl_val;
@@ -562,6 +587,49 @@ clk_alpha_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
	return alpha_pll_calc_rate(prate, l, a, alpha_width);
}

static int clk_alpha_pll_dynamic_update(struct clk_alpha_pll *pll)
{
	int ret;

	/* Latch the input to the PLL */
	regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll),
				PLL_UPDATE, PLL_UPDATE);

	/* Wait for 2 reference cycle before checking ACK bit */
	udelay(1);

	ret = wait_for_pll_latch_ack(pll);
	if (ret)
		return ret;

	/* Return latch input to 0 */
	regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll),
				PLL_UPDATE, (u32)~PLL_UPDATE);

	ret = wait_for_pll_enable_lock(pll);
	if (ret)
		return ret;

	return 0;
}

static const struct pll_vco_data
	*find_vco_data(const struct pll_vco_data *data,
			unsigned long rate, size_t size)
{
	int i;

	if (!data)
		return NULL;

	for (i = 0; i < size; i++) {
		if (rate == data[i].freq)
			return &data[i];
	}

	return &data[i - 1];
}

static int __clk_alpha_pll_update_latch(struct clk_alpha_pll *pll)
{
	int ret;
@@ -623,7 +691,10 @@ static int __clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate,
				    int (*is_enabled)(struct clk_hw *))
{
	struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
	struct clk_alpha_pll_postdiv *pll_postdiv =
		to_clk_alpha_pll_postdiv(hw);
	const struct pll_vco *vco;
	const struct pll_vco_data *data;
	u32 l, alpha_width = pll_alpha_width(pll);
	u64 a;
	unsigned long rrate;
@@ -666,9 +737,27 @@ static int __clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate,
				   vco->val << PLL_VCO_SHIFT);
	}

	data = find_vco_data(pll->vco_data, rate, pll->num_vco_data);
	if (data) {
		if (data->freq == rate)
			regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll),
				PLL_POST_DIV_MASK(pll_postdiv)
				<< PLL_POST_DIV_SHIFT,
				data->post_div_val << PLL_POST_DIV_SHIFT);
		else
			regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll),
					PLL_POST_DIV_MASK(pll_postdiv)
					<< PLL_POST_DIV_SHIFT,
					0x0 << PLL_VCO_SHIFT);
	}

	regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll),
			   PLL_ALPHA_EN, PLL_ALPHA_EN);

	if (is_enabled(&pll->clkr.hw) &&
		(pll->flags & SUPPORTS_DYNAMIC_UPDATE))
		clk_alpha_pll_dynamic_update(pll);

	if (is_enabled(&pll->clkr.hw) &&
	    !(pll->flags & SUPPORTS_DYNAMIC_UPDATE))
		hw->init->ops->enable(hw);
@@ -698,6 +787,9 @@ static long clk_alpha_pll_round_rate(struct clk_hw *hw, unsigned long rate,
	u64 a;
	unsigned long min_freq, max_freq;

	if (rate < pll->min_supported_freq)
		return pll->min_supported_freq;

	rate = alpha_pll_round_rate(rate, *prate, &l, &a, alpha_width);
	if (!pll->vco_table || alpha_pll_find_vco(pll, rate))
		return rate;
+16 −0
Original line number Diff line number Diff line
@@ -42,6 +42,11 @@ enum {

extern const u8 clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_MAX][PLL_OFF_MAX_REGS];

struct pll_vco_data {
	unsigned long freq;
	u8 post_div_val;
};

struct pll_vco {
	unsigned long min_freq;
	unsigned long max_freq;
@@ -55,6 +60,7 @@ struct pll_vco {
 * @soft_vote_mask: soft voting mask for multiple PLL software instances
 * @vco_table: array of VCO settings
 * @regs: alpha pll register map (see @clk_alpha_pll_regs)
 * @vco_data: array of VCO data settings like post div
 * @clkr: regmap clock handle
 */
struct clk_alpha_pll {
@@ -71,14 +77,24 @@ struct clk_alpha_pll {

	const struct pll_vco *vco_table;
	size_t num_vco;

	const struct pll_vco_data *vco_data;
	size_t num_vco_data;

#define SUPPORTS_OFFLINE_REQ	BIT(0)
#define SUPPORTS_FSM_MODE	BIT(2)
	/*
	 * Some PLLs support dynamically updating their rate without disabling
	 * the PLL first. Set this flag to enable this support.
	 */
#define SUPPORTS_DYNAMIC_UPDATE	BIT(3)
#define SUPPORTS_SLEW		BIT(4)
	/* Associated with soft_vote for multiple PLL software instances */
#define SUPPORTS_FSM_VOTE	BIT(5)
	u8 flags;

	struct clk_regmap clkr;
	unsigned long min_supported_freq;
};

/**