Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/arm/mach-omap2/clkt_clksel.c
10817 views
1
/*
2
* clkt_clksel.c - OMAP2/3/4 clksel 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
*
16
* clksel clocks are clocks that do not have a fixed parent, or that
17
* can divide their parent's rate, or possibly both at the same time, based
18
* on the contents of a hardware register bitfield.
19
*
20
* All of the various mux and divider settings can be encoded into
21
* struct clksel* data structures, and then these can be autogenerated
22
* from some hardware database for each new chip generation. This
23
* should avoid the need to write, review, and validate a lot of new
24
* clock code for each new chip, since it can be exported from the SoC
25
* design flow. This is now done on OMAP4.
26
*
27
* The fusion of mux and divider clocks is a software creation. In
28
* hardware reality, the multiplexer (parent selection) and the
29
* divider exist separately. XXX At some point these clksel clocks
30
* should be split into "divider" clocks and "mux" clocks to better
31
* match the hardware.
32
*
33
* (The name "clksel" comes from the name of the corresponding
34
* register field in the OMAP2/3 family of SoCs.)
35
*
36
* XXX Currently these clocks are only used in the OMAP2/3/4 code, but
37
* many of the OMAP1 clocks should be convertible to use this
38
* mechanism.
39
*/
40
#undef DEBUG
41
42
#include <linux/kernel.h>
43
#include <linux/errno.h>
44
#include <linux/clk.h>
45
#include <linux/io.h>
46
47
#include <plat/clock.h>
48
49
#include "clock.h"
50
51
/* Private functions */
52
53
/**
54
* _get_clksel_by_parent() - return clksel struct for a given clk & parent
55
* @clk: OMAP struct clk ptr to inspect
56
* @src_clk: OMAP struct clk ptr of the parent clk to search for
57
*
58
* Scan the struct clksel array associated with the clock to find
59
* the element associated with the supplied parent clock address.
60
* Returns a pointer to the struct clksel on success or NULL on error.
61
*/
62
static const struct clksel *_get_clksel_by_parent(struct clk *clk,
63
struct clk *src_clk)
64
{
65
const struct clksel *clks;
66
67
for (clks = clk->clksel; clks->parent; clks++)
68
if (clks->parent == src_clk)
69
break; /* Found the requested parent */
70
71
if (!clks->parent) {
72
/* This indicates a data problem */
73
WARN(1, "clock: Could not find parent clock %s in clksel array "
74
"of clock %s\n", src_clk->name, clk->name);
75
return NULL;
76
}
77
78
return clks;
79
}
80
81
/**
82
* _get_div_and_fieldval() - find the new clksel divisor and field value to use
83
* @src_clk: planned new parent struct clk *
84
* @clk: struct clk * that is being reparented
85
* @field_val: pointer to a u32 to contain the register data for the divisor
86
*
87
* Given an intended new parent struct clk * @src_clk, and the struct
88
* clk * @clk to the clock that is being reparented, find the
89
* appropriate rate divisor for the new clock (returned as the return
90
* value), and the corresponding register bitfield data to program to
91
* reach that divisor (returned in the u32 pointed to by @field_val).
92
* Returns 0 on error, or returns the newly-selected divisor upon
93
* success (in this latter case, the corresponding register bitfield
94
* value is passed back in the variable pointed to by @field_val)
95
*/
96
static u8 _get_div_and_fieldval(struct clk *src_clk, struct clk *clk,
97
u32 *field_val)
98
{
99
const struct clksel *clks;
100
const struct clksel_rate *clkr, *max_clkr = NULL;
101
u8 max_div = 0;
102
103
clks = _get_clksel_by_parent(clk, src_clk);
104
if (!clks)
105
return 0;
106
107
/*
108
* Find the highest divisor (e.g., the one resulting in the
109
* lowest rate) to use as the default. This should avoid
110
* clock rates that are too high for the device. XXX A better
111
* solution here would be to try to determine if there is a
112
* divisor matching the original clock rate before the parent
113
* switch, and if it cannot be found, to fall back to the
114
* highest divisor.
115
*/
116
for (clkr = clks->rates; clkr->div; clkr++) {
117
if (!(clkr->flags & cpu_mask))
118
continue;
119
120
if (clkr->div > max_div) {
121
max_div = clkr->div;
122
max_clkr = clkr;
123
}
124
}
125
126
if (max_div == 0) {
127
/* This indicates an error in the clksel data */
128
WARN(1, "clock: Could not find divisor for clock %s parent %s"
129
"\n", clk->name, src_clk->parent->name);
130
return 0;
131
}
132
133
*field_val = max_clkr->val;
134
135
return max_div;
136
}
137
138
/**
139
* _write_clksel_reg() - program a clock's clksel register in hardware
140
* @clk: struct clk * to program
141
* @v: clksel bitfield value to program (with LSB at bit 0)
142
*
143
* Shift the clksel register bitfield value @v to its appropriate
144
* location in the clksel register and write it in. This function
145
* will ensure that the write to the clksel_reg reaches its
146
* destination before returning -- important since PRM and CM register
147
* accesses can be quite slow compared to ARM cycles -- but does not
148
* take into account any time the hardware might take to switch the
149
* clock source.
150
*/
151
static void _write_clksel_reg(struct clk *clk, u32 field_val)
152
{
153
u32 v;
154
155
v = __raw_readl(clk->clksel_reg);
156
v &= ~clk->clksel_mask;
157
v |= field_val << __ffs(clk->clksel_mask);
158
__raw_writel(v, clk->clksel_reg);
159
160
v = __raw_readl(clk->clksel_reg); /* OCP barrier */
161
}
162
163
/**
164
* _clksel_to_divisor() - turn clksel field value into integer divider
165
* @clk: OMAP struct clk to use
166
* @field_val: register field value to find
167
*
168
* Given a struct clk of a rate-selectable clksel clock, and a register field
169
* value to search for, find the corresponding clock divisor. The register
170
* field value should be pre-masked and shifted down so the LSB is at bit 0
171
* before calling. Returns 0 on error or returns the actual integer divisor
172
* upon success.
173
*/
174
static u32 _clksel_to_divisor(struct clk *clk, u32 field_val)
175
{
176
const struct clksel *clks;
177
const struct clksel_rate *clkr;
178
179
clks = _get_clksel_by_parent(clk, clk->parent);
180
if (!clks)
181
return 0;
182
183
for (clkr = clks->rates; clkr->div; clkr++) {
184
if (!(clkr->flags & cpu_mask))
185
continue;
186
187
if (clkr->val == field_val)
188
break;
189
}
190
191
if (!clkr->div) {
192
/* This indicates a data error */
193
WARN(1, "clock: Could not find fieldval %d for clock %s parent "
194
"%s\n", field_val, clk->name, clk->parent->name);
195
return 0;
196
}
197
198
return clkr->div;
199
}
200
201
/**
202
* _divisor_to_clksel() - turn clksel integer divisor into a field value
203
* @clk: OMAP struct clk to use
204
* @div: integer divisor to search for
205
*
206
* Given a struct clk of a rate-selectable clksel clock, and a clock
207
* divisor, find the corresponding register field value. Returns the
208
* register field value _before_ left-shifting (i.e., LSB is at bit
209
* 0); or returns 0xFFFFFFFF (~0) upon error.
210
*/
211
static u32 _divisor_to_clksel(struct clk *clk, u32 div)
212
{
213
const struct clksel *clks;
214
const struct clksel_rate *clkr;
215
216
/* should never happen */
217
WARN_ON(div == 0);
218
219
clks = _get_clksel_by_parent(clk, clk->parent);
220
if (!clks)
221
return ~0;
222
223
for (clkr = clks->rates; clkr->div; clkr++) {
224
if (!(clkr->flags & cpu_mask))
225
continue;
226
227
if (clkr->div == div)
228
break;
229
}
230
231
if (!clkr->div) {
232
pr_err("clock: Could not find divisor %d for clock %s parent "
233
"%s\n", div, clk->name, clk->parent->name);
234
return ~0;
235
}
236
237
return clkr->val;
238
}
239
240
/**
241
* _read_divisor() - get current divisor applied to parent clock (from hdwr)
242
* @clk: OMAP struct clk to use.
243
*
244
* Read the current divisor register value for @clk that is programmed
245
* into the hardware, convert it into the actual divisor value, and
246
* return it; or return 0 on error.
247
*/
248
static u32 _read_divisor(struct clk *clk)
249
{
250
u32 v;
251
252
if (!clk->clksel || !clk->clksel_mask)
253
return 0;
254
255
v = __raw_readl(clk->clksel_reg);
256
v &= clk->clksel_mask;
257
v >>= __ffs(clk->clksel_mask);
258
259
return _clksel_to_divisor(clk, v);
260
}
261
262
/* Public functions */
263
264
/**
265
* omap2_clksel_round_rate_div() - find divisor for the given clock and rate
266
* @clk: OMAP struct clk to use
267
* @target_rate: desired clock rate
268
* @new_div: ptr to where we should store the divisor
269
*
270
* Finds 'best' divider value in an array based on the source and target
271
* rates. The divider array must be sorted with smallest divider first.
272
* This function is also used by the DPLL3 M2 divider code.
273
*
274
* Returns the rounded clock rate or returns 0xffffffff on error.
275
*/
276
u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
277
u32 *new_div)
278
{
279
unsigned long test_rate;
280
const struct clksel *clks;
281
const struct clksel_rate *clkr;
282
u32 last_div = 0;
283
284
if (!clk->clksel || !clk->clksel_mask)
285
return ~0;
286
287
pr_debug("clock: clksel_round_rate_div: %s target_rate %ld\n",
288
clk->name, target_rate);
289
290
*new_div = 1;
291
292
clks = _get_clksel_by_parent(clk, clk->parent);
293
if (!clks)
294
return ~0;
295
296
for (clkr = clks->rates; clkr->div; clkr++) {
297
if (!(clkr->flags & cpu_mask))
298
continue;
299
300
/* Sanity check */
301
if (clkr->div <= last_div)
302
pr_err("clock: clksel_rate table not sorted "
303
"for clock %s", clk->name);
304
305
last_div = clkr->div;
306
307
test_rate = clk->parent->rate / clkr->div;
308
309
if (test_rate <= target_rate)
310
break; /* found it */
311
}
312
313
if (!clkr->div) {
314
pr_err("clock: Could not find divisor for target "
315
"rate %ld for clock %s parent %s\n", target_rate,
316
clk->name, clk->parent->name);
317
return ~0;
318
}
319
320
*new_div = clkr->div;
321
322
pr_debug("clock: new_div = %d, new_rate = %ld\n", *new_div,
323
(clk->parent->rate / clkr->div));
324
325
return clk->parent->rate / clkr->div;
326
}
327
328
/*
329
* Clocktype interface functions to the OMAP clock code
330
* (i.e., those used in struct clk field function pointers, etc.)
331
*/
332
333
/**
334
* omap2_init_clksel_parent() - set a clksel clk's parent field from the hdwr
335
* @clk: OMAP clock struct ptr to use
336
*
337
* Given a pointer @clk to a source-selectable struct clk, read the
338
* hardware register and determine what its parent is currently set
339
* to. Update @clk's .parent field with the appropriate clk ptr. No
340
* return value.
341
*/
342
void omap2_init_clksel_parent(struct clk *clk)
343
{
344
const struct clksel *clks;
345
const struct clksel_rate *clkr;
346
u32 r, found = 0;
347
348
if (!clk->clksel || !clk->clksel_mask)
349
return;
350
351
r = __raw_readl(clk->clksel_reg) & clk->clksel_mask;
352
r >>= __ffs(clk->clksel_mask);
353
354
for (clks = clk->clksel; clks->parent && !found; clks++) {
355
for (clkr = clks->rates; clkr->div && !found; clkr++) {
356
if (!(clkr->flags & cpu_mask))
357
continue;
358
359
if (clkr->val == r) {
360
if (clk->parent != clks->parent) {
361
pr_debug("clock: inited %s parent "
362
"to %s (was %s)\n",
363
clk->name, clks->parent->name,
364
((clk->parent) ?
365
clk->parent->name : "NULL"));
366
clk_reparent(clk, clks->parent);
367
};
368
found = 1;
369
}
370
}
371
}
372
373
/* This indicates a data error */
374
WARN(!found, "clock: %s: init parent: could not find regval %0x\n",
375
clk->name, r);
376
377
return;
378
}
379
380
/**
381
* omap2_clksel_recalc() - function ptr to pass via struct clk .recalc field
382
* @clk: struct clk *
383
*
384
* This function is intended to be called only by the clock framework.
385
* Each clksel clock should have its struct clk .recalc field set to this
386
* function. Returns the clock's current rate, based on its parent's rate
387
* and its current divisor setting in the hardware.
388
*/
389
unsigned long omap2_clksel_recalc(struct clk *clk)
390
{
391
unsigned long rate;
392
u32 div = 0;
393
394
div = _read_divisor(clk);
395
if (div == 0)
396
return clk->rate;
397
398
rate = clk->parent->rate / div;
399
400
pr_debug("clock: %s: recalc'd rate is %ld (div %d)\n", clk->name,
401
rate, div);
402
403
return rate;
404
}
405
406
/**
407
* omap2_clksel_round_rate() - find rounded rate for the given clock and rate
408
* @clk: OMAP struct clk to use
409
* @target_rate: desired clock rate
410
*
411
* This function is intended to be called only by the clock framework.
412
* Finds best target rate based on the source clock and possible dividers.
413
* rates. The divider array must be sorted with smallest divider first.
414
*
415
* Returns the rounded clock rate or returns 0xffffffff on error.
416
*/
417
long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate)
418
{
419
u32 new_div;
420
421
return omap2_clksel_round_rate_div(clk, target_rate, &new_div);
422
}
423
424
/**
425
* omap2_clksel_set_rate() - program clock rate in hardware
426
* @clk: struct clk * to program rate
427
* @rate: target rate to program
428
*
429
* This function is intended to be called only by the clock framework.
430
* Program @clk's rate to @rate in the hardware. The clock can be
431
* either enabled or disabled when this happens, although if the clock
432
* is enabled, some downstream devices may glitch or behave
433
* unpredictably when the clock rate is changed - this depends on the
434
* hardware. This function does not currently check the usecount of
435
* the clock, so if multiple drivers are using the clock, and the rate
436
* is changed, they will all be affected without any notification.
437
* Returns -EINVAL upon error, or 0 upon success.
438
*/
439
int omap2_clksel_set_rate(struct clk *clk, unsigned long rate)
440
{
441
u32 field_val, validrate, new_div = 0;
442
443
if (!clk->clksel || !clk->clksel_mask)
444
return -EINVAL;
445
446
validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
447
if (validrate != rate)
448
return -EINVAL;
449
450
field_val = _divisor_to_clksel(clk, new_div);
451
if (field_val == ~0)
452
return -EINVAL;
453
454
_write_clksel_reg(clk, field_val);
455
456
clk->rate = clk->parent->rate / new_div;
457
458
pr_debug("clock: %s: set rate to %ld\n", clk->name, clk->rate);
459
460
return 0;
461
}
462
463
/*
464
* Clksel parent setting function - not passed in struct clk function
465
* pointer - instead, the OMAP clock code currently assumes that any
466
* parent-setting clock is a clksel clock, and calls
467
* omap2_clksel_set_parent() by default
468
*/
469
470
/**
471
* omap2_clksel_set_parent() - change a clock's parent clock
472
* @clk: struct clk * of the child clock
473
* @new_parent: struct clk * of the new parent clock
474
*
475
* This function is intended to be called only by the clock framework.
476
* Change the parent clock of clock @clk to @new_parent. This is
477
* intended to be used while @clk is disabled. This function does not
478
* currently check the usecount of the clock, so if multiple drivers
479
* are using the clock, and the parent is changed, they will all be
480
* affected without any notification. Returns -EINVAL upon error, or
481
* 0 upon success.
482
*/
483
int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent)
484
{
485
u32 field_val = 0;
486
u32 parent_div;
487
488
if (!clk->clksel || !clk->clksel_mask)
489
return -EINVAL;
490
491
parent_div = _get_div_and_fieldval(new_parent, clk, &field_val);
492
if (!parent_div)
493
return -EINVAL;
494
495
_write_clksel_reg(clk, field_val);
496
497
clk_reparent(clk, new_parent);
498
499
/* CLKSEL clocks follow their parents' rates, divided by a divisor */
500
clk->rate = new_parent->rate;
501
502
if (parent_div > 0)
503
clk->rate /= parent_div;
504
505
pr_debug("clock: %s: set parent to %s (new rate %ld)\n",
506
clk->name, clk->parent->name, clk->rate);
507
508
return 0;
509
}
510
511