From: Quanyang Wang <quanyang.w...@windriver.com>

This patch reverts the commit c249ef9d0978a ("drivers: clk: zynqmp:
update divider round rate logic").

This is because that there has been a similar commit efe0d3640f6ff
("drivers: clk: zynqmp: update divider round rate logic") which is
picked from SDK. This commit introduces some problem and the SDK patch
7e6654b576a00 ("drivers: clk: zynqmp: add hack to use old algorithm
for divider round rate") is to fix it. But when merging, the content of
the commit 7e6654b576a00 is missing. So we need to revert the commit
c249ef9d0978a and bring the content of the commit 7e6654b576a00 back.

Signed-off-by: Quanyang Wang <quanyang.w...@windriver.com>
---
Hi Bruce,
Would you please help merge this patch to the branches:
        v6.1/standard/preempt-rt/sdkv6.1/xlnx-soc
        v6.1/standard/sdkv6.1/xlnx-soc
Thanks,
Quanyang
---
 drivers/clk/zynqmp/divider.c | 88 ++++++++++++++++++++++++++++++++++--
 1 file changed, 83 insertions(+), 5 deletions(-)

diff --git a/drivers/clk/zynqmp/divider.c b/drivers/clk/zynqmp/divider.c
index a491f19ef7f8b..0ed124ba0ea6b 100644
--- a/drivers/clk/zynqmp/divider.c
+++ b/drivers/clk/zynqmp/divider.c
@@ -111,6 +111,51 @@ static unsigned long zynqmp_clk_divider_recalc_rate(struct 
clk_hw *hw,
        return DIV_ROUND_UP_ULL(parent_rate, value);
 }
 
+static void zynqmp_get_divider2_val(struct clk_hw *hw, unsigned long rate,
+                                   struct zynqmp_clk_divider *divider,
+                                   u32 *bestdiv)
+{
+       int div1;
+       int div2;
+       long error = LONG_MAX;
+       unsigned long div1_prate;
+       struct clk_hw *div1_parent_hw;
+       struct zynqmp_clk_divider *pdivider;
+       struct clk_hw *div2_parent_hw = clk_hw_get_parent(hw);
+
+       if (!div2_parent_hw)
+               return;
+
+       pdivider = to_zynqmp_clk_divider(div2_parent_hw);
+       if (!pdivider)
+               return;
+
+       div1_parent_hw = clk_hw_get_parent(div2_parent_hw);
+       if (!div1_parent_hw)
+               return;
+
+       div1_prate = clk_hw_get_rate(div1_parent_hw);
+       *bestdiv = 1;
+       for (div1 = 1; div1 <= pdivider->max_div;) {
+               for (div2 = 1; div2 <= divider->max_div;) {
+                       long new_error = ((div1_prate / div1) / div2) - rate;
+
+                       if (abs(new_error) < abs(error)) {
+                               *bestdiv = div2;
+                               error = new_error;
+                       }
+                       if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+                               div2 = div2 << 1;
+                       else
+                               div2++;
+               }
+               if (pdivider->flags & CLK_DIVIDER_POWER_OF_TWO)
+                       div1 = div1 << 1;
+               else
+                       div1++;
+       }
+}
+
 /**
  * zynqmp_clk_divider_round_rate() - Round rate of divider clock
  * @hw:                        handle between common and hardware-specific 
interfaces
@@ -129,7 +174,8 @@ static long zynqmp_clk_divider_round_rate(struct clk_hw *hw,
        u32 div_type = divider->div_type;
        u32 bestdiv;
        int ret;
-       u8 width = 0;
+       u8 width;
+       struct device_node *np;
 
        /* if read only, just return current value */
        if (divider->flags & CLK_DIVIDER_READ_ONLY) {
@@ -149,12 +195,44 @@ static long zynqmp_clk_divider_round_rate(struct clk_hw 
*hw,
                return DIV_ROUND_UP_ULL((u64)*prate, bestdiv);
        }
 
-       width = fls(divider->max_div);
+       /*
+        * Hack to use old algorithm for round rate div clocks. Currently PL
+        * rate is getting changed because RPLL_TO_FPD clock is changing RPLL
+        * rate for DP audio driver. Using old algorithm RPLL rate change is
+        * less and its not affecting PL clocks more so as a temporary solution
+        * use old algorithm for Versal and ZynqMP platforms.
+        *
+        * TBD: Remove this hack and use new algorithm for all platform once PL
+        * clock issue is fixed with better way.
+        */
+       np = of_find_compatible_node(NULL, NULL, "xlnx,versal-net");
+       if (np) {
+               width = fls(divider->max_div);
 
-       rate = divider_round_rate(hw, rate, prate, NULL, width, divider->flags);
+               rate = divider_round_rate(hw, rate, prate, NULL, width, 
divider->flags);
 
-       if (divider->is_frac && (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && 
(rate % *prate))
-               *prate = rate;
+               if (divider->is_frac && (clk_hw_get_flags(hw) & 
CLK_SET_RATE_PARENT) &&
+                   (rate % *prate))
+                       *prate = rate;
+       } else {
+               bestdiv = zynqmp_divider_get_val(*prate, rate, divider->flags);
+
+               /*
+                * In case of two divisors, compute best divider values and 
return
+                * divider2 value based on compute value. div1 will  be 
automatically
+                * set to optimum based on required total divider value.
+                */
+               if (div_type == TYPE_DIV2 && (clk_hw_get_flags(hw) &
+                   CLK_SET_RATE_PARENT))
+                       zynqmp_get_divider2_val(hw, rate, divider, &bestdiv);
+
+               if ((clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) &&
+                   divider->is_frac)
+                       bestdiv = rate % *prate ? 1 : bestdiv;
+
+               bestdiv = min_t(u32, bestdiv, divider->max_div);
+               *prate = rate * bestdiv;
+       }
 
        return rate;
 }
-- 
2.36.1

-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#14133): 
https://lists.yoctoproject.org/g/linux-yocto/message/14133
Mute This Topic: https://lists.yoctoproject.org/mt/107138006/21656
Group Owner: linux-yocto+ow...@lists.yoctoproject.org
Unsubscribe: https://lists.yoctoproject.org/g/linux-yocto/unsub 
[arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to