~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/u-boot/arch/arm/cpu/arm926ejs/mxs/clock.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Freescale i.MX23/i.MX28 clock setup code
 
3
 *
 
4
 * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
 
5
 * on behalf of DENX Software Engineering GmbH
 
6
 *
 
7
 * Based on code from LTIB:
 
8
 * Copyright (C) 2010 Freescale Semiconductor, Inc.
 
9
 *
 
10
 * SPDX-License-Identifier:     GPL-2.0+
 
11
 */
 
12
 
 
13
#include <common.h>
 
14
#include <asm/errno.h>
 
15
#include <asm/io.h>
 
16
#include <asm/arch/clock.h>
 
17
#include <asm/arch/imx-regs.h>
 
18
 
 
19
/*
 
20
 * The PLL frequency is 480MHz and XTAL frequency is 24MHz
 
21
 *   iMX23: datasheet section 4.2
 
22
 *   iMX28: datasheet section 10.2
 
23
 */
 
24
#define PLL_FREQ_KHZ    480000
 
25
#define PLL_FREQ_COEF   18
 
26
#define XTAL_FREQ_KHZ   24000
 
27
 
 
28
#define PLL_FREQ_MHZ    (PLL_FREQ_KHZ / 1000)
 
29
#define XTAL_FREQ_MHZ   (XTAL_FREQ_KHZ / 1000)
 
30
 
 
31
#if defined(CONFIG_MX23)
 
32
#define MXC_SSPCLK_MAX MXC_SSPCLK0
 
33
#elif defined(CONFIG_MX28)
 
34
#define MXC_SSPCLK_MAX MXC_SSPCLK3
 
35
#endif
 
36
 
 
37
static uint32_t mxs_get_pclk(void)
 
38
{
 
39
        struct mxs_clkctrl_regs *clkctrl_regs =
 
40
                (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
 
41
 
 
42
        uint32_t clkctrl, clkseq, div;
 
43
        uint8_t clkfrac, frac;
 
44
 
 
45
        clkctrl = readl(&clkctrl_regs->hw_clkctrl_cpu);
 
46
 
 
47
        /* No support of fractional divider calculation */
 
48
        if (clkctrl &
 
49
                (CLKCTRL_CPU_DIV_XTAL_FRAC_EN | CLKCTRL_CPU_DIV_CPU_FRAC_EN)) {
 
50
                return 0;
 
51
        }
 
52
 
 
53
        clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
 
54
 
 
55
        /* XTAL Path */
 
56
        if (clkseq & CLKCTRL_CLKSEQ_BYPASS_CPU) {
 
57
                div = (clkctrl & CLKCTRL_CPU_DIV_XTAL_MASK) >>
 
58
                        CLKCTRL_CPU_DIV_XTAL_OFFSET;
 
59
                return XTAL_FREQ_MHZ / div;
 
60
        }
 
61
 
 
62
        /* REF Path */
 
63
        clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]);
 
64
        frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
 
65
        div = clkctrl & CLKCTRL_CPU_DIV_CPU_MASK;
 
66
        return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
 
67
}
 
68
 
 
69
static uint32_t mxs_get_hclk(void)
 
