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

Commit 286a9cd0 authored by Junjie Wu's avatar Junjie Wu Committed by Huaibin Yang
Browse files

clk: qcom: clock-local2: Only update display RCG if config changes



RCG update will briefly gate the output to ensure glitch free
transition, even if the configuration values are not changed. This
behavior is not acceptable for display clocks because display would
flicker when clock is gated.

Only trigger RCG update when configuration actually changes to avoid
display flicker.

Change-Id: I65b623b55a0abebe99a61137dabb3cfc3e37f2d6
Signed-off-by: default avatarJunjie Wu <junjiew@codeaurora.org>
parent e42f404d
Loading
Loading
Loading
Loading
+62 −10
Original line number Diff line number Diff line
/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -108,28 +108,31 @@ static void rcg_update_config(struct rcg_clk *rcg)
}

/* RCG set rate function for clocks with Half Integer Dividers. */
void set_rate_hid(struct rcg_clk *rcg, struct clk_freq_tbl *nf)
static void __set_rate_hid(struct rcg_clk *rcg, struct clk_freq_tbl *nf)
{
	u32 cfg_regval;
	unsigned long flags;

	spin_lock_irqsave(&local_clock_reg_lock, flags);
	cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg));
	cfg_regval &= ~(CFG_RCGR_DIV_MASK | CFG_RCGR_SRC_SEL_MASK);
	cfg_regval |= nf->div_src_val;
	writel_relaxed(cfg_regval, CFG_RCGR_REG(rcg));

	rcg_update_config(rcg);
}

void set_rate_hid(struct rcg_clk *rcg, struct clk_freq_tbl *nf)
{
	unsigned long flags;
	spin_lock_irqsave(&local_clock_reg_lock, flags);
	__set_rate_hid(rcg, nf);
	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
}

/* RCG set rate function for clocks with MND & Half Integer Dividers. */
void set_rate_mnd(struct rcg_clk *rcg, struct clk_freq_tbl *nf)
static void __set_rate_mnd(struct rcg_clk *rcg, struct clk_freq_tbl *nf)
{
	u32 cfg_regval;
	unsigned long flags;

	spin_lock_irqsave(&local_clock_reg_lock, flags);
	cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg));
	writel_relaxed(nf->m_val, M_REG(rcg));
	writel_relaxed(nf->n_val, N_REG(rcg));
@@ -146,6 +149,13 @@ void set_rate_mnd(struct rcg_clk *rcg, struct clk_freq_tbl *nf)
	writel_relaxed(cfg_regval, CFG_RCGR_REG(rcg));

	rcg_update_config(rcg);
}

void set_rate_mnd(struct rcg_clk *rcg, struct clk_freq_tbl *nf)
{
	unsigned long flags;
	spin_lock_irqsave(&local_clock_reg_lock, flags);
	__set_rate_mnd(rcg, nf);
	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
}

@@ -851,6 +861,34 @@ static struct frac_entry frac_table_810m[] = { /* Link rate of 162M */
	{0, 0},
};

static bool is_same_rcg_config(struct rcg_clk *rcg, struct clk_freq_tbl *freq,
			       bool has_mnd)
{
	u32 cfg;

	/* RCG update pending */
	if (readl_relaxed(CMD_RCGR_REG(rcg)) & CMD_RCGR_CONFIG_DIRTY_MASK)
		return false;
	if (has_mnd)
		if (readl_relaxed(M_REG(rcg)) != freq->m_val ||
		    readl_relaxed(N_REG(rcg)) != freq->n_val ||
		    readl_relaxed(D_REG(rcg)) != freq->d_val)
			return false;
	/*
	 * Both 0 and 1 represent same divider value in HW.
	 * Always use 0 to simplify comparison.
	 */
	if ((freq->div_src_val & CFG_RCGR_DIV_MASK) == 1)
		freq->div_src_val &= ~CFG_RCGR_DIV_MASK;
	cfg = readl_relaxed(CFG_RCGR_REG(rcg));
	if ((cfg & CFG_RCGR_DIV_MASK) == 1)
		cfg &= ~CFG_RCGR_DIV_MASK;
	if (cfg != freq->div_src_val)
		return false;

	return true;
}

static int set_rate_edp_pixel(struct clk *clk, unsigned long rate)
{
	struct rcg_clk *rcg = to_rcg_clk(clk);
@@ -859,6 +897,7 @@ static int set_rate_edp_pixel(struct clk *clk, unsigned long rate)
	int delta = 100000;
	s64 request;
	s64 src_rate;
	unsigned long flags;

	src_rate = clk_get_rate(clk->parent);

@@ -886,7 +925,10 @@ static int set_rate_edp_pixel(struct clk *clk, unsigned long rate)
			pixel_freq->n_val = ~(frac->den - frac->num);
			pixel_freq->d_val = ~frac->den;
		}
		set_rate_mnd(rcg, pixel_freq);
		spin_lock_irqsave(&local_clock_reg_lock, flags);
		if (!is_same_rcg_config(rcg, pixel_freq, true))
			__set_rate_mnd(rcg, pixel_freq);
		spin_unlock_irqrestore(&local_clock_reg_lock, flags);
		return 0;
	}
	return -EINVAL;
@@ -917,7 +959,7 @@ static int set_rate_byte(struct clk *clk, unsigned long rate)
{
	struct rcg_clk *rcg = to_rcg_clk(clk);
	struct clk *pll = clk->parent;
	unsigned long source_rate, div;
	unsigned long source_rate, div, flags;
	struct clk_freq_tbl *byte_freq = rcg->current_freq;
	int rc;

@@ -936,9 +978,19 @@ static int set_rate_byte(struct clk *clk, unsigned long rate)
	if (div > CFG_RCGR_DIV_MASK)
		return -EINVAL;

	/*
	 * Both 0 and 1 represent same divider value in HW.
	 * Always use 0 to simplify comparison.
	 */
	div = (div == 1) ? 0 : div;

	byte_freq->div_src_val &= ~CFG_RCGR_DIV_MASK;
	byte_freq->div_src_val |= BVAL(4, 0, div);
	set_rate_hid(rcg, byte_freq);

	spin_lock_irqsave(&local_clock_reg_lock, flags);
	if (!is_same_rcg_config(rcg, byte_freq, false))
		__set_rate_hid(rcg, byte_freq);
	spin_unlock_irqrestore(&local_clock_reg_lock, flags);

	return 0;
}