Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/arm/mach-imx/clock-imx1.c
10817 views
1
/*
2
* Copyright (C) 2008 Sascha Hauer <[email protected]>, Pengutronix
3
*
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License version 2 as
6
* published by the Free Software Foundation.
7
*
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
12
*
13
* You should have received a copy of the GNU General Public License along
14
* with this program; if not, write to the Free Software Foundation, Inc.,
15
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
16
*/
17
18
#include <linux/kernel.h>
19
#include <linux/init.h>
20
#include <linux/list.h>
21
#include <linux/math64.h>
22
#include <linux/err.h>
23
#include <linux/clk.h>
24
#include <linux/io.h>
25
#include <linux/clkdev.h>
26
27
#include <mach/clock.h>
28
#include <mach/hardware.h>
29
#include <mach/common.h>
30
31
#define IO_ADDR_CCM(off) (MX1_IO_ADDRESS(MX1_CCM_BASE_ADDR + (off)))
32
33
/* CCM register addresses */
34
#define CCM_CSCR IO_ADDR_CCM(0x0)
35
#define CCM_MPCTL0 IO_ADDR_CCM(0x4)
36
#define CCM_SPCTL0 IO_ADDR_CCM(0xc)
37
#define CCM_PCDR IO_ADDR_CCM(0x20)
38
39
#define CCM_CSCR_CLKO_OFFSET 29
40
#define CCM_CSCR_CLKO_MASK (0x7 << 29)
41
#define CCM_CSCR_USB_OFFSET 26
42
#define CCM_CSCR_USB_MASK (0x7 << 26)
43
#define CCM_CSCR_OSC_EN_SHIFT 17
44
#define CCM_CSCR_SYSTEM_SEL (1 << 16)
45
#define CCM_CSCR_BCLK_OFFSET 10
46
#define CCM_CSCR_BCLK_MASK (0xf << 10)
47
#define CCM_CSCR_PRESC (1 << 15)
48
49
#define CCM_PCDR_PCLK3_OFFSET 16
50
#define CCM_PCDR_PCLK3_MASK (0x7f << 16)
51
#define CCM_PCDR_PCLK2_OFFSET 4
52
#define CCM_PCDR_PCLK2_MASK (0xf << 4)
53
#define CCM_PCDR_PCLK1_OFFSET 0
54
#define CCM_PCDR_PCLK1_MASK 0xf
55
56
#define IO_ADDR_SCM(off) (MX1_IO_ADDRESS(MX1_SCM_BASE_ADDR + (off)))
57
58
/* SCM register addresses */
59
#define SCM_GCCR IO_ADDR_SCM(0xc)
60
61
#define SCM_GCCR_DMA_CLK_EN_OFFSET 3
62
#define SCM_GCCR_CSI_CLK_EN_OFFSET 2
63
#define SCM_GCCR_MMA_CLK_EN_OFFSET 1
64
#define SCM_GCCR_USBD_CLK_EN_OFFSET 0
65
66
static int _clk_enable(struct clk *clk)
67
{
68
unsigned int reg;
69
70
reg = __raw_readl(clk->enable_reg);
71
reg |= 1 << clk->enable_shift;
72
__raw_writel(reg, clk->enable_reg);
73
74
return 0;
75
}
76
77
static void _clk_disable(struct clk *clk)
78
{
79
unsigned int reg;
80
81
reg = __raw_readl(clk->enable_reg);
82
reg &= ~(1 << clk->enable_shift);
83
__raw_writel(reg, clk->enable_reg);
84
}
85
86
static int _clk_can_use_parent(const struct clk *clk_arr[], unsigned int size,
87
struct clk *parent)
88
{
89
int i;
90
91
for (i = 0; i < size; i++)
92
if (parent == clk_arr[i])
93
return i;
94
95
return -EINVAL;
96
}
97
98
static unsigned long
99
_clk_simple_round_rate(struct clk *clk, unsigned long rate, unsigned int limit)
100
{
101
int div;
102
unsigned long parent_rate;
103
104
parent_rate = clk_get_rate(clk->parent);
105
106
div = parent_rate / rate;
107
if (parent_rate % rate)
108
div++;
109
110
if (div > limit)
111
div = limit;
112
113
return parent_rate / div;
114
}
115
116
static unsigned long _clk_parent_round_rate(struct clk *clk, unsigned long rate)
117
{
118
return clk->parent->round_rate(clk->parent, rate);
119
}
120
121
static int _clk_parent_set_rate(struct clk *clk, unsigned long rate)
122
{
123
return clk->parent->set_rate(clk->parent, rate);
124
}
125
126
static unsigned long clk16m_get_rate(struct clk *clk)
127
{
128
return 16000000;
129
}
130
131
static struct clk clk16m = {
132
.get_rate = clk16m_get_rate,
133
.enable = _clk_enable,
134
.enable_reg = CCM_CSCR,
135
.enable_shift = CCM_CSCR_OSC_EN_SHIFT,
136
.disable = _clk_disable,
137
};
138
139
/* in Hz */
140
static unsigned long clk32_rate;
141
142
static unsigned long clk32_get_rate(struct clk *clk)
143
{
144
return clk32_rate;
145
}
146
147
static struct clk clk32 = {
148
.get_rate = clk32_get_rate,
149
};
150
151
static unsigned long clk32_premult_get_rate(struct clk *clk)
152
{
153
return clk_get_rate(clk->parent) * 512;
154
}
155
156
static struct clk clk32_premult = {
157
.parent = &clk32,
158
.get_rate = clk32_premult_get_rate,
159
};
160
161
static const struct clk *prem_clk_clocks[] = {
162
&clk32_premult,
163
&clk16m,
164
};
165
166
static int prem_clk_set_parent(struct clk *clk, struct clk *parent)
167
{
168
int i;
169
unsigned int reg = __raw_readl(CCM_CSCR);
170
171
i = _clk_can_use_parent(prem_clk_clocks, ARRAY_SIZE(prem_clk_clocks),
172
parent);
173
174
switch (i) {
175
case 0:
176
reg &= ~CCM_CSCR_SYSTEM_SEL;
177
break;
178
case 1:
179
reg |= CCM_CSCR_SYSTEM_SEL;
180
break;
181
default:
182
return i;
183
}
184
185
__raw_writel(reg, CCM_CSCR);
186
187
return 0;
188
}
189
190
static struct clk prem_clk = {
191
.set_parent = prem_clk_set_parent,
192
};
193
194
static unsigned long system_clk_get_rate(struct clk *clk)
195
{
196
return mxc_decode_pll(__raw_readl(CCM_SPCTL0),
197
clk_get_rate(clk->parent));
198
}
199
200
static struct clk system_clk = {
201
.parent = &prem_clk,
202
.get_rate = system_clk_get_rate,
203
};
204
205
static unsigned long mcu_clk_get_rate(struct clk *clk)
206
{
207
return mxc_decode_pll(__raw_readl(CCM_MPCTL0),
208
clk_get_rate(clk->parent));
209
}
210
211
static struct clk mcu_clk = {
212
.parent = &clk32_premult,
213
.get_rate = mcu_clk_get_rate,
214
};
215
216
static unsigned long fclk_get_rate(struct clk *clk)
217
{
218
unsigned long fclk = clk_get_rate(clk->parent);
219
220
if (__raw_readl(CCM_CSCR) & CCM_CSCR_PRESC)
221
fclk /= 2;
222
223
return fclk;
224
}
225
226
static struct clk fclk = {
227
.parent = &mcu_clk,
228
.get_rate = fclk_get_rate,
229
};
230
231
/*
232
* get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA )
233
*/
234
static unsigned long hclk_get_rate(struct clk *clk)
235
{
236
return clk_get_rate(clk->parent) / (((__raw_readl(CCM_CSCR) &
237
CCM_CSCR_BCLK_MASK) >> CCM_CSCR_BCLK_OFFSET) + 1);
238
}
239
240
static unsigned long hclk_round_rate(struct clk *clk, unsigned long rate)
241
{
242
return _clk_simple_round_rate(clk, rate, 16);
243
}
244
245
static int hclk_set_rate(struct clk *clk, unsigned long rate)
246
{
247
unsigned int div;
248
unsigned int reg;
249
unsigned long parent_rate;
250
251
parent_rate = clk_get_rate(clk->parent);
252
253
div = parent_rate / rate;
254
255
if (div > 16 || div < 1 || ((parent_rate / div) != rate))
256
return -EINVAL;
257
258
div--;
259
260
reg = __raw_readl(CCM_CSCR);
261
reg &= ~CCM_CSCR_BCLK_MASK;
262
reg |= div << CCM_CSCR_BCLK_OFFSET;
263
__raw_writel(reg, CCM_CSCR);
264
265
return 0;
266
}
267
268
static struct clk hclk = {
269
.parent = &system_clk,
270
.get_rate = hclk_get_rate,
271
.round_rate = hclk_round_rate,
272
.set_rate = hclk_set_rate,
273
};
274
275
static unsigned long clk48m_get_rate(struct clk *clk)
276
{
277
return clk_get_rate(clk->parent) / (((__raw_readl(CCM_CSCR) &
278
CCM_CSCR_USB_MASK) >> CCM_CSCR_USB_OFFSET) + 1);
279
}
280
281
static unsigned long clk48m_round_rate(struct clk *clk, unsigned long rate)
282
{
283
return _clk_simple_round_rate(clk, rate, 8);
284
}
285
286
static int clk48m_set_rate(struct clk *clk, unsigned long rate)
287
{
288
unsigned int div;
289
unsigned int reg;
290
unsigned long parent_rate;
291
292
parent_rate = clk_get_rate(clk->parent);
293
294
div = parent_rate / rate;
295
296
if (div > 8 || div < 1 || ((parent_rate / div) != rate))
297
return -EINVAL;
298
299
div--;
300
301
reg = __raw_readl(CCM_CSCR);
302
reg &= ~CCM_CSCR_USB_MASK;
303
reg |= div << CCM_CSCR_USB_OFFSET;
304
__raw_writel(reg, CCM_CSCR);
305
306
return 0;
307
}
308
309
static struct clk clk48m = {
310
.parent = &system_clk,
311
.get_rate = clk48m_get_rate,
312
.round_rate = clk48m_round_rate,
313
.set_rate = clk48m_set_rate,
314
};
315
316
/*
317
* get peripheral clock 1 ( UART[12], Timer[12], PWM )
318
*/
319
static unsigned long perclk1_get_rate(struct clk *clk)
320
{
321
return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) &
322
CCM_PCDR_PCLK1_MASK) >> CCM_PCDR_PCLK1_OFFSET) + 1);
323
}
324
325
static unsigned long perclk1_round_rate(struct clk *clk, unsigned long rate)
326
{
327
return _clk_simple_round_rate(clk, rate, 16);
328
}
329
330
static int perclk1_set_rate(struct clk *clk, unsigned long rate)
331
{
332
unsigned int div;
333
unsigned int reg;
334
unsigned long parent_rate;
335
336
parent_rate = clk_get_rate(clk->parent);
337
338
div = parent_rate / rate;
339
340
if (div > 16 || div < 1 || ((parent_rate / div) != rate))
341
return -EINVAL;
342
343
div--;
344
345
reg = __raw_readl(CCM_PCDR);
346
reg &= ~CCM_PCDR_PCLK1_MASK;
347
reg |= div << CCM_PCDR_PCLK1_OFFSET;
348
__raw_writel(reg, CCM_PCDR);
349
350
return 0;
351
}
352
353
/*
354
* get peripheral clock 2 ( LCD, SD, SPI[12] )
355
*/
356
static unsigned long perclk2_get_rate(struct clk *clk)
357
{
358
return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) &
359
CCM_PCDR_PCLK2_MASK) >> CCM_PCDR_PCLK2_OFFSET) + 1);
360
}
361
362
static unsigned long perclk2_round_rate(struct clk *clk, unsigned long rate)
363
{
364
return _clk_simple_round_rate(clk, rate, 16);
365
}
366
367
static int perclk2_set_rate(struct clk *clk, unsigned long rate)
368
{
369
unsigned int div;
370
unsigned int reg;
371
unsigned long parent_rate;
372
373
parent_rate = clk_get_rate(clk->parent);
374
375
div = parent_rate / rate;
376
377
if (div > 16 || div < 1 || ((parent_rate / div) != rate))
378
return -EINVAL;
379
380
div--;
381
382
reg = __raw_readl(CCM_PCDR);
383
reg &= ~CCM_PCDR_PCLK2_MASK;
384
reg |= div << CCM_PCDR_PCLK2_OFFSET;
385
__raw_writel(reg, CCM_PCDR);
386
387
return 0;
388
}
389
390
/*
391
* get peripheral clock 3 ( SSI )
392
*/
393
static unsigned long perclk3_get_rate(struct clk *clk)
394
{
395
return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) &
396
CCM_PCDR_PCLK3_MASK) >> CCM_PCDR_PCLK3_OFFSET) + 1);
397
}
398
399
static unsigned long perclk3_round_rate(struct clk *clk, unsigned long rate)
400
{
401
return _clk_simple_round_rate(clk, rate, 128);
402
}
403
404
static int perclk3_set_rate(struct clk *clk, unsigned long rate)
405
{
406
unsigned int div;
407
unsigned int reg;
408
unsigned long parent_rate;
409
410
parent_rate = clk_get_rate(clk->parent);
411
412
div = parent_rate / rate;
413
414
if (div > 128 || div < 1 || ((parent_rate / div) != rate))
415
return -EINVAL;
416
417
div--;
418
419
reg = __raw_readl(CCM_PCDR);
420
reg &= ~CCM_PCDR_PCLK3_MASK;
421
reg |= div << CCM_PCDR_PCLK3_OFFSET;
422
__raw_writel(reg, CCM_PCDR);
423
424
return 0;
425
}
426
427
static struct clk perclk[] = {
428
{
429
.id = 0,
430
.parent = &system_clk,
431
.get_rate = perclk1_get_rate,
432
.round_rate = perclk1_round_rate,
433
.set_rate = perclk1_set_rate,
434
}, {
435
.id = 1,
436
.parent = &system_clk,
437
.get_rate = perclk2_get_rate,
438
.round_rate = perclk2_round_rate,
439
.set_rate = perclk2_set_rate,
440
}, {
441
.id = 2,
442
.parent = &system_clk,
443
.get_rate = perclk3_get_rate,
444
.round_rate = perclk3_round_rate,
445
.set_rate = perclk3_set_rate,
446
}
447
};
448
449
static const struct clk *clko_clocks[] = {
450
&perclk[0],
451
&hclk,
452
&clk48m,
453
&clk16m,
454
&prem_clk,
455
&fclk,
456
};
457
458
static int clko_set_parent(struct clk *clk, struct clk *parent)
459
{
460
int i;
461
unsigned int reg;
462
463
i = _clk_can_use_parent(clko_clocks, ARRAY_SIZE(clko_clocks), parent);
464
if (i < 0)
465
return i;
466
467
reg = __raw_readl(CCM_CSCR) & ~CCM_CSCR_CLKO_MASK;
468
reg |= i << CCM_CSCR_CLKO_OFFSET;
469
__raw_writel(reg, CCM_CSCR);
470
471
if (clko_clocks[i]->set_rate && clko_clocks[i]->round_rate) {
472
clk->set_rate = _clk_parent_set_rate;
473
clk->round_rate = _clk_parent_round_rate;
474
} else {
475
clk->set_rate = NULL;
476
clk->round_rate = NULL;
477
}
478
479
return 0;
480
}
481
482
static struct clk clko_clk = {
483
.set_parent = clko_set_parent,
484
};
485
486
static struct clk dma_clk = {
487
.parent = &hclk,
488
.round_rate = _clk_parent_round_rate,
489
.set_rate = _clk_parent_set_rate,
490
.enable = _clk_enable,
491
.enable_reg = SCM_GCCR,
492
.enable_shift = SCM_GCCR_DMA_CLK_EN_OFFSET,
493
.disable = _clk_disable,
494
};
495
496
static struct clk csi_clk = {
497
.parent = &hclk,
498
.round_rate = _clk_parent_round_rate,
499
.set_rate = _clk_parent_set_rate,
500
.enable = _clk_enable,
501
.enable_reg = SCM_GCCR,
502
.enable_shift = SCM_GCCR_CSI_CLK_EN_OFFSET,
503
.disable = _clk_disable,
504
};
505
506
static struct clk mma_clk = {
507
.parent = &hclk,
508
.round_rate = _clk_parent_round_rate,
509
.set_rate = _clk_parent_set_rate,
510
.enable = _clk_enable,
511
.enable_reg = SCM_GCCR,
512
.enable_shift = SCM_GCCR_MMA_CLK_EN_OFFSET,
513
.disable = _clk_disable,
514
};
515
516
static struct clk usbd_clk = {
517
.parent = &clk48m,
518
.round_rate = _clk_parent_round_rate,
519
.set_rate = _clk_parent_set_rate,
520
.enable = _clk_enable,
521
.enable_reg = SCM_GCCR,
522
.enable_shift = SCM_GCCR_USBD_CLK_EN_OFFSET,
523
.disable = _clk_disable,
524
};
525
526
static struct clk gpt_clk = {
527
.parent = &perclk[0],
528
.round_rate = _clk_parent_round_rate,
529
.set_rate = _clk_parent_set_rate,
530
};
531
532
static struct clk uart_clk = {
533
.parent = &perclk[0],
534
.round_rate = _clk_parent_round_rate,
535
.set_rate = _clk_parent_set_rate,
536
};
537
538
static struct clk i2c_clk = {
539
.parent = &hclk,
540
.round_rate = _clk_parent_round_rate,
541
.set_rate = _clk_parent_set_rate,
542
};
543
544
static struct clk spi_clk = {
545
.parent = &perclk[1],
546
.round_rate = _clk_parent_round_rate,
547
.set_rate = _clk_parent_set_rate,
548
};
549
550
static struct clk sdhc_clk = {
551
.parent = &perclk[1],
552
.round_rate = _clk_parent_round_rate,
553
.set_rate = _clk_parent_set_rate,
554
};
555
556
static struct clk lcdc_clk = {
557
.parent = &perclk[1],
558
.round_rate = _clk_parent_round_rate,
559
.set_rate = _clk_parent_set_rate,
560
};
561
562
static struct clk mshc_clk = {
563
.parent = &hclk,
564
.round_rate = _clk_parent_round_rate,
565
.set_rate = _clk_parent_set_rate,
566
};
567
568
static struct clk ssi_clk = {
569
.parent = &perclk[2],
570
.round_rate = _clk_parent_round_rate,
571
.set_rate = _clk_parent_set_rate,
572
};
573
574
static struct clk rtc_clk = {
575
.parent = &clk32,
576
};
577
578
#define _REGISTER_CLOCK(d, n, c) \
579
{ \
580
.dev_id = d, \
581
.con_id = n, \
582
.clk = &c, \
583
},
584
static struct clk_lookup lookups[] __initdata = {
585
_REGISTER_CLOCK(NULL, "dma", dma_clk)
586
_REGISTER_CLOCK("mx1-camera.0", NULL, csi_clk)
587
_REGISTER_CLOCK(NULL, "mma", mma_clk)
588
_REGISTER_CLOCK("imx_udc.0", NULL, usbd_clk)
589
_REGISTER_CLOCK(NULL, "gpt", gpt_clk)
590
_REGISTER_CLOCK("imx-uart.0", NULL, uart_clk)
591
_REGISTER_CLOCK("imx-uart.1", NULL, uart_clk)
592
_REGISTER_CLOCK("imx-uart.2", NULL, uart_clk)
593
_REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk)
594
_REGISTER_CLOCK("imx1-cspi.0", NULL, spi_clk)
595
_REGISTER_CLOCK("imx1-cspi.1", NULL, spi_clk)
596
_REGISTER_CLOCK("imx-mmc.0", NULL, sdhc_clk)
597
_REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk)
598
_REGISTER_CLOCK(NULL, "mshc", mshc_clk)
599
_REGISTER_CLOCK(NULL, "ssi", ssi_clk)
600
_REGISTER_CLOCK("mxc_rtc.0", NULL, rtc_clk)
601
};
602
603
int __init mx1_clocks_init(unsigned long fref)
604
{
605
unsigned int reg;
606
607
/* disable clocks we are able to */
608
__raw_writel(0, SCM_GCCR);
609
610
clk32_rate = fref;
611
reg = __raw_readl(CCM_CSCR);
612
613
/* detect clock reference for system PLL */
614
if (reg & CCM_CSCR_SYSTEM_SEL) {
615
prem_clk.parent = &clk16m;
616
} else {
617
/* ensure that oscillator is disabled */
618
reg &= ~(1 << CCM_CSCR_OSC_EN_SHIFT);
619
__raw_writel(reg, CCM_CSCR);
620
prem_clk.parent = &clk32_premult;
621
}
622
623
/* detect reference for CLKO */
624
reg = (reg & CCM_CSCR_CLKO_MASK) >> CCM_CSCR_CLKO_OFFSET;
625
clko_clk.parent = (struct clk *)clko_clocks[reg];
626
627
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
628
629
clk_enable(&hclk);
630
clk_enable(&fclk);
631
632
mxc_timer_init(&gpt_clk, MX1_IO_ADDRESS(MX1_TIM1_BASE_ADDR),
633
MX1_TIM1_INT);
634
635
return 0;
636
}
637
638