10
10
#include "ccu_gate.h"
11
11
#include "ccu_mp.h"
12
12
13
+ static unsigned int next_div (unsigned int div , bool shift )
14
+ {
15
+ if (shift )
16
+ return div << 1 ;
17
+ return div + 1 ;
18
+ }
19
+
13
20
static unsigned long ccu_mp_find_best (unsigned long parent , unsigned long rate ,
14
21
unsigned int max_m , unsigned int max_p ,
22
+ bool shift ,
15
23
unsigned int * m , unsigned int * p )
16
24
{
17
25
unsigned long best_rate = 0 ;
18
26
unsigned int best_m = 0 , best_p = 0 ;
19
27
unsigned int _m , _p ;
20
28
21
- for (_p = 1 ; _p <= max_p ; _p <<= 1 ) {
29
+ for (_p = 1 ; _p <= max_p ; _p = next_div ( _p , shift ) ) {
22
30
for (_m = 1 ; _m <= max_m ; _m ++ ) {
23
31
unsigned long tmp_rate = parent / _p / _m ;
24
32
@@ -43,7 +51,8 @@ static unsigned long ccu_mp_find_best_with_parent_adj(struct clk_hw *hw,
43
51
unsigned long * parent ,
44
52
unsigned long rate ,
45
53
unsigned int max_m ,
46
- unsigned int max_p )
54
+ unsigned int max_p ,
55
+ bool shift )
47
56
{
48
57
unsigned long parent_rate_saved ;
49
58
unsigned long parent_rate , now ;
@@ -60,7 +69,7 @@ static unsigned long ccu_mp_find_best_with_parent_adj(struct clk_hw *hw,
60
69
maxdiv = max_m * max_p ;
61
70
maxdiv = min (ULONG_MAX / rate , maxdiv );
62
71
63
- for (_p = 1 ; _p <= max_p ; _p <<= 1 ) {
72
+ for (_p = 1 ; _p <= max_p ; _p = next_div ( _p , shift ) ) {
64
73
for (_m = 1 ; _m <= max_m ; _m ++ ) {
65
74
div = _m * _p ;
66
75
@@ -103,18 +112,26 @@ static unsigned long ccu_mp_round_rate(struct ccu_mux_internal *mux,
103
112
struct ccu_mp * cmp = data ;
104
113
unsigned int max_m , max_p ;
105
114
unsigned int m , p ;
115
+ bool shift = true;
106
116
107
117
if (cmp -> common .features & CCU_FEATURE_FIXED_POSTDIV )
108
118
rate *= cmp -> fixed_post_div ;
109
119
120
+ if (cmp -> common .features & CCU_FEATURE_DUAL_DIV )
121
+ shift = false;
122
+
110
123
max_m = cmp -> m .max ?: 1 << cmp -> m .width ;
111
- max_p = cmp -> p .max ?: 1 << ((1 << cmp -> p .width ) - 1 );
124
+ if (shift )
125
+ max_p = cmp -> p .max ?: 1 << ((1 << cmp -> p .width ) - 1 );
126
+ else
127
+ max_p = cmp -> p .max ?: 1 << cmp -> p .width ;
112
128
113
129
if (!clk_hw_can_set_rate_parent (& cmp -> common .hw )) {
114
- rate = ccu_mp_find_best (* parent_rate , rate , max_m , max_p , & m , & p );
130
+ rate = ccu_mp_find_best (* parent_rate , rate , max_m , max_p , shift ,
131
+ & m , & p );
115
132
} else {
116
133
rate = ccu_mp_find_best_with_parent_adj (hw , parent_rate , rate ,
117
- max_m , max_p );
134
+ max_m , max_p , shift );
118
135
}
119
136
120
137
if (cmp -> common .features & CCU_FEATURE_FIXED_POSTDIV )
@@ -167,7 +184,11 @@ static unsigned long ccu_mp_recalc_rate(struct clk_hw *hw,
167
184
p = reg >> cmp -> p .shift ;
168
185
p &= (1 << cmp -> p .width ) - 1 ;
169
186
170
- rate = (parent_rate >> p ) / m ;
187
+ if (cmp -> common .features & CCU_FEATURE_DUAL_DIV )
188
+ rate = (parent_rate / p ) / m ;
189
+ else
190
+ rate = (parent_rate >> p ) / m ;
191
+
171
192
if (cmp -> common .features & CCU_FEATURE_FIXED_POSTDIV )
172
193
rate /= cmp -> fixed_post_div ;
173
194
@@ -190,28 +211,38 @@ static int ccu_mp_set_rate(struct clk_hw *hw, unsigned long rate,
190
211
unsigned long flags ;
191
212
unsigned int max_m , max_p ;
192
213
unsigned int m , p ;
214
+ bool shift = true;
193
215
u32 reg ;
194
216
217
+ if (cmp -> common .features & CCU_FEATURE_DUAL_DIV )
218
+ shift = false;
219
+
195
220
/* Adjust parent_rate according to pre-dividers */
196
221
parent_rate = ccu_mux_helper_apply_prediv (& cmp -> common , & cmp -> mux , -1 ,
197
222
parent_rate );
198
223
199
224
max_m = cmp -> m .max ?: 1 << cmp -> m .width ;
200
- max_p = cmp -> p .max ?: 1 << ((1 << cmp -> p .width ) - 1 );
225
+ if (shift )
226
+ max_p = cmp -> p .max ?: 1 << ((1 << cmp -> p .width ) - 1 );
227
+ else
228
+ max_p = cmp -> p .max ?: 1 << cmp -> p .width ;
201
229
202
230
/* Adjust target rate according to post-dividers */
203
231
if (cmp -> common .features & CCU_FEATURE_FIXED_POSTDIV )
204
232
rate = rate * cmp -> fixed_post_div ;
205
233
206
- ccu_mp_find_best (parent_rate , rate , max_m , max_p , & m , & p );
234
+ ccu_mp_find_best (parent_rate , rate , max_m , max_p , shift , & m , & p );
207
235
208
236
spin_lock_irqsave (cmp -> common .lock , flags );
209
237
210
238
reg = readl (cmp -> common .base + cmp -> common .reg );
211
239
reg &= ~GENMASK (cmp -> m .width + cmp -> m .shift - 1 , cmp -> m .shift );
212
240
reg &= ~GENMASK (cmp -> p .width + cmp -> p .shift - 1 , cmp -> p .shift );
213
241
reg |= (m - cmp -> m .offset ) << cmp -> m .shift ;
214
- reg |= ilog2 (p ) << cmp -> p .shift ;
242
+ if (shift )
243
+ reg |= ilog2 (p ) << cmp -> p .shift ;
244
+ else
245
+ reg |= (p - cmp -> p .offset ) << cmp -> p .shift ;
215
246
216
247
writel (reg , cmp -> common .base + cmp -> common .reg );
217
248
0 commit comments