70
{
 
71
        struct mxs_clkctrl_regs *clkctrl_regs =
 
72
                (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
 
73
 
 
74
        uint32_t div;
 
75
        uint32_t clkctrl;
 
76
 
 
77
        clkctrl = readl(&clkctrl_regs->hw_clkctrl_hbus);
 
78
 
 
79
        /* No support of fractional divider calculation */
 
80
        if (clkctrl & CLKCTRL_HBUS_DIV_FRAC_EN)
 
81
                return 0;
 
82
 
 
83
        div = clkctrl & CLKCTRL_HBUS_DIV_MASK;
 
84
        return mxs_get_pclk() / div;
 
85
}
 
86
 
 
87
static uint32_t mxs_get_emiclk(void)
 
88
{
 
89
        struct mxs_clkctrl_regs *clkctrl_regs =
 
90
                (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
 
91
 
 
92
        uint32_t clkctrl, clkseq, div;
 
93
        uint8_t clkfrac, frac;
 
94
 
 
95
        clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
 
96
        clkctrl = readl(&clkctrl_regs->hw_clkctrl_emi);
 
97
 
 
98
        /* XTAL Path */
 
99
        if (clkseq & CLKCTRL_CLKSEQ_BYPASS_EMI) {
 
100
                div = (clkctrl & CLKCTRL_EMI_DIV_XTAL_MASK) >>
 
101
                        CLKCTRL_EMI_DIV_XTAL_OFFSET;
 
102
                return XTAL_FREQ_MHZ / div;
 
103
        }
 
104
 
 
105
        /* REF Path */
 
106
        clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_EMI]);
 
107
        frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
 
108
        div = clkctrl & CLKCTRL_EMI_DIV_EMI_MASK;
 
109
        return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
 
110
}
 
111
 
 
112
static uint32_t mxs_get_gpmiclk(void)
 
113
{
 
114
        struct mxs_clkctrl_regs *clkctrl_regs =
 
115
                (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
 
116
#if defined(CONFIG_MX23)
 
117
        uint8_t *reg =
 
118
                &clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU];
 
119
#elif defined(CONFIG_MX28)
 
120
        uint8_t *reg =
 
121
                &clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_GPMI];
 
122
#endif
 
123
        uint32_t clkctrl, clkseq, div;
 
124
        uint8_t clkfrac, frac;
 
125
 
 
126
        clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
 
127
        clkctrl = readl(&clkctrl_regs->hw_clkctrl_gpmi);
 
128
 
 
129
        /* XTAL Path */
 
130
        if (clkseq & CLKCTRL_CLKSEQ_BYPASS_GPMI) {
 
131
                div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
 
132
                return XTAL_FREQ_MHZ / div;
 
133
        }
 
134
 
 
135
        /* REF Path */
 
136
        clkfrac = readb(reg);
 
137
        frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
 
138
        div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
 
139
        return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
 
140
}
 
141
 
 
142
/*
 
143
 * Set IO clock frequency, in kHz
 
144
 */
 
145
void mxs_set_ioclk(enum mxs_ioclock io, uint32_t freq)
 
146
{
 
147
        struct mxs_clkctrl_regs *clkctrl_regs =
 
148
                (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
 
149
        uint32_t div;
 
150
        int io_reg;
 
151
 
 
152
        if (freq == 0)
 
153
                return;
 
154
 
 
155
        if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1))
 
156
                return;
 
157
 
 
158
        div = (PLL_FREQ_KHZ * PLL_FREQ_COEF) / freq;
 
159
 
 
160
        if (div < 18)
 
161
                div = 18;
 
162
 
 
163
        if (div > 35)
 
164
                div = 35;
 
165
 
 
166
        io_reg = CLKCTRL_FRAC0_IO0 - io;        /* Register order is reversed */
 
167
        writeb(CLKCTRL_FRAC_CLKGATE,
 
168
                &clkctrl_regs->hw_clkctrl_frac0_set[io_reg]);
 
169
        writeb(CLKCTRL_FRAC_CLKGATE | (div & CLKCTRL_FRAC_FRAC_MASK),
 
170
                &clkctrl_regs->hw_clkctrl_frac0[io_reg]);
 
171
        writeb(CLKCTRL_FRAC_CLKGATE,
 
172
                &clkctrl_regs->hw_clkctrl_frac0_clr[io_reg]);
 
173
}
 
174
 
 
175
/*
 
176
 * Get IO clock, returns IO clock in kHz
 
177
 */
 
178
static uint32_t mxs_get_ioclk(enum mxs_ioclock io)
 
179
{
 
180
        struct mxs_clkctrl_regs *clkctrl_regs =
 
181
                (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
 
182
        uint8_t ret;
 
183
        int io_reg;
 
184
 
 
185
        if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1))
 
