All of lore.kernel.org
 help / color / mirror / Atom feed
From: James Kelly <jamespeterkelly@gmail.com>
To: Michal Simek <michal.simek@xilinx.com>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: driverdev-devel@linuxdriverproject.org
Subject: [PATCH 13/14] staging: clocking-wizard: Automatically set input clock rate
Date: Mon,  7 May 2018 11:20:39 +1000	[thread overview]
Message-ID: <20180507012040.18187-14-jamespeterkelly@gmail.com> (raw)
In-Reply-To: <20180507012040.18187-1-jamespeterkelly@gmail.com>

Allow CLK_SET_RATE_PARENT to be optionally enabled on first divider clock.
This has the potential to set the rate of one output clock with more
precision.  On Zynq-7000 this is typically achieved using a PS FCLK as
input to the Clocking Wizard IP.

This feature is enabled by the optional device-tree property
"set-input-rate-range".  The presence of this property in the device tree
enables the feature.  This feature is only active if the
"set-parent-output" device-tree property is also present as it depends on
the feature enabled by that property.

The value of the "set-input-rate-range" allows the input rate to be
constrained to a narrower range than the hardware supports as this is
useful in some circumstances.

The input rate is then further constrained to ensure the PLL can always
lock when the input rate is changed.

Signed-off-by: James Kelly <jamespeterkelly@gmail.com>
---
 drivers/staging/clocking-wizard/TODO               |  1 -
 .../clocking-wizard/clk-xlnx-clock-wizard.c        | 89 +++++++++++++++++++++-
 drivers/staging/clocking-wizard/dt-binding.txt     |  4 +
 3 files changed, 89 insertions(+), 5 deletions(-)

diff --git a/drivers/staging/clocking-wizard/TODO b/drivers/staging/clocking-wizard/TODO
index bf7435c5b67e..2a563ca67cd2 100644
--- a/drivers/staging/clocking-wizard/TODO
+++ b/drivers/staging/clocking-wizard/TODO
@@ -1,7 +1,6 @@
 TODO:
 	- review arithmetic
 	  - overflow after multiplication?
-	- implement CLK_SET_RATE_PARENT to set input clock
 	- test on 64-bit ARM and Microblaze architectures.
 	- support clk_set_phase
 
