summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-imx/speed-imx6.c
blob: 645b2c97354a0d4918612aa9c36417a60b5981f1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
#include <common.h>
#include <asm/io.h>
#include <asm-generic/div64.h>
#include <mach/imx-regs.h>
#include <mach/clock-imx6.h>
#include <mach/imx6-anadig.h>

enum pll_clocks {
	CPU_PLL1,	/* System PLL */
	BUS_PLL2,	/* System Bus PLL*/
	USBOTG_PLL3,    /* OTG USB PLL */
	AUD_PLL4,	/* Audio PLL */
	VID_PLL5,	/* Video PLL */
	MLB_PLL6,	/* MLB PLL */
	USBHOST_PLL7,   /* Host USB PLL */
	ENET_PLL8,      /* ENET PLL */
};

#define SZ_DEC_1M		1000000

/* Out-of-reset PFDs and clock source definitions */
#define PLL2_PFD0_FREQ		352000000
#define PLL2_PFD1_FREQ		594000000
#define PLL2_PFD2_FREQ		400000000
#define PLL2_PFD2_DIV_FREQ	200000000
#define PLL3_PFD0_FREQ		720000000
#define PLL3_PFD1_FREQ		540000000
#define PLL3_PFD2_FREQ		508200000
#define PLL3_PFD3_FREQ		454700000
#define PLL3_80M		80000000
#define PLL3_60M		60000000

#define AHB_CLK_ROOT		132000000
#define IPG_CLK_ROOT		66000000
#define ENET_FREQ_0		25000000
#define ENET_FREQ_1		50000000
#define ENET_FREQ_2		100000000
#define ENET_FREQ_3		125000000

#define CONFIG_MX6_HCLK_FREQ      24000000

static u32 __decode_pll(enum pll_clocks pll, u32 infreq)
{
	u32 div;

	switch (pll) {
	case CPU_PLL1:
		div = readl(MX6_ANATOP_BASE_ADDR + HW_ANADIG_PLL_SYS) &
			BM_ANADIG_PLL_SYS_DIV_SELECT;
		return infreq * (div >> 1);
	case BUS_PLL2:
		div = readl(MX6_ANATOP_BASE_ADDR + HW_ANADIG_PLL_528) &
			BM_ANADIG_PLL_528_DIV_SELECT;
		return infreq * (20 + (div << 1));
	case USBOTG_PLL3:
		div = readl(MX6_ANATOP_BASE_ADDR + HW_ANADIG_USB2_PLL_480_CTRL) &
			BM_ANADIG_USB2_PLL_480_CTRL_DIV_SELECT;
		return infreq * (20 + (div << 1));
	case ENET_PLL8:
		div = readl(MX6_ANATOP_BASE_ADDR + HW_ANADIG_PLL_ENET) &
			BM_ANADIG_PLL_ENET_DIV_SELECT;
		switch (div) {
		default:
		case 0:
			return ENET_FREQ_0;
		case 1:
			return ENET_FREQ_1;
		case 2:
			return ENET_FREQ_2;
		case 3:
			return ENET_FREQ_3;
		}
	case AUD_PLL4:
	case VID_PLL5:
	case MLB_PLL6:
	case USBHOST_PLL7:
	default:
		return 0;
	}
}

static u32 __get_mcu_main_clk(void)
{
	u32 reg, freq;
	reg = (__REG(MXC_CCM_CACRR) & MXC_CCM_CACRR_ARM_PODF_MASK) >>
	    MXC_CCM_CACRR_ARM_PODF_OFFSET;
	freq = __decode_pll(CPU_PLL1, CONFIG_MX6_HCLK_FREQ);
	return freq / (reg + 1);
}

