Skip to content

Commit 1fe15be

Browse files
jbuddhabbebarino
authored andcommitted
drivers: clk: zynqmp: update divider round rate logic
Currently zynqmp divider round rate is considering single parent and calculating rate and parent rate accordingly. But if divider clock flag is set to SET_RATE_PARENT then its not trying to traverse through all parent rate and not selecting best parent rate from that. So use common divider_round_rate() which is traversing through all clock parents and its rate and calculating proper parent rate. Fixes: 3fde0e1 ("drivers: clk: Add ZynqMP clock driver") Signed-off-by: Jay Buddhabhatti <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Stephen Boyd <[email protected]>
1 parent b782921 commit 1fe15be

File tree

1 file changed

+5
-61
lines changed

1 file changed

+5
-61
lines changed

drivers/clk/zynqmp/divider.c

Lines changed: 5 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -110,52 +110,6 @@ static unsigned long zynqmp_clk_divider_recalc_rate(struct clk_hw *hw,
110110
return DIV_ROUND_UP_ULL(parent_rate, value);
111111
}
112112

113-
static void zynqmp_get_divider2_val(struct clk_hw *hw,
114-
unsigned long rate,
115-
struct zynqmp_clk_divider *divider,
116-
u32 *bestdiv)
117-
{
118-
int div1;
119-
int div2;
120-
long error = LONG_MAX;
121-
unsigned long div1_prate;
122-
struct clk_hw *div1_parent_hw;
123-
struct zynqmp_clk_divider *pdivider;
124-
struct clk_hw *div2_parent_hw = clk_hw_get_parent(hw);
125-
126-
if (!div2_parent_hw)
127-
return;
128-
129-
pdivider = to_zynqmp_clk_divider(div2_parent_hw);
130-
if (!pdivider)
131-
return;
132-
133-
div1_parent_hw = clk_hw_get_parent(div2_parent_hw);
134-
if (!div1_parent_hw)
135-
return;
136-
137-
div1_prate = clk_hw_get_rate(div1_parent_hw);
138-
*bestdiv = 1;
139-
for (div1 = 1; div1 <= pdivider->max_div;) {
140-
for (div2 = 1; div2 <= divider->max_div;) {
141-
long new_error = ((div1_prate / div1) / div2) - rate;
142-
143-
if (abs(new_error) < abs(error)) {
144-
*bestdiv = div2;
145-
error = new_error;
146-
}
147-
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
148-
div2 = div2 << 1;
149-
else
150-
div2++;
151-
}
152-
if (pdivider->flags & CLK_DIVIDER_POWER_OF_TWO)
153-
div1 = div1 << 1;
154-
else
155-
div1++;
156-
}
157-
}
158-
159113
/**
160114
* zynqmp_clk_divider_round_rate() - Round rate of divider clock
161115
* @hw: handle between common and hardware-specific interfaces
@@ -174,6 +128,7 @@ static long zynqmp_clk_divider_round_rate(struct clk_hw *hw,
174128
u32 div_type = divider->div_type;
175129
u32 bestdiv;
176130
int ret;
131+
u8 width;
177132

178133
/* if read only, just return current value */
179134
if (divider->flags & CLK_DIVIDER_READ_ONLY) {
@@ -193,23 +148,12 @@ static long zynqmp_clk_divider_round_rate(struct clk_hw *hw,
193148
return DIV_ROUND_UP_ULL((u64)*prate, bestdiv);
194149
}
195150

196-
bestdiv = zynqmp_divider_get_val(*prate, rate, divider->flags);
197-
198-
/*
199-
* In case of two divisors, compute best divider values and return
200-
* divider2 value based on compute value. div1 will be automatically
201-
* set to optimum based on required total divider value.
202-
*/
203-
if (div_type == TYPE_DIV2 &&
204-
(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
205-
zynqmp_get_divider2_val(hw, rate, divider, &bestdiv);
206-
}
151+
width = fls(divider->max_div);
207152

208-
if ((clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && divider->is_frac)
209-
bestdiv = rate % *prate ? 1 : bestdiv;
153+
rate = divider_round_rate(hw, rate, prate, NULL, width, divider->flags);
210154

211-
bestdiv = min_t(u32, bestdiv, divider->max_div);
212-
*prate = rate * bestdiv;
155+
if (divider->is_frac && (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && (rate % *prate))
156+
*prate = rate;
213157

214158
return rate;
215159
}

0 commit comments

Comments
 (0)