Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: 3fde0e16d016 ("drivers: clk: Add ZynqMP clock driver")
Signed-off-by: Jay Buddhabhatti <jay.buddhabhatti@amd.com>
Link: https://lore.kernel.org/r/20231129112916.23125-3-jay.buddhabhatti@amd.com
Signed-off-by: Stephen Boyd <sboyd@kernel.org>

authored by

Jay Buddhabhatti and committed by
Stephen Boyd
1fe15be1 b782921d

+5 -61
+5 -61
drivers/clk/zynqmp/divider.c
··· 110 110 return DIV_ROUND_UP_ULL(parent_rate, value); 111 111 } 112 112 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 - 159 113 /** 160 114 * zynqmp_clk_divider_round_rate() - Round rate of divider clock 161 115 * @hw: handle between common and hardware-specific interfaces ··· 128 174 u32 div_type = divider->div_type; 129 175 u32 bestdiv; 130 176 int ret; 177 + u8 width; 131 178 132 179 /* if read only, just return current value */ 133 180 if (divider->flags & CLK_DIVIDER_READ_ONLY) { ··· 148 193 return DIV_ROUND_UP_ULL((u64)*prate, bestdiv); 149 194 } 150 195 151 - bestdiv = zynqmp_divider_get_val(*prate, rate, divider->flags); 196 + width = fls(divider->max_div); 152 197 153 - /* 154 - * In case of two divisors, compute best divider values and return 155 - * divider2 value based on compute value. div1 will be automatically 156 - * set to optimum based on required total divider value. 157 - */ 158 - if (div_type == TYPE_DIV2 && 159 - (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) { 160 - zynqmp_get_divider2_val(hw, rate, divider, &bestdiv); 161 - } 198 + rate = divider_round_rate(hw, rate, prate, NULL, width, divider->flags); 162 199 163 - if ((clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && divider->is_frac) 164 - bestdiv = rate % *prate ? 1 : bestdiv; 165 - 166 - bestdiv = min_t(u32, bestdiv, divider->max_div); 167 - *prate = rate * bestdiv; 200 + if (divider->is_frac && (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && (rate % *prate)) 201 + *prate = rate; 168 202 169 203 return rate; 170 204 }