186
                return 0;
 
187
 
 
188
        io_reg = CLKCTRL_FRAC0_IO0 - io;        /* Register order is reversed */
 
189
 
 
190
        ret = readb(&clkctrl_regs->hw_clkctrl_frac0[io_reg]) &
 
191
                CLKCTRL_FRAC_FRAC_MASK;
 
192
 
 
193
        return (PLL_FREQ_KHZ * PLL_FREQ_COEF) / ret;
 
194
}
 
195
 
 
196
/*
 
197
 * Configure SSP clock frequency, in kHz
 
198
 */
 
199
void mxs_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal)
 
200
{
 
201
        struct mxs_clkctrl_regs *clkctrl_regs =
 
202
                (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
 
203
        uint32_t clk, clkreg;
 
204
 
 
205
        if (ssp > MXC_SSPCLK_MAX)
 
206
                return;
 
207
 
 
208
        clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
 
209
                        (ssp * sizeof(struct mxs_register_32));
 
210
 
 
211
        clrbits_le32(clkreg, CLKCTRL_SSP_CLKGATE);
 
212
        while (readl(clkreg) & CLKCTRL_SSP_CLKGATE)
 
213
                ;
 
214
 
 
215
        if (xtal)
 
216
                clk = XTAL_FREQ_KHZ;
 
217
        else
 
218
                clk = mxs_get_ioclk(ssp >> 1);
 
219
 
 
220
        if (freq > clk)
 
221
                return;
 
222
 
 
223
        /* Calculate the divider and cap it if necessary */
 
224
        clk /= freq;
 
225
        if (clk > CLKCTRL_SSP_DIV_MASK)
 
226
                clk = CLKCTRL_SSP_DIV_MASK;
 
227
 
 
228
        clrsetbits_le32(clkreg, CLKCTRL_SSP_DIV_MASK, clk);
 
229
        while (readl(clkreg) & CLKCTRL_SSP_BUSY)
 
230
                ;
 
231
 
 
232
        if (xtal)
 
233
                writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
 
234
                        &clkctrl_regs->hw_clkctrl_clkseq_set);
 
235
        else
 
236
                writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
 
237
                        &clkctrl_regs->hw_clkctrl_clkseq_clr);
 
238
}
 
239
 
 
240
/*
 
241
 * Return SSP frequency, in kHz
 
242
 */
 
243
static uint32_t mxs_get_sspclk(enum mxs_sspclock ssp)
 