static u32 __get_periph_clk(void)
{
	u32 reg;
	reg = __REG(MXC_CCM_CBCDR);
	if (reg & MXC_CCM_CBCDR_PERIPH_CLK_SEL) {
		reg = __REG(MXC_CCM_CBCMR);
		switch ((reg & MXC_CCM_CBCMR_PERIPH_CLK2_SEL_MASK) >>
			MXC_CCM_CBCMR_PERIPH_CLK2_SEL_OFFSET) {
		case 0:
			return __decode_pll(USBOTG_PLL3, CONFIG_MX6_HCLK_FREQ);
		case 1:
		case 2:
			return CONFIG_MX6_HCLK_FREQ;
		default:
			return 0;
		}
	} else {
		reg = __REG(MXC_CCM_CBCMR);
		switch ((reg & MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK) >>
			MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_OFFSET) {
		default:
		case 0:
			return __decode_pll(BUS_PLL2, CONFIG_MX6_HCLK_FREQ);
		case 1:
			return PLL2_PFD2_FREQ;
		case 2:
			return PLL2_PFD0_FREQ;
		case 3:
			return PLL2_PFD2_DIV_FREQ;
		}
	}
}

static u32 __get_ipg_clk(void)
{
	u32 ahb_podf, ipg_podf;

	ahb_podf = __REG(MXC_CCM_CBCDR);
	ipg_podf = (ahb_podf & MXC_CCM_CBCDR_IPG_PODF_MASK) >>
			MXC_CCM_CBCDR_IPG_PODF_OFFSET;
	ahb_podf = (ahb_podf & MXC_CCM_CBCDR_AHB_PODF_MASK) >>
			MXC_CCM_CBCDR_AHB_PODF_OFFSET;
	return __get_periph_clk() / ((ahb_podf + 1) * (ipg_podf + 1));
}

u32 imx_get_gptclk(void)
{
	return __get_ipg_clk();
}

static u32 __get_ipg_per_clk(void)
{
	u32 podf;
	u32 clk_root = __get_ipg_clk();

	podf = __REG(MXC_CCM_CSCMR1) & MXC_CCM_CSCMR1_PERCLK_PODF_MASK;
	return clk_root / (podf + 1);
}

u32 imx_get_uartclk(void)
{
	u32 freq = PLL3_80M, reg, podf;

	reg = __REG(MXC_CCM_CSCDR1);
	podf = (reg & MXC_CCM_CSCDR1_UART_CLK_PODF_MASK) >>
		MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET;
	freq /= (podf + 1);

	return freq;
}

static u32 __get_cspi_clk(void)
{
	u32 freq = PLL3_60M, reg, podf;

	reg = __REG(MXC_CCM_CSCDR2);
	podf = (reg & MXC_CCM_CSCDR2_ECSPI_CLK_PODF_MASK) >>
		MXC_CCM_CSCDR2_ECSPI_CLK_PODF_OFFSET;
	freq /= (podf + 1);

	return freq;
}

static u32 __get_axi_clk(void)
{
	u32 clkroot;
	u32 cbcdr =  __REG(MXC_CCM_CBCDR);
	u32 podf = (cbcdr & MXC_CCM_CBCDR_AXI_PODF_MASK) >>
		MXC_CCM_CBCDR_AXI_PODF_OFFSET;

	if (cbcdr & MXC_CCM_CBCDR_AXI_SEL) {
		if (cbcdr & MXC_CCM_CBCDR_AXI_ALT_SEL)
			clkroot = PLL2_PFD2_FREQ;
		else
			clkroot = PLL3_PFD1_FREQ;;
	} else
		clkroot = __get_periph_clk();

	return  clkroot / (podf + 1);
}

static u32 __get_ahb_clk(void)
{
	u32 cbcdr =  __REG(MXC_CCM_CBCDR);
	u32 podf = (cbcdr & MXC_CCM_CBCDR_AHB_PODF_MASK) \
			>> MXC_CCM_CBCDR_AHB_PODF_OFFSET;

	return  __get_periph_clk() / (podf + 1);
}

