lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1427063726-4248-3-git-send-email-tony@atomide.com>
Date:	Sun, 22 Mar 2015 15:35:25 -0700
From:	Tony Lindgren <tony@...mide.com>
To:	Mike Turquette <mturquette@...aro.org>,
	Stephen Boyd <sboyd@...eaurora.org>
Cc:	linux-kernel@...r.kernel.org, linux-omap@...r.kernel.org,
	Brian Hutchinson <b.hutchman@...il.com>,
	Matthijs van Duin <matthijsvanduin@...il.com>,
	Tero Kristo <t-kristo@...com>
Subject: [PATCH 2/3] clk: ti: Implement FAPLL set_rate for the synthesizer

We can pretty much get any rate out of the FAPLL because of the fractional
divider. Let's first try just adjusting the post divider, and if that is
not enough, then reprogram both the fractional divider and the post divider.

Let's also add a define for the fixed SYNTH_PHASE_K instead of using 8.

Cc: Brian Hutchinson <b.hutchman@...il.com>
Cc: Matthijs van Duin <matthijsvanduin@...il.com>
Cc: Tero Kristo <t-kristo@...com>
Signed-off-by: Tony Lindgren <tony@...mide.com>
---
 drivers/clk/ti/fapll.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 132 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/ti/fapll.c b/drivers/clk/ti/fapll.c
index 3b5e231..4064f7b 100644
--- a/drivers/clk/ti/fapll.c
+++ b/drivers/clk/ti/fapll.c
@@ -12,6 +12,7 @@
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
 #include <linux/err.h>
+#include <linux/math64.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/clk/ti.h>
@@ -47,6 +48,8 @@
 /* Synthesizer frequency register */
 #define SYNTH_LDFREQ		BIT(31)
 