244
{
 
245
        struct mxs_clkctrl_regs *clkctrl_regs =
 
246
                (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
 
247
        uint32_t clkreg;
 
248
        uint32_t clk, tmp;
 
249
 
 
250
        if (ssp > MXC_SSPCLK_MAX)
 
251
                return 0;
 
252
 
 
253
        tmp = readl(&clkctrl_regs->hw_clkctrl_clkseq);
 
254
        if (tmp & (CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp))
 
255
                return XTAL_FREQ_KHZ;
 
256
 
 
257
        clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
 
258
                        (ssp * sizeof(struct mxs_register_32));
 
259
 
 
260
        tmp = readl(clkreg) & CLKCTRL_SSP_DIV_MASK;
 
261
 
 
262
        if (tmp == 0)
 
263
                return 0;
 
264
 
 
265
        clk = mxs_get_ioclk(ssp >> 1);
 
266
 
 
267
        return clk / tmp;
 
268
}
 
269
 
 
270
/*
 
271
 * Set SSP/MMC bus frequency, in kHz)
 
272
 */
 
273
void mxs_set_ssp_busclock(unsigned int bus, uint32_t freq)
 
274
{
 
275
        struct mxs_ssp_regs *ssp_regs;
 
276
        const enum mxs_sspclock clk = mxs_ssp_clock_by_bus(bus);
 
277
        const uint32_t sspclk = mxs_get_sspclk(clk);
 
278
        uint32_t reg;
 
279
        uint32_t divide, rate, tgtclk;
 
280
 
 
281
        ssp_regs = mxs_ssp_regs_by_bus(bus);
 
282
 
 
283
        /*
 
284
         * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)),
 
285
         * CLOCK_DIVIDE has to be an even value from 2 to 254, and
 
286
         * CLOCK_RATE could be any integer from 0 to 255.
 
287
         */
 
288
        for (divide = 2; divide < 254; divide += 2) {
 
289
                rate = sspclk / freq / divide;
 
290
                if (rate <= 256)
 
291
                        break;
 
292
        }
 
293
 
 
294
        tgtclk = sspclk / divide / rate;
 
295
        while (tgtclk > freq) {
 
296
                rate++;
 
297
                tgtclk = sspclk / divide / rate;
 
298
        }
 
299
        if (rate > 256)
 
300
                rate = 256;
 
301
 
 
302
        /* Always set timeout the maximum */
 
303
        reg = SSP_TIMING_TIMEOUT_MASK |
 
304
                (divide << SSP_TIMING_CLOCK_DIVIDE_OFFSET) |
 
305
                ((rate - 1) << SSP_TIMING_CLOCK_RATE_OFFSET);
 
306
        writel(reg, &ssp_regs->hw_ssp_timing);
 
307
 
 
308
        debug("SPI%d: Set freq rate to %d KHz (requested %d KHz)\n",
 
309
                bus, tgtclk, freq);
 
310
}
 
311
 
 
312
void mxs_set_lcdclk(uint32_t freq)
 
313
{
 
314
        struct mxs_clkctrl_regs *clkctrl_regs =
 
315
                (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
 
316
        uint32_t fp, x, k_rest, k_best, x_best, tk;
 
317
        int32_t k_best_l = 999, k_best_t = 0, x_best_l = 0xff, x_best_t = 0xff;
 
318
 
 
319
        if (freq == 0)
 
320
                return;
 
321
 
 
322
#if defined(CONFIG_MX23)
 
323
        writel(CLKCTRL_CLKSEQ_BYPASS_PIX, &clkctrl_regs->hw_clkctrl_clkseq_clr);
 
324
#elif defined(CONFIG_MX28)
 
325
        writel(CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF, &clkctrl_regs->hw_clkctrl_clkseq_clr);
 
326
#endif
 
327
 
 
328
        /*
 
329
         *             /               18 \     1       1
 
330
         * freq kHz = | 480000000 Hz * --  | * --- * ------
 
331
         *             \                x /     k     1000
 
332
         *
 
333
         *      480000000 Hz   18
 
334
         *      ------------ * --
 
335
         *        freq kHz      x
 
336
         * k = -------------------
 
337
         *             1000
 
338
         */
 
339
 
 
340
        fp = ((PLL_FREQ_KHZ * 1000) / freq) * 18;
 
341
 
 
342
        for (x = 18; x <= 35; x++) {
 
343
                tk = fp / x;
 
344
                if ((tk / 1000 == 0) || (tk / 1000 > 255))
 
345
                        continue;
 
346
 
 
347
                k_rest = tk % 1000;
 
348
 
 
349
                if (k_rest < (k_best_l % 1000)) {
 
350
                        k_best_l = tk;
 
351
                        x_best_l = x;
 
352
                }
 
353
 
 
354
                if (k_rest > (k_best_t % 1000)) {
 
355
                        k_best_t = tk;
 
356
                        x_best_t = x;
 
357
                }
 
358
        }
 
359
 
 
360
        if (1000 - (k_best_t % 1000) > (k_best_l % 1000)) {
 
361
                k_best = k_best_l;
 
362
                x_best = x_best_l;
 
363
        } else {
 
364
                k_best = k_best_t;
 
365
                x_best = x_best_t;
 
366
        }
 
367
 
 
368
        k_best /= 1000;
 
369
 
 
370
#if defined(CONFIG_MX23)
 
371
        writeb(CLKCTRL_FRAC_CLKGATE,
 
372
                &clkctrl_regs->hw_clkctrl_frac0_set[CLKCTRL_FRAC0_PIX]);
 
373
        writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK),
 
374
                &clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_PIX]);
 
