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]
Date:	Fri, 26 Feb 2016 13:08:46 +0800
From:	Shawn Lin <shawn.lin@...k-chips.com>
To:	Stephen Boyd <sboyd@...eaurora.org>,
	Michael Turquette <mturquette@...libre.com>
Cc:	linux-kernel@...r.kernel.org, linux-clk@...r.kernel.org,
	Shawn Lin <shawn.lin@...k-chips.com>
Subject: [RFC PATCH 1/3] clk: add clk_round_phase support

This patch add new clk_round_phase API for drivers to
know what the actual phase the clk will provide. Also, add
round_rate and determine_rate callback into clk_ops for clk-driver
to do that. By default, we make min_phase and max_phase to be
0 and 360 respectively.

Signed-off-by: Shawn Lin <shawn.lin@...k-chips.com>

---

 drivers/clk/clk.c            | 138 +++++++++++++++++++++++++++++++++++++++----
 include/linux/clk-provider.h |  20 +++++++
 include/linux/clk.h          |  23 ++++++++
 3 files changed, 171 insertions(+), 10 deletions(-)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 549fdb8..3a8407c 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -64,6 +64,8 @@ struct clk_core {
 	unsigned long		max_rate;
 	unsigned long		accuracy;
 	int			phase;
+	unsigned long		min_phase;
+	unsigned long		max_phase;
 	struct hlist_head	children;
 	struct hlist_node	child_node;
 	struct hlist_head	clks;
@@ -522,18 +524,27 @@ struct clk *__clk_lookup(const char *name)
 
 static void clk_core_get_boundaries(struct clk_core *core,
 				    unsigned long *min_rate,
-				    unsigned long *max_rate)
+				    unsigned long *max_rate,
+				    unsigned long *min_phase,
+				    unsigned long *max_phase)
 {
 	struct clk *clk_user;
 
-	*min_rate = core->min_rate;
-	*max_rate = core->max_rate;
+	if (min_rate && max_rate) {
+		*min_rate = core->min_rate;
+		*max_rate = core->max_rate;
 
-	hlist_for_each_entry(clk_user, &core->clks, clks_node)
-		*min_rate = max(*min_rate, clk_user->min_rate);
+		hlist_for_each_entry(clk_user, &core->clks, clks_node)
+			*min_rate = max(*min_rate, clk_user->min_rate);
 
-	hlist_for_each_entry(clk_user, &core->clks, clks_node)
-		*max_rate = min(*max_rate, clk_user->max_rate);
+		hlist_for_each_entry(clk_user, &core->clks, clks_node)
+			*max_rate = min(*max_rate, clk_user->max_rate);
+	}
+
+	if (min_phase && max_phase) {
+		*min_phase = core->min_phase;
+		*max_phase = core->max_phase;
+	}
 }
 
 void clk_hw_set_rate_range(struct clk_hw *hw, unsigned long min_rate,
@@ -845,7 +856,8 @@ unsigned long clk_hw_round_rate(struct clk_hw *hw, unsigned long rate)
 	int ret;
 	struct clk_rate_request req;
 
-	clk_core_get_boundaries(hw->core, &req.min_rate, &req.max_rate);
+	clk_core_get_boundaries(hw->core, &req.min_rate, &req.max_rate,
+				NULL, NULL);
 	req.rate = rate;
 
 	ret = clk_core_round_rate_nolock(hw->core, &req);
@@ -875,7 +887,8 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
 
 	clk_prepare_lock();
 
-	clk_core_get_boundaries(clk->core, &req.min_rate, &req.max_rate);
+	clk_core_get_boundaries(clk->core, &req.min_rate, &req.max_rate,
+				NULL, NULL);
 	req.rate = rate;
 
 	ret = clk_core_round_rate_nolock(clk->core, &req);
@@ -888,6 +901,106 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
 }
 EXPORT_SYMBOL_GPL(clk_round_rate);
 
