Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/arm/mach-omap2/clkt_dpll.c
10817 views
1
/*
2
* OMAP2/3/4 DPLL clock functions
3
*
4
* Copyright (C) 2005-2008 Texas Instruments, Inc.
5
* Copyright (C) 2004-2010 Nokia Corporation
6
*
7
* Contacts:
8
* Richard Woodruff <[email protected]>
9
* Paul Walmsley
10
*
11
* This program is free software; you can redistribute it and/or modify
12
* it under the terms of the GNU General Public License version 2 as
13
* published by the Free Software Foundation.
14
*/
15
#undef DEBUG
16
17
#include <linux/kernel.h>
18
#include <linux/errno.h>
19
#include <linux/clk.h>
20
#include <linux/io.h>
21
22
#include <asm/div64.h>
23
24
#include <plat/clock.h>
25
26
#include "clock.h"
27
#include "cm-regbits-24xx.h"
28
#include "cm-regbits-34xx.h"
29
30
/* DPLL rate rounding: minimum DPLL multiplier, divider values */
31
#define DPLL_MIN_MULTIPLIER 2
32
#define DPLL_MIN_DIVIDER 1
33
34
/* Possible error results from _dpll_test_mult */
35
#define DPLL_MULT_UNDERFLOW -1
36
37
/*
38
* Scale factor to mitigate roundoff errors in DPLL rate rounding.
39
* The higher the scale factor, the greater the risk of arithmetic overflow,
40
* but the closer the rounded rate to the target rate. DPLL_SCALE_FACTOR
41
* must be a power of DPLL_SCALE_BASE.
42
*/
43
#define DPLL_SCALE_FACTOR 64
44
#define DPLL_SCALE_BASE 2
45
#define DPLL_ROUNDING_VAL ((DPLL_SCALE_BASE / 2) * \
46
(DPLL_SCALE_FACTOR / DPLL_SCALE_BASE))
47
48
/* DPLL valid Fint frequency band limits - from 34xx TRM Section 4.7.6.2 */
49
#define DPLL_FINT_BAND1_MIN 750000
50
#define DPLL_FINT_BAND1_MAX 2100000
51
#define DPLL_FINT_BAND2_MIN 7500000
52
#define DPLL_FINT_BAND2_MAX 21000000
53
54
/* _dpll_test_fint() return codes */
55
#define DPLL_FINT_UNDERFLOW -1
56
#define DPLL_FINT_INVALID -2
57
58
/* Private functions */
59
60
/*
61
* _dpll_test_fint - test whether an Fint value is valid for the DPLL
62
* @clk: DPLL struct clk to test
63
* @n: divider value (N) to test
64
*
65
* Tests whether a particular divider @n will result in a valid DPLL
66
* internal clock frequency Fint. See the 34xx TRM 4.7.6.2 "DPLL Jitter
67
* Correction". Returns 0 if OK, -1 if the enclosing loop can terminate
68
* (assuming that it is counting N upwards), or -2 if the enclosing loop
69
* should skip to the next iteration (again assuming N is increasing).
70
*/
71
static int _dpll_test_fint(struct clk *clk, u8 n)
72
{
73
struct dpll_data *dd;
74
long fint;
75
int ret = 0;
76
77
dd = clk->dpll_data;
78
79
/* DPLL divider must result in a valid jitter correction val */
80
fint = clk->parent->rate / n;
81
if (fint < DPLL_FINT_BAND1_MIN) {
82
83
pr_debug("rejecting n=%d due to Fint failure, "
84
"lowering max_divider\n", n);
85
dd->max_divider = n;
86
ret = DPLL_FINT_UNDERFLOW;
87
88
} else if (fint > DPLL_FINT_BAND1_MAX &&
89
fint < DPLL_FINT_BAND2_MIN) {
90
91
pr_debug("rejecting n=%d due to Fint failure\n", n);
92
ret = DPLL_FINT_INVALID;
93
94
} else if (fint > DPLL_FINT_BAND2_MAX) {
95
96
pr_debug("rejecting n=%d due to Fint failure, "
97
"boosting min_divider\n", n);
98
dd->min_divider = n;
99
ret = DPLL_FINT_INVALID;
100
101
}
102
103
return ret;
104
}
105
106
static unsigned long _dpll_compute_new_rate(unsigned long parent_rate,
107
unsigned int m, unsigned int n)
108
{
109
unsigned long long num;
110
111
num = (unsigned long long)parent_rate * m;
112
do_div(num, n);
113
return num;
114
}
115
116
/*
117
* _dpll_test_mult - test a DPLL multiplier value
118
* @m: pointer to the DPLL m (multiplier) value under test
119
* @n: current DPLL n (divider) value under test
120
* @new_rate: pointer to storage for the resulting rounded rate
121
* @target_rate: the desired DPLL rate
122
* @parent_rate: the DPLL's parent clock rate
123
*
124
* This code tests a DPLL multiplier value, ensuring that the
125
* resulting rate will not be higher than the target_rate, and that
126
* the multiplier value itself is valid for the DPLL. Initially, the
127
* integer pointed to by the m argument should be prescaled by
128
* multiplying by DPLL_SCALE_FACTOR. The code will replace this with
129
* a non-scaled m upon return. This non-scaled m will result in a
130
* new_rate as close as possible to target_rate (but not greater than
131
* target_rate) given the current (parent_rate, n, prescaled m)
132
* triple. Returns DPLL_MULT_UNDERFLOW in the event that the
133
* non-scaled m attempted to underflow, which can allow the calling
134
* function to bail out early; or 0 upon success.
135
*/
136
static int _dpll_test_mult(int *m, int n, unsigned long *new_rate,
137
unsigned long target_rate,
138
unsigned long parent_rate)
139
{
140
int r = 0, carry = 0;
141
142
/* Unscale m and round if necessary */
143
if (*m % DPLL_SCALE_FACTOR >= DPLL_ROUNDING_VAL)
144
carry = 1;
145
*m = (*m / DPLL_SCALE_FACTOR) + carry;
146
147
/*
148
* The new rate must be <= the target rate to avoid programming
149
* a rate that is impossible for the hardware to handle
150
*/
151
*new_rate = _dpll_compute_new_rate(parent_rate, *m, n);
152
if (*new_rate > target_rate) {
153
(*m)--;
154
*new_rate = 0;
155
}
156
157
/* Guard against m underflow */
158
if (*m < DPLL_MIN_MULTIPLIER) {
159
*m = DPLL_MIN_MULTIPLIER;
160
*new_rate = 0;
161
r = DPLL_MULT_UNDERFLOW;
162
}
163
164
if (*new_rate == 0)
165
*new_rate = _dpll_compute_new_rate(parent_rate, *m, n);
166
167
return r;
168
}
169
170
/* Public functions */
171
172
void omap2_init_dpll_parent(struct clk *clk)
173
{
174
u32 v;
175
struct dpll_data *dd;
176
177
dd = clk->dpll_data;
178
if (!dd)
179
return;
180
181
v = __raw_readl(dd->control_reg);
182
v &= dd->enable_mask;
183
v >>= __ffs(dd->enable_mask);
184
185
/* Reparent the struct clk in case the dpll is in bypass */
186
if (cpu_is_omap24xx()) {
187
if (v == OMAP2XXX_EN_DPLL_LPBYPASS ||
188
v == OMAP2XXX_EN_DPLL_FRBYPASS)
189
clk_reparent(clk, dd->clk_bypass);
190
} else if (cpu_is_omap34xx()) {
191
if (v == OMAP3XXX_EN_DPLL_LPBYPASS ||
192
v == OMAP3XXX_EN_DPLL_FRBYPASS)
193
clk_reparent(clk, dd->clk_bypass);
194
} else if (cpu_is_omap44xx()) {
195
if (v == OMAP4XXX_EN_DPLL_LPBYPASS ||
196
v == OMAP4XXX_EN_DPLL_FRBYPASS ||
197
v == OMAP4XXX_EN_DPLL_MNBYPASS)
198
clk_reparent(clk, dd->clk_bypass);
199
}
200
return;
201
}
202
203
/**
204
* omap2_get_dpll_rate - returns the current DPLL CLKOUT rate
205
* @clk: struct clk * of a DPLL
206
*
207
* DPLLs can be locked or bypassed - basically, enabled or disabled.
208
* When locked, the DPLL output depends on the M and N values. When
209
* bypassed, on OMAP2xxx, the output rate is either the 32KiHz clock
210
* or sys_clk. Bypass rates on OMAP3 depend on the DPLL: DPLLs 1 and
211
* 2 are bypassed with dpll1_fclk and dpll2_fclk respectively
212
* (generated by DPLL3), while DPLL 3, 4, and 5 bypass rates are sys_clk.
213
* Returns the current DPLL CLKOUT rate (*not* CLKOUTX2) if the DPLL is
214
* locked, or the appropriate bypass rate if the DPLL is bypassed, or 0
215
* if the clock @clk is not a DPLL.
216
*/
217
u32 omap2_get_dpll_rate(struct clk *clk)
218
{
219
long long dpll_clk;
220
u32 dpll_mult, dpll_div, v;
221
struct dpll_data *dd;
222
223
dd = clk->dpll_data;
224
if (!dd)
225
return 0;
226
227
/* Return bypass rate if DPLL is bypassed */
228
v = __raw_readl(dd->control_reg);
229
v &= dd->enable_mask;
230
v >>= __ffs(dd->enable_mask);
231
232
if (cpu_is_omap24xx()) {
233
if (v == OMAP2XXX_EN_DPLL_LPBYPASS ||
234
v == OMAP2XXX_EN_DPLL_FRBYPASS)
235
return dd->clk_bypass->rate;
236
} else if (cpu_is_omap34xx()) {
237
if (v == OMAP3XXX_EN_DPLL_LPBYPASS ||
238
v == OMAP3XXX_EN_DPLL_FRBYPASS)
239
return dd->clk_bypass->rate;
240
} else if (cpu_is_omap44xx()) {
241
if (v == OMAP4XXX_EN_DPLL_LPBYPASS ||
242
v == OMAP4XXX_EN_DPLL_FRBYPASS ||
243
v == OMAP4XXX_EN_DPLL_MNBYPASS)
244
return dd->clk_bypass->rate;
245
}
246
247
v = __raw_readl(dd->mult_div1_reg);
248
dpll_mult = v & dd->mult_mask;
249
dpll_mult >>= __ffs(dd->mult_mask);
250
dpll_div = v & dd->div1_mask;
251
dpll_div >>= __ffs(dd->div1_mask);
252
253
dpll_clk = (long long)dd->clk_ref->rate * dpll_mult;
254
do_div(dpll_clk, dpll_div + 1);
255
256
return dpll_clk;
257
}
258
259
/* DPLL rate rounding code */
260
261
/**
262
* omap2_dpll_round_rate - round a target rate for an OMAP DPLL
263
* @clk: struct clk * for a DPLL
264
* @target_rate: desired DPLL clock rate
265
*
266
* Given a DPLL and a desired target rate, round the target rate to a
267
* possible, programmable rate for this DPLL. Attempts to select the
268
* minimum possible n. Stores the computed (m, n) in the DPLL's
269
* dpll_data structure so set_rate() will not need to call this
270
* (expensive) function again. Returns ~0 if the target rate cannot
271
* be rounded, or the rounded rate upon success.
272
*/
273
long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate)
274
{
275
int m, n, r, scaled_max_m;
276
unsigned long scaled_rt_rp;
277
unsigned long new_rate = 0;
278
struct dpll_data *dd;
279
280
if (!clk || !clk->dpll_data)
281
return ~0;
282
283
dd = clk->dpll_data;
284
285
pr_debug("clock: %s: starting DPLL round_rate, target rate %ld\n",
286
clk->name, target_rate);
287
288
scaled_rt_rp = target_rate / (dd->clk_ref->rate / DPLL_SCALE_FACTOR);
289
scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR;
290
291
dd->last_rounded_rate = 0;
292
293
for (n = dd->min_divider; n <= dd->max_divider; n++) {
294
295
/* Is the (input clk, divider) pair valid for the DPLL? */
296
r = _dpll_test_fint(clk, n);
297
if (r == DPLL_FINT_UNDERFLOW)
298
break;
299
else if (r == DPLL_FINT_INVALID)
300
continue;
301
302
/* Compute the scaled DPLL multiplier, based on the divider */
303
m = scaled_rt_rp * n;
304
305
/*
306
* Since we're counting n up, a m overflow means we
307
* can bail out completely (since as n increases in
308
* the next iteration, there's no way that m can
309
* increase beyond the current m)
310
*/
311
if (m > scaled_max_m)
312
break;
313
314
r = _dpll_test_mult(&m, n, &new_rate, target_rate,
315
dd->clk_ref->rate);
316
317
/* m can't be set low enough for this n - try with a larger n */
318
if (r == DPLL_MULT_UNDERFLOW)
319
continue;
320
321
pr_debug("clock: %s: m = %d: n = %d: new_rate = %ld\n",
322
clk->name, m, n, new_rate);
323
324
if (target_rate == new_rate) {
325
dd->last_rounded_m = m;
326
dd->last_rounded_n = n;
327
dd->last_rounded_rate = target_rate;
328
break;
329
}
330
}
331
332
if (target_rate != new_rate) {
333
pr_debug("clock: %s: cannot round to rate %ld\n", clk->name,
334
target_rate);
335
return ~0;
336
}
337
338
return target_rate;
339
}
340
341
342