static u32 __get_emi_slow_clk(void)
{
	u32 cscmr1 =  __REG(MXC_CCM_CSCMR1);
	u32 emi_clk_sel = (cscmr1 & MXC_CCM_CSCMR1_ACLK_EMI_SLOW_MASK) >>
		MXC_CCM_CSCMR1_ACLK_EMI_SLOW_OFFSET;
	u32 podf = (cscmr1 & MXC_CCM_CSCMR1_ACLK_EMI_SLOW_PODF_MASK) >>
			MXC_CCM_CSCMR1_ACLK_EMI_PODF_OFFSET;

	switch (emi_clk_sel) {
	default:
	case 0:
		return __get_axi_clk() / (podf + 1);
	case 1:
		return __decode_pll(USBOTG_PLL3, CONFIG_MX6_HCLK_FREQ) /
			(podf + 1);
	case 2:
		return PLL2_PFD2_FREQ / (podf + 1);
	case 3:
		return PLL2_PFD0_FREQ / (podf + 1);
	}
}

static u32 __get_nfc_clk(void)
{
	u32 clkroot;
	u32 cs2cdr =  __REG(MXC_CCM_CS2CDR);
	u32 podf = (cs2cdr & MXC_CCM_CS2CDR_ENFC_CLK_PODF_MASK) \
			>> MXC_CCM_CS2CDR_ENFC_CLK_PODF_OFFSET;
	u32 pred = (cs2cdr & MXC_CCM_CS2CDR_ENFC_CLK_PRED_MASK) \
			>> MXC_CCM_CS2CDR_ENFC_CLK_PRED_OFFSET;

	switch ((cs2cdr & MXC_CCM_CS2CDR_ENFC_CLK_SEL_MASK) >>
		MXC_CCM_CS2CDR_ENFC_CLK_SEL_OFFSET) {
		default:
		case 0:
			clkroot = PLL2_PFD0_FREQ;
			break;
		case 1:
			clkroot = __decode_pll(BUS_PLL2, CONFIG_MX6_HCLK_FREQ);
			break;
		case 2:
			clkroot = __decode_pll(USBOTG_PLL3, CONFIG_MX6_HCLK_FREQ);
			break;
		case 3:
			clkroot = PLL2_PFD2_FREQ;
			break;
	}

	return  clkroot / (pred+1) / (podf+1);
}

static u32 __get_ddr_clk(void)
{
	u32 cbcdr = __REG(MXC_CCM_CBCDR);
	u32 podf = (cbcdr & MXC_CCM_CBCDR_MMDC_CH0_PODF_MASK) >>
		MXC_CCM_CBCDR_MMDC_CH0_PODF_OFFSET;

	return __get_periph_clk() / (podf + 1);
}

static u32 __get_usdhc1_clk(void)
{
	u32 clkroot;
	u32 cscmr1 = __REG(MXC_CCM_CSCMR1);
	u32 cscdr1 = __REG(MXC_CCM_CSCDR1);
	u32 podf = (cscdr1 & MXC_CCM_CSCDR1_USDHC1_PODF_MASK) >>
		MXC_CCM_CSCDR1_USDHC1_PODF_OFFSET;

	if (cscmr1 & MXC_CCM_CSCMR1_USDHC1_CLK_SEL)
		clkroot = PLL2_PFD0_FREQ;
	else
		clkroot = PLL2_PFD2_FREQ;

	return clkroot / (podf + 1);
}

static u32 __get_usdhc2_clk(void)
{
	u32 clkroot;
	u32 cscmr1 = __REG(MXC_CCM_CSCMR1);
	u32 cscdr1 = __REG(MXC_CCM_CSCDR1);
	u32 podf = (cscdr1 & MXC_CCM_CSCDR1_USDHC2_PODF_MASK) >>
		MXC_CCM_CSCDR1_USDHC2_PODF_OFFSET;

	if (cscmr1 & MXC_CCM_CSCMR1_USDHC2_CLK_SEL)
		clkroot = PLL2_PFD0_FREQ;
	else
		clkroot = PLL2_PFD2_FREQ;

	return clkroot / (podf + 1);
}

static u32 __get_usdhc3_clk(void)
{
	u32 clkroot;
	u32 cscmr1 = __REG(MXC_CCM_CSCMR1);
	u32 cscdr1 = __REG(MXC_CCM_CSCDR1);
	u32 podf = (cscdr1 & MXC_CCM_CSCDR1_USDHC3_PODF_MASK) >>
		MXC_CCM_CSCDR1_USDHC3_PODF_OFFSET;

	if (cscmr1 & MXC_CCM_CSCMR1_USDHC3_CLK_SEL)
		clkroot = PLL2_PFD0_FREQ;
	else
		clkroot = PLL2_PFD2_FREQ;

	return clkroot / (podf + 1);
}