+static int clk_core_round_phase_nolock(struct clk_core *core,
+				      struct clk_phase_request *req)
+{
+	long phase;
+
+	lockdep_assert_held(&prepare_lock);
+
+	if (!core)
+		return 0;
+
+	/* sanity check  */
+	req->phase %= 360;
+	if (req->phase < 0)
+		req->phase += 360;
+
+	if (core->ops->determine_phase) {
+		return core->ops->determine_phase(core->hw, req);
+	} else if (core->ops->round_phase) {
+		phase = core->ops->round_phase(core->hw, req->phase);
+		if (phase < 0)
+			return phase;
+
+		req->phase = phase;
+	}
+
+	return 0;
+}
+
+/**
+ * __clk_determine_phase - get the closest phase actually supported by a clock
+ * @hw: determine the phase of this clock
+ * @phase: target rate
+ * @min_phase: returned phase must be greater than this phase
+ * @max_phase: returned phase must be less than this phase
+ *
+ * Useful for clk_ops such as .set_phase and .determine_phase.
+ */
+int __clk_determine_phase(struct clk_hw *hw, struct clk_phase_request *req)
+{
+	if (!hw) {
+		req->phase = 0;
+		return 0;
+	}
+
+	return clk_core_round_phase_nolock(hw->core, req);
+}
+EXPORT_SYMBOL_GPL(__clk_determine_phase);
+
+unsigned long clk_hw_round_phase(struct clk_hw *hw, int phase)
+{
+	int ret;
+	struct clk_phase_request req;
+
+	clk_core_get_boundaries(hw->core, NULL, NULL,
+				&req.min_phase, &req.max_phase);
+
+	req.phase = phase;
+
+	ret = clk_core_round_phase_nolock(hw->core, &req);
+	if (ret)
+		return 0;
+
+	return req.phase;
+}
+EXPORT_SYMBOL_GPL(clk_hw_round_phase);
+
+/**
+ * clk_round_phase - round the given phase for a clk
+ * @clk: the clk for which we are rounding a phase
+ * @phase: the phase which is to be rounded
+ *
+ * Takes in a phase as input and rounds it to a phase that the clk can actually
+ * use which is then returned.  If clk doesn't support round_phase operation
+ * then the requested phase is returned.
+ */
+long clk_round_phase(struct clk *clk, int phase)
+{
+	struct clk_phase_request req;
+	int ret;
+
+	if (!clk)
+		return 0;
+
+	clk_prepare_lock();
+
+	clk_core_get_boundaries(clk->core, NULL, NULL,
+				&req.min_phase, &req.max_phase);
+	req.phase = phase;
+
+	ret = clk_core_round_phase_nolock(clk->core, &req);
+	clk_prepare_unlock();
+
+	if (ret)
+		return ret;
+
+	return req.phase;
+}
+EXPORT_SYMBOL_GPL(clk_round_phase);
+
+
 /**
  * __clk_notify - call clk notifier chain
  * @core: clk that is changing rate
@@ -1312,7 +1425,8 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core,
 	if (parent)
 		best_parent_rate = parent->rate;
 
-	clk_core_get_boundaries(core, &min_rate, &max_rate);
+	clk_core_get_boundaries(core, &min_rate, &max_rate,
+				NULL, NULL);
 
 	/* find the closest rate and parent clk/rate */
 	if (core->ops->determine_rate) {
@@ -2443,6 +2557,10 @@ static int __clk_init(struct device *dev, struct clk *clk_user)
 	else
 		core->phase = 0;
 
+	/* Set phase range from 0 to 360 by default */
+	core->min_phase = 0;
+	core->max_phase = 360;
+
 	/*
 	 * Set clk's rate.  The preferred method is to use .recalc_rate.  For
 	 * simple clocks and lazy developers the default fallback is to use the
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 1143e38..f7e58ae 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -61,6 +61,23 @@ struct clk_rate_request {
 };
 
 /**
+ * struct clk_phase_request - Structure encoding the clk constraints that
+ * a clock user might require.
+ *
+ * @phase:		Requested clock phase. This field will be adjusted by
+ *			clock drivers according to hardware capabilities.
+ * @min_phase:		Minimum phase imposed by clk users.
+ * @max_phase:		Maximum phase imposed by clk users.
+ *
+ */
+struct clk_phase_request {
+	int phase;
+	unsigned long min_phase;
+	unsigned long max_phase;
+};
+
+
+/**
  * struct clk_ops -  Callback operations for hardware clocks; these are to
  * be provided by the clock implementation, and will be called by drivers
  * through the clk_* api.
@@ -212,6 +229,9 @@ struct clk_ops {
 					   unsigned long parent_accuracy);
 	int		(*get_phase)(struct clk_hw *hw);
 	int		(*set_phase)(struct clk_hw *hw, int degrees);
+	int		(*round_phase)(struct clk_hw *hw, int degrees);
+	int		(*determine_phase)(struct clk_hw *hw,
+					  struct clk_phase_request *req);
 	void		(*init)(struct clk_hw *hw);
 	int		(*debug_init)(struct clk_hw *hw, struct dentry *dentry);
 };
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 0df4a51..105cae0 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -325,6 +325,29 @@ void devm_clk_put(struct device *dev, struct clk *clk);
 long clk_round_rate(struct clk *clk, unsigned long rate);
 
 /**
+ * clk_round_phase - adjust a phase to the exact phase a clock can provide
+ * @clk: clock source
+ * @phase: desired clock phase in degrees
+ *
+ * This answers the question "if I were to pass @phase to clk_set_phase(),
+ * what clock phase would I end up with?" without changing the hardware
+ * in any way.  In other words:
+ *
+ *   phase = clk_round_phase(clk, p);
+ *
+ * and:
+ *
+ *   clk_set_phase(clk, p);
+ *   phase = clk_get_phase(clk);
+ *
+ * are equivalent except the former does not modify the clock hardware
+ * in any way.
+ *
+ * Returns rounded clock phase in degrees, or negative errno.
+ */
+long clk_round_phase(struct clk *clk, int phase);
+
+/**
  * clk_set_rate - set the clock rate for a clock source
  * @clk: clock source
  * @rate: desired clock rate in Hz
-- 
2.3.7


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