diff options
author | Kukjin Kim <kgene.kim@samsung.com> | 2013-01-21 18:24:34 -0500 |
---|---|---|
committer | Kukjin Kim <kgene.kim@samsung.com> | 2013-01-21 20:04:21 -0500 |
commit | dbb8fd34c401b3526ccaab5a490088d19ac3701e (patch) | |
tree | e406efa3930220ceab0f965c530734b470109fad /arch/arm/mach-s3c24xx | |
parent | c896ba8883b689fa78e24d881d1387f65f9d3805 (diff) |
ARM: S3C24XX: Move mach-s3c2412/ cpufreq driver into mach-s3c24xx/
This patch moves mach-s3c2412/cpufreq driver into mach-s3c24xx/
and removes arch/arm/mach-s3c2412/ directory in kernel.
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
Diffstat (limited to 'arch/arm/mach-s3c24xx')
-rw-r--r-- | arch/arm/mach-s3c24xx/Kconfig | 8 | ||||
-rw-r--r-- | arch/arm/mach-s3c24xx/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-s3c24xx/cpufreq-s3c2412.c | 257 |
3 files changed, 266 insertions, 0 deletions
diff --git a/arch/arm/mach-s3c24xx/Kconfig b/arch/arm/mach-s3c24xx/Kconfig index 5cc740c07457..f1d3951fc102 100644 --- a/arch/arm/mach-s3c24xx/Kconfig +++ b/arch/arm/mach-s3c24xx/Kconfig | |||
@@ -280,6 +280,14 @@ config CPU_S3C2412_ONLY | |||
280 | !CPU_S3C2443 && CPU_S3C2412 | 280 | !CPU_S3C2443 && CPU_S3C2412 |
281 | default y | 281 | default y |
282 | 282 | ||
283 | config S3C2412_CPUFREQ | ||
284 | bool | ||
285 | depends on CPU_FREQ_S3C24XX && CPU_S3C2412 | ||
286 | default y | ||
287 | select S3C2412_IOTIMING | ||
288 | help | ||
289 | CPU Frequency scaling support for S3C2412 and S3C2413 SoC CPUs. | ||
290 | |||
283 | config S3C2412_DMA | 291 | config S3C2412_DMA |
284 | bool | 292 | bool |
285 | help | 293 | help |
diff --git a/arch/arm/mach-s3c24xx/Makefile b/arch/arm/mach-s3c24xx/Makefile index ecace54fd1d5..0f042d180fb8 100644 --- a/arch/arm/mach-s3c24xx/Makefile +++ b/arch/arm/mach-s3c24xx/Makefile | |||
@@ -23,6 +23,7 @@ obj-$(CONFIG_S3C2410_PLL) += pll-s3c2410.o | |||
23 | obj-$(CONFIG_S3C2410_PM) += pm-s3c2410.o sleep-s3c2410.o | 23 | obj-$(CONFIG_S3C2410_PM) += pm-s3c2410.o sleep-s3c2410.o |
24 | 24 | ||
25 | obj-$(CONFIG_CPU_S3C2412) += s3c2412.o irq-s3c2412.o clock-s3c2412.o | 25 | obj-$(CONFIG_CPU_S3C2412) += s3c2412.o irq-s3c2412.o clock-s3c2412.o |
26 | obj-$(CONFIG_S3C2412_CPUFREQ) += cpufreq-s3c2412.o | ||
26 | obj-$(CONFIG_S3C2412_DMA) += dma-s3c2412.o | 27 | obj-$(CONFIG_S3C2412_DMA) += dma-s3c2412.o |
27 | obj-$(CONFIG_S3C2412_PM) += pm-s3c2412.o | 28 | obj-$(CONFIG_S3C2412_PM) += pm-s3c2412.o |
28 | obj-$(CONFIG_S3C2412_PM_SLEEP) += sleep-s3c2412.o | 29 | obj-$(CONFIG_S3C2412_PM_SLEEP) += sleep-s3c2412.o |
diff --git a/arch/arm/mach-s3c24xx/cpufreq-s3c2412.c b/arch/arm/mach-s3c24xx/cpufreq-s3c2412.c new file mode 100644 index 000000000000..c8f05f309eee --- /dev/null +++ b/arch/arm/mach-s3c24xx/cpufreq-s3c2412.c | |||
@@ -0,0 +1,257 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Simtec Electronics | ||
3 | * http://armlinux.simtec.co.uk/ | ||
4 | * Ben Dooks <ben@simtec.co.uk> | ||
5 | * | ||
6 | * S3C2412 CPU Frequency scalling | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/init.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/ioport.h> | ||
17 | #include <linux/cpufreq.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/clk.h> | ||
21 | #include <linux/err.h> | ||
22 | #include <linux/io.h> | ||
23 | |||
24 | #include <asm/mach/arch.h> | ||
25 | #include <asm/mach/map.h> | ||
26 | |||
27 | #include <mach/regs-clock.h> | ||
28 | #include <mach/regs-s3c2412-mem.h> | ||
29 | |||
30 | #include <plat/cpu.h> | ||
31 | #include <plat/clock.h> | ||
32 | #include <plat/cpu-freq-core.h> | ||
33 | |||
34 | /* our clock resources. */ | ||
35 | static struct clk *xtal; | ||
36 | static struct clk *fclk; | ||
37 | static struct clk *hclk; | ||
38 | static struct clk *armclk; | ||
39 | |||
40 | /* HDIV: 1, 2, 3, 4, 6, 8 */ | ||
41 | |||
42 | static int s3c2412_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg) | ||
43 | { | ||
44 | unsigned int hdiv, pdiv, armdiv, dvs; | ||
45 | unsigned long hclk, fclk, armclk, armdiv_clk; | ||
46 | unsigned long hclk_max; | ||
47 | |||
48 | fclk = cfg->freq.fclk; | ||
49 | armclk = cfg->freq.armclk; | ||
50 | hclk_max = cfg->max.hclk; | ||
51 | |||
52 | /* We can't run hclk above armclk as at the best we have to | ||
53 | * have armclk and hclk in dvs mode. */ | ||
54 | |||
55 | if (hclk_max > armclk) | ||
56 | hclk_max = armclk; | ||
57 | |||
58 | s3c_freq_dbg("%s: fclk=%lu, armclk=%lu, hclk_max=%lu\n", | ||
59 | __func__, fclk, armclk, hclk_max); | ||
60 | s3c_freq_dbg("%s: want f=%lu, arm=%lu, h=%lu, p=%lu\n", | ||
61 | __func__, cfg->freq.fclk, cfg->freq.armclk, | ||
62 | cfg->freq.hclk, cfg->freq.pclk); | ||
63 | |||
64 | armdiv = fclk / armclk; | ||
65 | |||
66 | if (armdiv < 1) | ||
67 | armdiv = 1; | ||
68 | if (armdiv > 2) | ||
69 | armdiv = 2; | ||
70 | |||
71 | cfg->divs.arm_divisor = armdiv; | ||
72 | armdiv_clk = fclk / armdiv; | ||
73 | |||
74 | hdiv = armdiv_clk / hclk_max; | ||
75 | if (hdiv < 1) | ||
76 | hdiv = 1; | ||
77 | |||
78 | cfg->freq.hclk = hclk = armdiv_clk / hdiv; | ||
79 | |||
80 | /* set dvs depending on whether we reached armclk or not. */ | ||
81 | cfg->divs.dvs = dvs = armclk < armdiv_clk; | ||
82 | |||
83 | /* update the actual armclk we achieved. */ | ||
84 | cfg->freq.armclk = dvs ? hclk : armdiv_clk; | ||
85 | |||
86 | s3c_freq_dbg("%s: armclk %lu, hclk %lu, armdiv %d, hdiv %d, dvs %d\n", | ||
87 | __func__, armclk, hclk, armdiv, hdiv, cfg->divs.dvs); | ||
88 | |||
89 | if (hdiv > 4) | ||
90 | goto invalid; | ||
91 | |||
92 | pdiv = (hclk > cfg->max.pclk) ? 2 : 1; | ||
93 | |||
94 | if ((hclk / pdiv) > cfg->max.pclk) | ||
95 | pdiv++; | ||
96 | |||
97 | cfg->freq.pclk = hclk / pdiv; | ||
98 | |||
99 | s3c_freq_dbg("%s: pdiv %d\n", __func__, pdiv); | ||
100 | |||
101 | if (pdiv > 2) | ||
102 | goto invalid; | ||
103 | |||
104 | pdiv *= hdiv; | ||
105 | |||
106 | /* store the result, and then return */ | ||
107 | |||
108 | cfg->divs.h_divisor = hdiv * armdiv; | ||
109 | cfg->divs.p_divisor = pdiv * armdiv; | ||
110 | |||
111 | return 0; | ||
112 | |||
113 | invalid: | ||
114 | return -EINVAL; | ||
115 | } | ||
116 | |||
117 | static void s3c2412_cpufreq_setdivs(struct s3c_cpufreq_config *cfg) | ||
118 | { | ||
119 | unsigned long clkdiv; | ||
120 | unsigned long olddiv; | ||
121 | |||
122 | olddiv = clkdiv = __raw_readl(S3C2410_CLKDIVN); | ||
123 | |||
124 | /* clear off current clock info */ | ||
125 | |||
126 | clkdiv &= ~S3C2412_CLKDIVN_ARMDIVN; | ||
127 | clkdiv &= ~S3C2412_CLKDIVN_HDIVN_MASK; | ||
128 | clkdiv &= ~S3C2412_CLKDIVN_PDIVN; | ||
129 | |||
130 | if (cfg->divs.arm_divisor == 2) | ||
131 | clkdiv |= S3C2412_CLKDIVN_ARMDIVN; | ||
132 | |||
133 | clkdiv |= ((cfg->divs.h_divisor / cfg->divs.arm_divisor) - 1); | ||
134 | |||
135 | if (cfg->divs.p_divisor != cfg->divs.h_divisor) | ||
136 | clkdiv |= S3C2412_CLKDIVN_PDIVN; | ||
137 | |||
138 | s3c_freq_dbg("%s: div %08lx => %08lx\n", __func__, olddiv, clkdiv); | ||
139 | __raw_writel(clkdiv, S3C2410_CLKDIVN); | ||
140 | |||
141 | clk_set_parent(armclk, cfg->divs.dvs ? hclk : fclk); | ||
142 | } | ||
143 | |||
144 | static void s3c2412_cpufreq_setrefresh(struct s3c_cpufreq_config *cfg) | ||
145 | { | ||
146 | struct s3c_cpufreq_board *board = cfg->board; | ||
147 | unsigned long refresh; | ||
148 | |||
149 | s3c_freq_dbg("%s: refresh %u ns, hclk %lu\n", __func__, | ||
150 | board->refresh, cfg->freq.hclk); | ||
151 | |||
152 | /* Reduce both the refresh time (in ns) and the frequency (in MHz) | ||
153 | * by 10 each to ensure that we do not overflow 32 bit numbers. This | ||
154 | * should work for HCLK up to 133MHz and refresh period up to 30usec. | ||
155 | */ | ||
156 | |||
157 | refresh = (board->refresh / 10); | ||
158 | refresh *= (cfg->freq.hclk / 100); | ||
159 | refresh /= (1 * 1000 * 1000); /* 10^6 */ | ||
160 | |||
161 | s3c_freq_dbg("%s: setting refresh 0x%08lx\n", __func__, refresh); | ||
162 | __raw_writel(refresh, S3C2412_REFRESH); | ||
163 | } | ||
164 | |||
165 | /* set the default cpu frequency information, based on an 200MHz part | ||
166 | * as we have no other way of detecting the speed rating in software. | ||
167 | */ | ||
168 | |||
169 | static struct s3c_cpufreq_info s3c2412_cpufreq_info = { | ||
170 | .max = { | ||
171 | .fclk = 200000000, | ||
172 | .hclk = 100000000, | ||
173 | .pclk = 50000000, | ||
174 | }, | ||
175 | |||
176 | .latency = 5000000, /* 5ms */ | ||
177 | |||
178 | .locktime_m = 150, | ||
179 | .locktime_u = 150, | ||
180 | .locktime_bits = 16, | ||
181 | |||
182 | .name = "s3c2412", | ||
183 | .set_refresh = s3c2412_cpufreq_setrefresh, | ||
184 | .set_divs = s3c2412_cpufreq_setdivs, | ||
185 | .calc_divs = s3c2412_cpufreq_calcdivs, | ||
186 | |||
187 | .calc_iotiming = s3c2412_iotiming_calc, | ||
188 | .set_iotiming = s3c2412_iotiming_set, | ||
189 | .get_iotiming = s3c2412_iotiming_get, | ||
190 | |||
191 | .resume_clocks = s3c2412_setup_clocks, | ||
192 | |||
193 | .debug_io_show = s3c_cpufreq_debugfs_call(s3c2412_iotiming_debugfs), | ||
194 | }; | ||
195 | |||
196 | static int s3c2412_cpufreq_add(struct device *dev, | ||
197 | struct subsys_interface *sif) | ||
198 | { | ||
199 | unsigned long fclk_rate; | ||
200 | |||
201 | hclk = clk_get(NULL, "hclk"); | ||
202 | if (IS_ERR(hclk)) { | ||
203 | printk(KERN_ERR "%s: cannot find hclk clock\n", __func__); | ||
204 | return -ENOENT; | ||
205 | } | ||
206 | |||
207 | fclk = clk_get(NULL, "fclk"); | ||
208 | if (IS_ERR(fclk)) { | ||
209 | printk(KERN_ERR "%s: cannot find fclk clock\n", __func__); | ||
210 | goto err_fclk; | ||
211 | } | ||
212 | |||
213 | fclk_rate = clk_get_rate(fclk); | ||
214 | if (fclk_rate > 200000000) { | ||
215 | printk(KERN_INFO | ||
216 | "%s: fclk %ld MHz, assuming 266MHz capable part\n", | ||
217 | __func__, fclk_rate / 1000000); | ||
218 | s3c2412_cpufreq_info.max.fclk = 266000000; | ||
219 | s3c2412_cpufreq_info.max.hclk = 133000000; | ||
220 | s3c2412_cpufreq_info.max.pclk = 66000000; | ||
221 | } | ||
222 | |||
223 | armclk = clk_get(NULL, "armclk"); | ||
224 | if (IS_ERR(armclk)) { | ||
225 | printk(KERN_ERR "%s: cannot find arm clock\n", __func__); | ||
226 | goto err_armclk; | ||
227 | } | ||
228 | |||
229 | xtal = clk_get(NULL, "xtal"); | ||
230 | if (IS_ERR(xtal)) { | ||
231 | printk(KERN_ERR "%s: cannot find xtal clock\n", __func__); | ||
232 | goto err_xtal; | ||
233 | } | ||
234 | |||
235 | return s3c_cpufreq_register(&s3c2412_cpufreq_info); | ||
236 | |||
237 | err_xtal: | ||
238 | clk_put(armclk); | ||
239 | err_armclk: | ||
240 | clk_put(fclk); | ||
241 | err_fclk: | ||
242 | clk_put(hclk); | ||
243 | |||
244 | return -ENOENT; | ||
245 | } | ||
246 | |||
247 | static struct subsys_interface s3c2412_cpufreq_interface = { | ||
248 | .name = "s3c2412_cpufreq", | ||
249 | .subsys = &s3c2412_subsys, | ||
250 | .add_dev = s3c2412_cpufreq_add, | ||
251 | }; | ||
252 | |||
253 | static int s3c2412_cpufreq_init(void) | ||
254 | { | ||
255 | return subsys_interface_register(&s3c2412_cpufreq_interface); | ||
256 | } | ||
257 | arch_initcall(s3c2412_cpufreq_init); | ||