+#define SYNTH_PHASE_K		8
+#define SYNTH_MAX_INT_DIV	0xf
 #define SYNTH_MAX_DIV_M		0xff
 
 struct fapll_data {
@@ -204,7 +207,7 @@ static unsigned long ti_fapll_synth_recalc_rate(struct clk_hw *hw,
 	/*
 	 * Synth frequency integer and fractional divider.
 	 * Note that the phase output K is 8, so the result needs
-	 * to be multiplied by 8.
+	 * to be multiplied by SYNTH_PHASE_K.
 	 */
 	if (synth->freq) {
 		u32 v, synth_int_div, synth_frac_div, synth_div_freq;
@@ -215,7 +218,7 @@ static unsigned long ti_fapll_synth_recalc_rate(struct clk_hw *hw,
 		synth_div_freq = (synth_int_div * 10000000) + synth_frac_div;
 		rate *= 10000000;
 		do_div(rate, synth_div_freq);
-		rate *= 8;
+		rate *= SYNTH_PHASE_K;
 	}
 
 	/* Synth post-divider M */
@@ -224,11 +227,138 @@ static unsigned long ti_fapll_synth_recalc_rate(struct clk_hw *hw,
 	return DIV_ROUND_UP_ULL(rate, synth_div_m);
 }
 
+static unsigned long ti_fapll_synth_get_frac_rate(struct clk_hw *hw,
+						  unsigned long parent_rate)
+{
+	struct fapll_synth *synth = to_synth(hw);
+	unsigned long current_rate, frac_rate;
+	u32 post_div_m;
+
+	current_rate = ti_fapll_synth_recalc_rate(hw, parent_rate);
+	post_div_m = readl_relaxed(synth->div) & SYNTH_MAX_DIV_M;
+	frac_rate = current_rate * post_div_m;
+
+	return frac_rate;
+}
+
+static u32 ti_fapll_synth_set_frac_rate(struct fapll_synth *synth,
+					unsigned long rate,
+					unsigned long parent_rate)
+{
+	u32 post_div_m, synth_int_div, synth_frac_div, v;
+
+	post_div_m = DIV_ROUND_UP_ULL((u64)parent_rate * SYNTH_PHASE_K, rate);
+	post_div_m = post_div_m / SYNTH_MAX_INT_DIV;
+	if (post_div_m > SYNTH_MAX_DIV_M)
+		return -EINVAL;
+	if (!post_div_m)
+		post_div_m = 1;
+
+	for (; post_div_m < SYNTH_MAX_DIV_M; post_div_m++) {
+		synth_int_div = DIV_ROUND_UP_ULL((u64)parent_rate *
+						 SYNTH_PHASE_K *
+						 10000000,
+						 rate * post_div_m);
+		synth_frac_div = synth_int_div % 10000000;
+		synth_int_div /= 10000000;
+
+		if (synth_int_div <= SYNTH_MAX_INT_DIV)
+			break;
+	}
+
+	if (synth_int_div > SYNTH_MAX_INT_DIV)
+		return -EINVAL;
+
+	v = readl_relaxed(synth->freq);
+	v &= ~0x1fffffff;
+	v |= (synth_int_div & SYNTH_MAX_INT_DIV) << 24;
+	v |= (synth_frac_div & 0xffffff);
+	v |= SYNTH_LDFREQ;
+	writel_relaxed(v, synth->freq);
+
+	return post_div_m;
+}
+
+static long ti_fapll_synth_round_rate(struct clk_hw *hw, unsigned long rate,
+				      unsigned long *parent_rate)
+{
+	struct fapll_synth *synth = to_synth(hw);
+	struct fapll_data *fd = synth->fd;
+	unsigned long r;
+
+	if (ti_fapll_clock_is_bypass(fd) || !synth->div || !rate)
+		return -EINVAL;
+
+	/* Only post divider m available with no fractional divider? */
+	if (!synth->freq) {
+		unsigned long frac_rate;
+		u32 synth_post_div_m;
+
+		frac_rate = ti_fapll_synth_get_frac_rate(hw, *parent_rate);
+		synth_post_div_m = DIV_ROUND_UP(frac_rate, rate);
+		r = DIV_ROUND_UP(frac_rate, synth_post_div_m);
+		goto out;
+	}
+
+	r = *parent_rate * SYNTH_PHASE_K;
+	if (rate > r)
+		goto out;
+
+	r = DIV_ROUND_UP_ULL(r, SYNTH_MAX_INT_DIV * SYNTH_MAX_DIV_M);
+	if (rate < r)
+		goto out;
+
+	r = rate;
+out:
+	return r;
+}
+
+static int ti_fapll_synth_set_rate(struct clk_hw *hw, unsigned long rate,
+				   unsigned long parent_rate)
+{
+	struct fapll_synth *synth = to_synth(hw);
+	struct fapll_data *fd = synth->fd;
+	unsigned long frac_rate, post_rate = 0;
+	u32 post_div_m = 0, v;
+
+	if (ti_fapll_clock_is_bypass(fd) || !synth->div || !rate)
+		return -EINVAL;
+
+	/* Produce the rate with just post divider M? */
+	frac_rate = ti_fapll_synth_get_frac_rate(hw, parent_rate);
+	if (frac_rate < rate) {
+		if (!synth->freq)
+			return -EINVAL;
+	} else {
+		post_div_m = DIV_ROUND_UP(frac_rate, rate);
+		if (post_div_m && (post_div_m <= SYNTH_MAX_DIV_M))
+			post_rate = DIV_ROUND_UP(frac_rate, post_div_m);
+		if (!synth->freq && !post_rate)
+			return -EINVAL;
+	}
+
+	/* Need to recalculate the fractional divider? */
+	if ((post_rate != rate) && synth->freq)
+		post_div_m = ti_fapll_synth_set_frac_rate(synth,
+							  rate,
+							  parent_rate);
+
+	v = readl_relaxed(synth->div);
+	v &= ~SYNTH_MAX_DIV_M;
+	v |= post_div_m;
+	v |= SYNTH_LDMDIV1;
+	writel_relaxed(v, synth->div);
+
+	return 0;
+}
+
 static struct clk_ops ti_fapll_synt_ops = {
 	.enable = ti_fapll_synth_enable,
 	.disable = ti_fapll_synth_disable,
 	.is_enabled = ti_fapll_synth_is_enabled,
 	.recalc_rate = ti_fapll_synth_recalc_rate,
+	.round_rate = ti_fapll_synth_round_rate,
+	.set_rate = ti_fapll_synth_set_rate,
 };
 
 static struct clk * __init ti_fapll_synth_setup(struct fapll_data *fd,
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