[4/7] clk: zynqmp: Add support for get max divider
diff mbox series

Message ID 1573564580-9006-5-git-send-email-rajan.vaja@xilinx.com
State New
Headers show
Series
  • clk: zynqmp: Extend and fix zynqmp clock driver
Related show

Commit Message

Rajan Vaja Nov. 12, 2019, 1:16 p.m. UTC
To achieve best possible rate, maximum limit of divider is required
while computation. Get maximum supported divisor from firmware. To
maintain backward compatibility assign maximum possible value(0xFFFF)
if query for max divisor is not successful.

Signed-off-by: Rajan Vaja <rajan.vaja@xilinx.com>
---
 drivers/clk/zynqmp/divider.c         | 19 +++++++++++++++++++
 include/linux/firmware/xlnx-zynqmp.h |  1 +
 2 files changed, 20 insertions(+)

Comments

Michael Tretter Nov. 21, 2019, 2:33 p.m. UTC | #1
On Tue, 12 Nov 2019 05:16:17 -0800, Rajan Vaja wrote:
> To achieve best possible rate, maximum limit of divider is required
> while computation. Get maximum supported divisor from firmware. To
> maintain backward compatibility assign maximum possible value(0xFFFF)
> if query for max divisor is not successful.
> 
> Signed-off-by: Rajan Vaja <rajan.vaja@xilinx.com>
> ---
>  drivers/clk/zynqmp/divider.c         | 19 +++++++++++++++++++
>  include/linux/firmware/xlnx-zynqmp.h |  1 +
>  2 files changed, 20 insertions(+)
> 
> diff --git a/drivers/clk/zynqmp/divider.c b/drivers/clk/zynqmp/divider.c
> index d8f5b70d..b79cd45 100644
> --- a/drivers/clk/zynqmp/divider.c
> +++ b/drivers/clk/zynqmp/divider.c
> @@ -41,6 +41,7 @@ struct zynqmp_clk_divider {
>  	bool is_frac;
>  	u32 clk_id;
>  	u32 div_type;
> +	u16 max_div;
>  };
>  
>  static inline int zynqmp_divider_get_val(unsigned long parent_rate,
> @@ -195,6 +196,9 @@ struct clk_hw *zynqmp_clk_register_divider(const char *name,
>  	struct clk_hw *hw;
>  	struct clk_init_data init;
>  	int ret;
> +	const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
> +	struct zynqmp_pm_query_data qdata = {0};
> +	u32 ret_payload[PAYLOAD_ARG_CNT];
>  
>  	/* allocate the divider */
>  	div = kzalloc(sizeof(*div), GFP_KERNEL);
> @@ -215,6 +219,21 @@ struct clk_hw *zynqmp_clk_register_divider(const char *name,
>  	div->clk_id = clk_id;
>  	div->div_type = nodes->type;
>  
> +	/*
> +	 * To achieve best possible rate, maximum limit of divider is required
> +	 * while computation. Get maximum supported divisor from firmware. To
> +	 * maintain backward compatibility assign maximum possible value(0xFFFF)
> +	 * if query for max divisor is not successful.
> +	 */
> +	qdata.qid = PM_QID_CLOCK_GET_MAX_DIVISOR;
> +	qdata.arg1 = clk_id;
> +	qdata.arg2 = nodes->type;
> +	ret = eemi_ops->query_data(qdata, ret_payload);
> +	if (ret)
> +		div->max_div = U16_MAX;
> +	else
> +		div->max_div = ret_payload[1];

Add a helper function for retrieving the max divisor. The clk_register
function should really not be mixed with code to access the firmware.

Michael

> +
>  	hw = &div->hw;
>  	ret = clk_hw_register(NULL, hw);
>  	if (ret) {
> diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h
> index f019d1c..f0d4558 100644
> --- a/include/linux/firmware/xlnx-zynqmp.h
> +++ b/include/linux/firmware/xlnx-zynqmp.h
> @@ -114,6 +114,7 @@ enum pm_query_id {
>  	PM_QID_CLOCK_GET_PARENTS,
>  	PM_QID_CLOCK_GET_ATTRIBUTES,
>  	PM_QID_CLOCK_GET_NUM_CLOCKS = 12,
> +	PM_QID_CLOCK_GET_MAX_DIVISOR,
>  };
>  
>  enum zynqmp_pm_reset_action {

Patch
diff mbox series

diff --git a/drivers/clk/zynqmp/divider.c b/drivers/clk/zynqmp/divider.c
index d8f5b70d..b79cd45 100644
--- a/drivers/clk/zynqmp/divider.c
+++ b/drivers/clk/zynqmp/divider.c
@@ -41,6 +41,7 @@  struct zynqmp_clk_divider {
 	bool is_frac;
 	u32 clk_id;
 	u32 div_type;
+	u16 max_div;
 };
 
 static inline int zynqmp_divider_get_val(unsigned long parent_rate,
@@ -195,6 +196,9 @@  struct clk_hw *zynqmp_clk_register_divider(const char *name,
 	struct clk_hw *hw;
 	struct clk_init_data init;
 	int ret;
+	const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+	struct zynqmp_pm_query_data qdata = {0};
+	u32 ret_payload[PAYLOAD_ARG_CNT];
 
 	/* allocate the divider */
 	div = kzalloc(sizeof(*div), GFP_KERNEL);
@@ -215,6 +219,21 @@  struct clk_hw *zynqmp_clk_register_divider(const char *name,
 	div->clk_id = clk_id;
 	div->div_type = nodes->type;
 
+	/*
+	 * To achieve best possible rate, maximum limit of divider is required
+	 * while computation. Get maximum supported divisor from firmware. To
+	 * maintain backward compatibility assign maximum possible value(0xFFFF)
+	 * if query for max divisor is not successful.
+	 */
+	qdata.qid = PM_QID_CLOCK_GET_MAX_DIVISOR;
+	qdata.arg1 = clk_id;
+	qdata.arg2 = nodes->type;
+	ret = eemi_ops->query_data(qdata, ret_payload);
+	if (ret)
+		div->max_div = U16_MAX;
+	else
+		div->max_div = ret_payload[1];
+
 	hw = &div->hw;
 	ret = clk_hw_register(NULL, hw);
 	if (ret) {
diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h
index f019d1c..f0d4558 100644
--- a/include/linux/firmware/xlnx-zynqmp.h
+++ b/include/linux/firmware/xlnx-zynqmp.h
@@ -114,6 +114,7 @@  enum pm_query_id {
 	PM_QID_CLOCK_GET_PARENTS,
 	PM_QID_CLOCK_GET_ATTRIBUTES,
 	PM_QID_CLOCK_GET_NUM_CLOCKS = 12,
+	PM_QID_CLOCK_GET_MAX_DIVISOR,
 };
 
 enum zynqmp_pm_reset_action {