summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-samsung/clocks-s3c24xx.c
blob: 34b38f345cf0ff2c3e2e4ad26c0a26eb8ca13b1f (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
/*
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <config.h>
#include <common.h>
#include <init.h>
#include <clock.h>
#include <io.h>
#include <mach/s3c-iomap.h>
#include <mach/s3c-generic.h>
#include <mach/s3c-clocks.h>
#include <mach/s3c-busctl.h>

/**
 * Calculate the current M-PLL clock.
 * @return Current frequency in Hz
 */
uint32_t s3c_get_mpllclk(void)
{
	uint32_t m, p, s, reg_val;

	reg_val = readl(S3C_MPLLCON);
	m = ((reg_val & 0xFF000) >> 12) + 8;
	p = ((reg_val & 0x003F0) >> 4) + 2;
	s = reg_val & 0x3;
#ifdef CONFIG_CPU_S3C2410
	return (S3C24XX_CLOCK_REFERENCE * m) / (p << s);
#endif
#ifdef CONFIG_CPU_S3C2440
	return 2 * m * (S3C24XX_CLOCK_REFERENCE / (p << s));
#endif
}

/**
 * Calculate the current U-PLL clock
 * @return Current frequency in Hz
 */
uint32_t s3c_get_upllclk(void)
{
	uint32_t m, p, s, reg_val;

	reg_val = readl(S3C_UPLLCON);
	m = ((reg_val & 0xFF000) >> 12) + 8;
	p = ((reg_val & 0x003F0) >> 4) + 2;
	s = reg_val & 0x3;

	return (S3C24XX_CLOCK_REFERENCE * m) / (p << s);
}

/**
 * Calculate the FCLK frequency used for the ARM CPU core
 * @return Current frequency in Hz
 */
uint32_t s3c_get_fclk(void)
{
	return s3c_get_mpllclk();
}

/**
 * Calculate the HCLK frequency used for the AHB bus (CPU to main peripheral)
 * @return Current frequency in Hz
 */
uint32_t s3c_get_hclk(void)
{
	uint32_t f_clk;

	f_clk = s3c_get_fclk();
#ifdef CONFIG_CPU_S3C2410
	if (readl(S3C_CLKDIVN) & 0x02)
		return f_clk >> 1;
#endif
#ifdef CONFIG_CPU_S3C2440
	switch(readl(S3C_CLKDIVN) & 0x06) {
	case 2:
		return f_clk >> 1;
	case 4:
		return f_clk >> 2;	/* TODO consider CAMDIVN */
	case 6:
		return f_clk / 3;	/* TODO consider CAMDIVN */
	}
#endif
	return f_clk;
}

/**
 * Calculate the PCLK frequency used for the slower peripherals
 * @return Current frequency in Hz
 */
uint32_t s3c_get_pclk(void)
{
	uint32_t p_clk;

	p_clk = s3c_get_hclk();
	if (readl(S3C_CLKDIVN) & 0x01)
		return p_clk >> 1;
	return p_clk;
}

/**
 * Return correct UART frequency based on the UCON register
 */
unsigned s3c_get_uart_clk(unsigned src)
{
	switch (src & 3) {
	case 0:
	case 2:
		return s3c_get_pclk();
	case 1:
		return 0; /* TODO UEXTCLK */
	case 3:
		return 0; /* TODO FCLK/n */
	}
	return 0; /* not reached, to make compiler happy */
}

/**
 * Show the user the current clock settings
 */
static int s3c24xx_dump_clocks(void)
{
	printf("refclk:  %7d kHz\n", S3C24XX_CLOCK_REFERENCE / 1000);
	printf("mpll:    %7d kHz\n", s3c_get_mpllclk() / 1000);
	printf("upll:    %7d kHz\n", s3c_get_upllclk() / 1000);
	printf("fclk:    %7d kHz\n", s3c_get_fclk() / 1000);
	printf("hclk:    %7d kHz\n", s3c_get_hclk() / 1000);
	printf("pclk:    %7d kHz\n", s3c_get_pclk() / 1000);
	printf("SDRAM1:   CL%d@%dMHz\n", ((readl(S3C_BANKCON6) & 0xc) >> 2) + 2,
						s3c_get_hclk() / 1000000);
	if ((readl(S3C_BANKCON7) & (0x3 << 15)) == (0x3 << 15))
		printf("SDRAM2:   CL%d@%dMHz\n",
			((readl(S3C_BANKCON7) & 0xc) >> 2) + 2,
			s3c_get_hclk() / 1000000);
	return 0;
}

late_initcall(s3c24xx_dump_clocks);