]> www.infradead.org Git - users/hch/misc.git/commitdiff
clk: xilinx: Optimize divisor search in clk_wzrd_get_divisors_ver()
authorShubhrajyoti Datta <shubhrajyoti.datta@amd.com>
Tue, 29 Jul 2025 05:08:42 +0000 (10:38 +0530)
committerStephen Boyd <sboyd@kernel.org>
Sun, 21 Sep 2025 17:56:21 +0000 (10:56 -0700)
Optimise the clock wizard divisor calculation by eliminating the innermost
loop over output divider o. Earlier there was an error that is returned
if the WZRD_MIN_ERR is not achieved error is returned now it computes
the best possible frequency.

Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
drivers/clk/xilinx/clk-xlnx-clock-wizard.c

index 0295a13a811cf8e00fd49879eefc5bcf4fb89228..6af41d207ab5d63d1e2afc4d91aaf4ba2bf4aa9d 100644 (file)
@@ -340,7 +340,7 @@ static int clk_wzrd_get_divisors_ver(struct clk_hw *hw, unsigned long rate,
                                     unsigned long parent_rate)
 {
        struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw);
-       u64 vco_freq, freq, diff, vcomin, vcomax;
+       u64 vco_freq, freq, diff, vcomin, vcomax, best_diff = -1ULL;
        u32 m, d, o;
        u32 mmin, mmax, dmin, dmax, omin, omax;
 
@@ -356,22 +356,26 @@ static int clk_wzrd_get_divisors_ver(struct clk_hw *hw, unsigned long rate,
        for (m = mmin; m <= mmax; m++) {
                for (d = dmin; d <= dmax; d++) {
                        vco_freq = DIV_ROUND_CLOSEST((parent_rate * m), d);
-                       if (vco_freq >= vcomin && vco_freq <= vcomax) {
-                               for (o = omin; o <= omax; o++) {
-                                       freq = DIV_ROUND_CLOSEST_ULL(vco_freq, o);
-                                       diff = abs(freq - rate);
-
-                                       if (diff < WZRD_MIN_ERR) {
-                                               divider->m = m;
-                                               divider->d = d;
-                                               divider->o = o;
-                                               return 0;
-                                       }
-                               }
+                       if (vco_freq < vcomin || vco_freq > vcomax)
+                               continue;
+
+                       o = DIV_ROUND_CLOSEST_ULL(vco_freq, rate);
+                       if (o < omin || o > omax)
+                               continue;
+                       freq = DIV_ROUND_CLOSEST_ULL(vco_freq, o);
+                       diff = abs(freq - rate);
+
+                       if (diff < best_diff) {
+                               best_diff = diff;
+                               divider->m = m;
+                               divider->d = d;
+                               divider->o = o;
+                               if (!diff)
+                                       return 0;
                        }
                }
        }
-       return -EBUSY;
+       return 0;
 }
 
 static int clk_wzrd_get_divisors(struct clk_hw *hw, unsigned long rate,