summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-imx/speed-imx25.c
blob: a615017ee9141c8e7f0d347a4267879e966986dc (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
#include <common.h>
#include <mach/imx-regs.h>
#include <asm/io.h>
#include <mach/clock.h>
#include <init.h>

unsigned long imx_get_mpllclk(void)
{
	ulong mpctl = readl(IMX_CCM_BASE + CCM_MPCTL);
	return imx_decode_pll(mpctl, CONFIG_MX25_HCLK_FREQ);
}

unsigned long imx_get_upllclk(void)
{
	ulong ppctl = readl(IMX_CCM_BASE + CCM_UPCTL);
	return imx_decode_pll(ppctl, CONFIG_MX25_HCLK_FREQ);
}

unsigned long imx_get_armclk(void)
{
	unsigned long rate, cctl;

	cctl = readl(IMX_CCM_BASE + CCM_CCTL);
	rate = imx_get_mpllclk();

	if (cctl & (1 << 14)) {
		rate *= 3;
		rate >>= 2;
	}

	return rate / ((cctl >> 30) + 1);
}

unsigned long imx_get_ahbclk(void)
{
	ulong cctl = readl(IMX_CCM_BASE + CCM_CCTL);
	return imx_get_armclk() / (((cctl >> 28) & 0x3) + 1);
}

unsigned long imx_get_ipgclk(void)
{
	return imx_get_ahbclk() / 2;
}

unsigned long imx_get_gptclk(void)
{
	return imx_get_ipgclk();
}

unsigned long imx_get_perclk(int per)
{
	ulong ofs = (per & 0x3) * 8;
	ulong reg = per & ~0x3;
	ulong val = (readl(IMX_CCM_BASE + CCM_PCDR0 + reg) >> ofs) & 0x3f;
	ulong fref;

	if (readl(IMX_CCM_BASE + 0x64) & (1 << per))
		fref = imx_get_upllclk();
	else
		fref = imx_get_ahbclk();

	return fref / (val + 1);
}

unsigned long imx_get_uartclk(void)
{
	return imx_get_perclk(15);
}

unsigned long imx_get_fecclk(void)
{
	return imx_get_ipgclk();
}

unsigned long imx_get_lcdclk(void)
{
	return imx_get_perclk(7);
}

int imx_dump_clocks(void)
{
	printf("mpll:    %10d Hz\n", imx_get_mpllclk());
	printf("upll:    %10d Hz\n", imx_get_upllclk());
	printf("arm:     %10d Hz\n", imx_get_armclk());
	printf("ahb:     %10d Hz\n", imx_get_ahbclk());
	printf("uart:    %10d Hz\n", imx_get_perclk(15));
	printf("gpt:     %10d Hz\n", imx_get_ipgclk());
	printf("nand:    %10d Hz\n", imx_get_perclk(8));
	printf("lcd:     %10d Hz\n", imx_get_perclk(7));
	return 0;
}

/*
 * Set the divider of the CLKO pin. Returns
 * the new divider (which may be smaller
 * than the desired one)
 */
int imx_clko_set_div(int div)
{
	unsigned long mcr = readl(IMX_CCM_BASE + 0x64);

	div -= 1;
	div &= 0x3f;

	mcr &= ~(0x3f << 24);
	mcr |= div << 24;

	writel(mcr, IMX_CCM_BASE + 0x64);

	return div + 1;
}

/*
 * Set the clock source for the CLKO pin
 */
void imx_clko_set_src(int src)
{
	unsigned long mcr = readl(IMX_CCM_BASE + 0x64);

	if (src < 0) {
		mcr &= ~(1 << 30);
		writel(mcr, IMX_CCM_BASE + 0x64);
		return;
	}

	mcr |= 1 << 30;
	mcr &= ~(0xf << 20);
	mcr |= (src & 0xf) << 20;

	writel(mcr, IMX_CCM_BASE + 0x64);
}