diff --git a/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c b/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c
index f706c3d6496e..bb64da849d9b 100644
--- a/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c
+++ b/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c
@@ -356,6 +356,8 @@ struct clk_wzrd_clk_data {
  * @pll_locked:		Phase locked loop locked status regmap field
  * @reconfig:		Reconfiguration regmap field
  * @dev:		Handle to device
+ * @min_input:		Current minimum input rate to ensure PLL lock
+ * @max_input:		Current maximum input rate to ensure PLL lock
  * @clkout_data:	Array of output clock provider data
  */
 struct clk_wzrd {
@@ -373,6 +375,8 @@ struct clk_wzrd {
 	struct regmap_field		*pll_locked;
 	struct regmap_field		*reconfig;
 	struct device			*dev;
+	unsigned long			min_input;
+	unsigned long			max_input;
 	struct clk_wzrd_clk_data	clkout_data[0];
 };
 #define to_clk_wzrd(_nb) container_of(_nb, struct clk_wzrd, nb)
@@ -529,6 +533,15 @@ static bool clk_wzrd_best_parent_rate(struct clk_wzrd_clk_data *cwc,
 	unsigned long inc = cwc->flags & WZRD_FLAG_FRAC ? 1 :
 			BIT(WZRD_FRAC_BITS);
 
+	/*
+	 * Apply extra constraint to ensure PLL lock when looking for the
+	 * best rate at the input of the Clocking Wizard IP.
+	 */
+	if (cwc == &cwc->cw->div_data) {
+		min_parent_rate = cwc->cw->min_input;
+		max_parent_rate = cwc->cw->max_input;
+	}
+
 	/*
 	 * Search by testing parent rates that corresponds to all possible
 	 * ratios that are within our parent rate constraints.
@@ -594,6 +607,30 @@ static int clk_wzrd_determine_rate(struct clk_hw *hw,
 	return 0;
 }
 
+static void clk_wzrd_update_input_constraint(struct clk_wzrd *cw)
+{
+	unsigned long min_pfd, max_pfd;
+	struct clk_wzrd_clk_data *out_cwc = &cw->clkout_data[0];
+	struct clk_wzrd_clk_data *pll_cwc = &cw->pll_data;
+	struct clk_wzrd_clk_data *div_cwc = &cw->div_data;
+	unsigned long current_pll_ratio = clk_wzrd_get_ratio(pll_cwc);
+	unsigned long current_div_ratio = clk_wzrd_get_ratio(div_cwc);
+
+	min_pfd = max(clk_wzrd_parent_rate(pll_cwc, out_cwc->min_parent,
+					   current_pll_ratio),
+		      pll_cwc->min_parent);
+	max_pfd = min(clk_wzrd_parent_rate(pll_cwc, out_cwc->max_parent,
+					   current_pll_ratio),
+		      pll_cwc->max_parent);
+
+	cw->min_input = max(clk_wzrd_parent_rate(div_cwc, min_pfd,
+						 current_div_ratio),
+			    div_cwc->min_parent);
+	cw->max_input = min(clk_wzrd_parent_rate(div_cwc, max_pfd,
+						 current_div_ratio),
+			    div_cwc->max_parent);
+}
+
 static bool clk_wzrd_set_ratio(struct clk_wzrd_clk_data *cwc,
 			       unsigned long parent_rate,
 			       unsigned long rate)
@@ -716,6 +753,9 @@ static int clk_wzrd_set_rate(struct clk_hw *hw, unsigned long req_rate,
 	if (!reconfigure)
 		return 0;
 
+	if (cwc == &cw->div_data || cwc == &cw->pll_data)
+		clk_wzrd_update_input_constraint(cw);
+
 	return clk_wzrd_reconfigure(cw);
 }
 
@@ -779,6 +819,18 @@ static int clk_wzrd_debug_init(struct clk_hw *hw, struct dentry *dentry)
 	if (IS_ERR(d))
 		return PTR_ERR(d);
 
+	if (cwc == &cwc->cw->div_data) {
+		d = debugfs_create_u32("clk_input_rate_min", 0444, dentry,
+				       (u32 *)&cwc->cw->min_input);
+		if (IS_ERR(d))
+			return PTR_ERR(d);
+
+		d = debugfs_create_u32("clk_input_rate_max", 0444, dentry,
+				       (u32 *)&cwc->cw->max_input);
+		if (IS_ERR(d))
+			return PTR_ERR(d);
+	}
+
 	d = debugfs_create_file_unsafe("clk_hw_flags", 0444, dentry, cwc,
 				       &clk_wzrd_flags_fops);
 	if (IS_ERR(d))
@@ -905,8 +957,8 @@ static int clk_wzrd_clk_notifier(struct notifier_block *nb, unsigned long event,
 		return NOTIFY_OK;
 
 	if (ndata->clk == cw->clk_in1) {
-		max = cw->chip->max[cw->speed_grade][WZRD_RATE_FIN];
-		min = cw->chip->min[WZRD_RATE_FIN];
+		max = cw->max_input;
+		min = cw->min_input;
 	} else if (ndata->clk == cw->axi_clk) {
 		max = WZRD_ACLK_MAX_FREQ;
 		min = 0;
@@ -1025,6 +1077,28 @@ static int clk_wzrd_get_device_tree_data(struct device *dev)
 				cw->chip->max[cw->speed_grade][WZRD_RATE_VCO];
 	}
 
+	if (of_find_property(node, "set-input-rate-range", NULL)) {
+		unsigned int rate;
+
+		ret = of_property_read_u32_index(node, "set-input-rate-range",
+						 0, &rate);
+		if (ret || rate < cw->div_data.min_parent ||
+		    rate > cw->div_data.max_parent) {
+			dev_err(dev, "Invalid set input minimum rate\n");
+			return -EINVAL;
+		}
+		cw->div_data.min_parent = rate;
+
+		ret = of_property_read_u32_index(node, "set-input-rate-range",
+						 1, &rate);
+		if (ret || rate < cw->div_data.min_parent ||
+		    rate > cw->div_data.max_parent) {
+			dev_err(dev, "Invalid set input maximum rate\n");
+			return -EINVAL;
+		}
+		cw->div_data.max_parent = rate;
+	}
+
 	cw->clk_in1 = devm_clk_get(dev, WZRD_CLKNAME_IN1);
 	if (IS_ERR(cw->clk_in1)) {
 		if (cw->clk_in1 != ERR_PTR(-EPROBE_DEFER))
@@ -1055,6 +1129,8 @@ static int clk_wzrd_get_device_tree_data(struct device *dev)
 		 clk_wzrd_family_name[family],
 		 clk_wzrd_type_name[type],
 		 cw->speed_grade + 1);
+	dev_info(dev, "Input rate range min: %lu max: %lu\n",
+		 cw->div_data.min_parent, cw->div_data.max_parent);
 
 	return 0;
 }
@@ -1095,7 +1171,7 @@ static int clk_wzrd_register_ccf(struct device *dev)
 	const char *clk_div_name;
 	const char *clk_pll_name;
 
-	unsigned long pll_flags = 0, out_flags = 0;
+	unsigned long div_flags = 0, pll_flags = 0, out_flags = 0;
 	struct clk_wzrd *cw = dev_get_drvdata(dev);
 
 	ret = of_property_read_u32(dev->of_node, "set-parent-output",
@@ -1107,10 +1183,13 @@ static int clk_wzrd_register_ccf(struct device *dev)
 			pll_flags = CLK_SET_RATE_PARENT;
 	}
 
+	if (of_find_property(dev->of_node, "set-input-rate-range", NULL))
+		div_flags = pll_flags;
 	clk_div_name = kasprintf(GFP_KERNEL, "%s_div", dev_name(dev));
 	if (!clk_div_name)
 		return -ENOMEM;
-	ret = clk_wzrd_register_clk(dev, clk_div_name, WZRD_CLK_DIV, 0, 0);
+	ret = clk_wzrd_register_clk(dev, clk_div_name, WZRD_CLK_DIV, 0,
+				    div_flags);
 	if (ret)
 		goto err_free_div_name;
 
@@ -1144,6 +1223,8 @@ static int clk_wzrd_register_ccf(struct device *dev)
 		cw->clkout[i] = cw->clkout_data[i].hw.clk;
 	}
 
+	clk_wzrd_update_input_constraint(cw);
+
 	cw->clk_data.clks = cw->clkout;
 	of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
 			    &cw->clk_data);
diff --git a/drivers/staging/clocking-wizard/dt-binding.txt b/drivers/staging/clocking-wizard/dt-binding.txt
index 37133a3f2ee9..9dfc4e71b489 100644
--- a/drivers/staging/clocking-wizard/dt-binding.txt
+++ b/drivers/staging/clocking-wizard/dt-binding.txt
@@ -26,6 +26,9 @@ Optional properties:
 	1 - PLL
  - set-parent-output: Set rate on this output can set parent rates
 	Valid values are 0..n-1, where n is number of clock outputs.
+ - set-input-rate-range: Set rate on set-parent-output can set input rate.
+	Array of two 32-bit values, where 1st element is minimum input rate
+	constraint and 2nd element is maximum input rate constraint.
 
 Example:
 	clock-generator@40040000 {
@@ -40,4 +43,5 @@ Example:
 		xlnx,family = <0>;
 		xlnx,primitive = <0>;
 		set-parent-output <0>;
+		set-input-rate-range <10000000 80000000>;
 	};
-- 
2.15.1 (Apple Git-101)

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

  parent reply	other threads:[~2018-05-07  1:22 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-05-07  1:20 [PATCH 00/14] staging: clocking-wizard: Implement many TODOs James Kelly
2018-05-07  1:20 ` [PATCH 01/14] staging: clocking-wizard: Add principles of operation James Kelly
2018-05-11  6:04   ` Michal Simek
2018-05-11  7:31     ` James Kelly
2018-05-11  7:59       ` Michal Simek
2018-05-14 13:36     ` Dan Carpenter
2018-05-07  1:20 ` [PATCH 02/14] staging: clocking-wizard: Reverse order of internal clocks James Kelly
2018-05-07  1:20 ` [PATCH 03/14] staging: clocking-wizard: Split probe function James Kelly
2018-05-14 13:47   ` Dan Carpenter
2018-05-14 14:47     ` Dan Carpenter
2018-05-14 19:30     ` James Kelly
2018-05-15  7:42       ` Dan Carpenter
2018-05-07  1:20 ` [PATCH 04/14] staging: clocking-wizard: Cosmetic cleanups James Kelly
2018-05-07  1:20 ` [PATCH 05/14] staging: clocking-wizard: Implement CCF clock provider James Kelly
2018-05-11  6:06   ` Michal Simek
2018-05-11  7:58     ` James Kelly
2018-05-11  8:05       ` Michal Simek
2018-05-07  1:20 ` [PATCH 06/14] staging: clocking-wizard: Swap CCF clock providers James Kelly
2018-05-11  6:21   ` Michal Simek
2018-05-11  6:24   ` Michal Simek
2018-05-07  1:20 ` [PATCH 07/14] staging: clocking-wizard: Add hardware constaints James Kelly
2018-05-07  1:20 ` [PATCH 08/14] staging: clocking-wizard: Support fractional ratios James Kelly
2018-05-07  5:00   ` kbuild test robot
2018-05-07  1:20 ` [PATCH 09/14] staging: clocking-wizard: Provide more information in debugfs James Kelly
2018-05-11  6:27   ` Michal Simek
2018-05-07  1:20 ` [PATCH 10/14] staging: clocking-wizard: Support clk_round_rate James Kelly
2018-05-11  6:31   ` Michal Simek
2018-05-15  7:52   ` Dan Carpenter
2018-05-15  7:56     ` Greg Kroah-Hartman
2018-05-07  1:20 ` [PATCH 11/14] staging: clocking-wizard: Support clk_set_rate James Kelly
2018-05-11  6:33   ` Michal Simek
2018-05-07  1:20 ` [PATCH 12/14] staging: clocking-wizard: Automatically set internal clock rates James Kelly
2018-05-07  1:20 ` James Kelly [this message]
2018-05-07  1:20 ` [PATCH 14/14] staging: clocking-wizard: Add debugfs entries to facilitate testing James Kelly
2018-05-14 12:02 ` [PATCH 00/14] staging: clocking-wizard: Implement many TODOs Greg Kroah-Hartman
2018-05-14 19:32   ` James Kelly

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180507012040.18187-14-jamespeterkelly@gmail.com \
    --to=jamespeterkelly@gmail.com \
    --cc=driverdev-devel@linuxdriverproject.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=michal.simek@xilinx.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.