static u32 __get_usdhc4_clk(void)
{
	u32 clkroot;
	u32 cscmr1 = __REG(MXC_CCM_CSCMR1);
	u32 cscdr1 = __REG(MXC_CCM_CSCDR1);
	u32 podf = (cscdr1 & MXC_CCM_CSCDR1_USDHC4_PODF_MASK) >>
		MXC_CCM_CSCDR1_USDHC4_PODF_OFFSET;

	if (cscmr1 & MXC_CCM_CSCMR1_USDHC4_CLK_SEL)
		clkroot = PLL2_PFD0_FREQ;
	else
		clkroot = PLL2_PFD2_FREQ;

	return clkroot / (podf + 1);
}

u32 imx_get_mmcclk(void)
{
	return __get_usdhc3_clk();
}

u32 imx_get_fecclk(void)
{
	return __get_ipg_clk();
}

u32 imx_get_i2cclk(void)
{
	return __get_ipg_per_clk();
}

u32 imx_get_cspiclk(void)
{
	return __get_cspi_clk();
}

void imx_dump_clocks(void)
{
	u32 freq;

	freq = __decode_pll(CPU_PLL1, CONFIG_MX6_HCLK_FREQ);
	printf("mx6q pll1: %d\n", freq);
	freq = __decode_pll(BUS_PLL2, CONFIG_MX6_HCLK_FREQ);
	printf("mx6q pll2: %d\n", freq);
	freq = __decode_pll(USBOTG_PLL3, CONFIG_MX6_HCLK_FREQ);
	printf("mx6q pll3: %d\n", freq);
	freq = __decode_pll(ENET_PLL8, CONFIG_MX6_HCLK_FREQ);
	printf("mx6q pll8: %d\n", freq);
	printf("mcu main:  %d\n", __get_mcu_main_clk());
	printf("periph:    %d\n", __get_periph_clk());
	printf("i2c:	   %d\n", __get_ipg_per_clk());
	printf("ipg:       %d\n", __get_ipg_clk());
	printf("ipg per:   %d\n", __get_ipg_per_clk());
	printf("cspi:      %d\n", __get_cspi_clk());
	printf("axi:       %d\n", __get_axi_clk());
	printf("ahb:       %d\n", __get_ahb_clk());
	printf("emi slow:  %d\n", __get_emi_slow_clk());
	printf("nfc:       %d\n", __get_nfc_clk());
	printf("ddr:       %d\n", __get_ddr_clk());
	printf("usdhc1:    %d\n", __get_usdhc1_clk());
	printf("usdhc2:    %d\n", __get_usdhc2_clk());
	printf("usdhc3:    %d\n", __get_usdhc3_clk());
	printf("usdhc4:    %d\n", __get_usdhc4_clk());
}

void imx6_ipu_clk_enable(int di)
{
	u32 reg;

	if (di == 1) {
		reg = readl(MXC_CCM_CCGR3);
		reg |= 0xC033;
		writel(reg, MXC_CCM_CCGR3);
	} else {
		reg = readl(MXC_CCM_CCGR3);
		reg |= 0x300F;
		writel(reg, MXC_CCM_CCGR3);
	}

	reg = readl(MX6_ANATOP_BASE_ADDR + 0xF0);
	reg &= ~0x00003F00;
	reg |= 0x00001300;
	writel(reg, MX6_ANATOP_BASE_ADDR + 0xF4);

	reg = readl(MXC_CCM_CS2CDR);
	reg &= ~0x00007E00;
	reg |= 0x00001200;
	writel(reg, MXC_CCM_CS2CDR);

	reg = readl(MXC_CCM_CSCMR2);
	reg |= 0x00000C00;
	writel(reg, MXC_CCM_CSCMR2);

	reg = 0x0002A953;
	writel(reg, MXC_CCM_CHSCDR);
}