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

Commit 4164f2e8 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

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

parents 6e10c0a6 a758a13d
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;
};

/**