375
        writeb(CLKCTRL_FRAC_CLKGATE,
 
376
                &clkctrl_regs->hw_clkctrl_frac0_clr[CLKCTRL_FRAC0_PIX]);
 
377
 
 
378
        writel(CLKCTRL_PIX_CLKGATE,
 
379
                &clkctrl_regs->hw_clkctrl_pix_set);
 
380
        clrsetbits_le32(&clkctrl_regs->hw_clkctrl_pix,
 
381
                        CLKCTRL_PIX_DIV_MASK | CLKCTRL_PIX_CLKGATE,
 
382
                        k_best << CLKCTRL_PIX_DIV_OFFSET);
 
383
 
 
384
        while (readl(&clkctrl_regs->hw_clkctrl_pix) & CLKCTRL_PIX_BUSY)
 
385
                ;
 
386
#elif defined(CONFIG_MX28)
 
387
        writeb(CLKCTRL_FRAC_CLKGATE,
 
388
                &clkctrl_regs->hw_clkctrl_frac1_set[CLKCTRL_FRAC1_PIX]);
 
389
        writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK),
 
390
                &clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_PIX]);
 
391
        writeb(CLKCTRL_FRAC_CLKGATE,
 
392
                &clkctrl_regs->hw_clkctrl_frac1_clr[CLKCTRL_FRAC1_PIX]);
 
393
 
 
394
        writel(CLKCTRL_DIS_LCDIF_CLKGATE,
 
395
                &clkctrl_regs->hw_clkctrl_lcdif_set);
 
396
        clrsetbits_le32(&clkctrl_regs->hw_clkctrl_lcdif,
 
397
                        CLKCTRL_DIS_LCDIF_DIV_MASK | CLKCTRL_DIS_LCDIF_CLKGATE,
 
398
                        k_best << CLKCTRL_DIS_LCDIF_DIV_OFFSET);
 
399
 
 
400
        while (readl(&clkctrl_regs->hw_clkctrl_lcdif) & CLKCTRL_DIS_LCDIF_BUSY)
 
401
                ;
 
402
#endif
 
403
}
 
404
 
 
405
uint32_t mxc_get_clock(enum mxc_clock clk)
 
406
{
 
407
        switch (clk) {
 
408
        case MXC_ARM_CLK:
 
409
                return mxs_get_pclk() * 1000000;
 
410
        case MXC_GPMI_CLK:
 
411
                return mxs_get_gpmiclk() * 1000000;
 
412
        case MXC_AHB_CLK:
 
413
        case MXC_IPG_CLK:
 
414
                return mxs_get_hclk() * 1000000;
 
415
        case MXC_EMI_CLK:
 
416
                return mxs_get_emiclk();
 
417
        case MXC_IO0_CLK:
 
418
                return mxs_get_ioclk(MXC_IOCLK0);
 
419
        case MXC_IO1_CLK:
 
420
                return mxs_get_ioclk(MXC_IOCLK1);
 
421
        case MXC_XTAL_CLK:
 
422
                return XTAL_FREQ_KHZ * 1000;
 
423
        case MXC_SSP0_CLK:
 
424
                return mxs_get_sspclk(MXC_SSPCLK0);
 
425
#ifdef CONFIG_MX28
 
426
        case MXC_SSP1_CLK:
 
427
                return mxs_get_sspclk(MXC_SSPCLK1);
 
428
        case MXC_SSP2_CLK:
 
429
                return mxs_get_sspclk(MXC_SSPCLK2);
 
430
        case MXC_SSP3_CLK:
 
431
                return mxs_get_sspclk(MXC_SSPCLK3);
 
432
#endif
 
433
        }
 
434
 
 
435
        return 0;
 
436
}