aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorBen Dooks <ben@simtec.co.uk>2009-07-30 18:23:27 -0400
committerBen Dooks <ben-linux@fluff.org>2009-07-30 18:22:52 -0400
commita24c091db988551e2c350cfde9eb80ab6e791ffb (patch)
tree487a86d71ed0a97c27c25de9e618e7db25066c8e /arch/arm
parent831a6fcb9393960b35173fa2e0f835b710152fff (diff)
ARM: S3C2410: CPUFREQ: Add core support.
Add core support for frequency scaling on the S3C2410 SoC. Signed-off-by: Ben Dooks <ben@simtec.co.uk> Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-s3c2410/Kconfig11
-rw-r--r--arch/arm/mach-s3c2410/Makefile1
-rw-r--r--arch/arm/mach-s3c2410/cpu-freq.c157
-rw-r--r--arch/arm/plat-s3c24xx/Kconfig7
-rw-r--r--arch/arm/plat-s3c24xx/Makefile1
-rw-r--r--arch/arm/plat-s3c24xx/s3c2410-cpufreq-utils.c64
6 files changed, 241 insertions, 0 deletions
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
index 41bb65d5b91f..a7f70e18ccb4 100644
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -12,6 +12,7 @@ config CPU_S3C2410
12 select S3C2410_GPIO 12 select S3C2410_GPIO
13 select CPU_LLSERIAL_S3C2410 13 select CPU_LLSERIAL_S3C2410
14 select S3C2410_PM if PM 14 select S3C2410_PM if PM
15 select S3C2410_CPUFREQ if CPU_FREQ_S3C24XX
15 help 16 help
16 Support for S3C2410 and S3C2410A family from the S3C24XX line 17 Support for S3C2410 and S3C2410A family from the S3C24XX line
17 of Samsung Mobile CPUs. 18 of Samsung Mobile CPUs.
@@ -45,6 +46,15 @@ config MACH_BAST_IDE
45 Internal node for machines with an BAST style IDE 46 Internal node for machines with an BAST style IDE
46 interface 47 interface
47 48
49# cpu frequency scaling support
50
51config S3C2410_CPUFREQ
52 bool
53 depends on CPU_FREQ_S3C24XX && CPU_S3C2410
54 select S3C2410_CPUFREQ_UTILS
55 help
56 CPU Frequency scaling support for S3C2410
57
48menu "S3C2410 Machines" 58menu "S3C2410 Machines"
49 59
50config ARCH_SMDK2410 60config ARCH_SMDK2410
@@ -79,6 +89,7 @@ config MACH_N30
79config ARCH_BAST 89config ARCH_BAST
80 bool "Simtec Electronics BAST (EB2410ITX)" 90 bool "Simtec Electronics BAST (EB2410ITX)"
81 select CPU_S3C2410 91 select CPU_S3C2410
92 select S3C2410_IOTIMING if S3C2410_CPUFREQ
82 select PM_SIMTEC if PM 93 select PM_SIMTEC if PM
83 select SIMTEC_NOR 94 select SIMTEC_NOR
84 select MACH_BAST_IDE 95 select MACH_BAST_IDE
diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
index fca02f82711c..cc25eb0eb2cd 100644
--- a/arch/arm/mach-s3c2410/Makefile
+++ b/arch/arm/mach-s3c2410/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o
15obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o 15obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o
16obj-$(CONFIG_S3C2410_PM) += pm.o sleep.o 16obj-$(CONFIG_S3C2410_PM) += pm.o sleep.o
17obj-$(CONFIG_S3C2410_GPIO) += gpio.o 17obj-$(CONFIG_S3C2410_GPIO) += gpio.o
18obj-$(CONFIG_S3C2410_CPUFREQ) += cpu-freq.o
18 19
19# Machine support 20# Machine support
20 21
diff --git a/arch/arm/mach-s3c2410/cpu-freq.c b/arch/arm/mach-s3c2410/cpu-freq.c
new file mode 100644
index 000000000000..f2cbdbab0df6
--- /dev/null
+++ b/arch/arm/mach-s3c2410/cpu-freq.c
@@ -0,0 +1,157 @@
1/* linux/arch/arm/mach-s3c2410/cpu-freq.c
2 *
3 * Copyright (c) 2006,2008 Simtec Electronics
4 * http://armlinux.simtec.co.uk/
5 * Ben Dooks <ben@simtec.co.uk>
6 *
7 * S3C2410 CPU Frequency scaling
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12*/
13
14#include <linux/init.h>
15#include <linux/module.h>
16#include <linux/interrupt.h>
17#include <linux/ioport.h>
18#include <linux/cpufreq.h>
19#include <linux/sysdev.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
29#include <plat/cpu.h>
30#include <plat/clock.h>
31#include <plat/cpu-freq-core.h>
32
33/* Note, 2410A has an extra mode for 1:4:4 ratio, bit 2 of CLKDIV */
34
35static void s3c2410_cpufreq_setdivs(struct s3c_cpufreq_config *cfg)
36{
37 u32 clkdiv = 0;
38
39 if (cfg->divs.h_divisor == 2)
40 clkdiv |= S3C2410_CLKDIVN_HDIVN;
41
42 if (cfg->divs.p_divisor != cfg->divs.h_divisor)
43 clkdiv |= S3C2410_CLKDIVN_PDIVN;
44
45 __raw_writel(clkdiv, S3C2410_CLKDIVN);
46}
47
48static int s3c2410_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg)
49{
50 unsigned long hclk, fclk, pclk;
51 unsigned int hdiv, pdiv;
52 unsigned long hclk_max;
53
54 fclk = cfg->freq.fclk;
55 hclk_max = cfg->max.hclk;
56
57 cfg->freq.armclk = fclk;
58
59 s3c_freq_dbg("%s: fclk is %lu, max hclk %lu\n",
60 __func__, fclk, hclk_max);
61
62 hdiv = (fclk > cfg->max.hclk) ? 2 : 1;
63 hclk = fclk / hdiv;
64
65 if (hclk > cfg->max.hclk) {
66 s3c_freq_dbg("%s: hclk too big\n", __func__);
67 return -EINVAL;
68 }
69
70 pdiv = (hclk > cfg->max.pclk) ? 2 : 1;
71 pclk = hclk / pdiv;
72
73 if (pclk > cfg->max.pclk) {
74 s3c_freq_dbg("%s: pclk too big\n", __func__);
75 return -EINVAL;
76 }
77
78 pdiv *= hdiv;
79
80 /* record the result */
81 cfg->divs.p_divisor = pdiv;
82 cfg->divs.h_divisor = hdiv;
83
84 return 0 ;
85}
86
87static struct s3c_cpufreq_info s3c2410_cpufreq_info = {
88 .max = {
89 .fclk = 200000000,
90 .hclk = 100000000,
91 .pclk = 50000000,
92 },
93
94 /* transition latency is about 5ms worst-case, so
95 * set 10ms to be sure */
96 .latency = 10000000,
97
98 .locktime_m = 150,
99 .locktime_u = 150,
100 .locktime_bits = 12,
101
102 .need_pll = 1,
103
104 .name = "s3c2410",
105 .calc_iotiming = s3c2410_iotiming_calc,
106 .set_iotiming = s3c2410_iotiming_set,
107 .get_iotiming = s3c2410_iotiming_get,
108 .resume_clocks = s3c2410_setup_clocks,
109
110 .set_fvco = s3c2410_set_fvco,
111 .set_refresh = s3c2410_cpufreq_setrefresh,
112 .set_divs = s3c2410_cpufreq_setdivs,
113 .calc_divs = s3c2410_cpufreq_calcdivs,
114};
115
116static int s3c2410_cpufreq_add(struct sys_device *sysdev)
117{
118 return s3c_cpufreq_register(&s3c2410_cpufreq_info);
119}
120
121static struct sysdev_driver s3c2410_cpufreq_driver = {
122 .add = s3c2410_cpufreq_add,
123};
124
125static int __init s3c2410_cpufreq_init(void)
126{
127 return sysdev_driver_register(&s3c2410_sysclass,
128 &s3c2410_cpufreq_driver);
129}
130
131arch_initcall(s3c2410_cpufreq_init);
132
133static int s3c2410a_cpufreq_add(struct sys_device *sysdev)
134{
135 /* alter the maximum freq settings for S3C2410A. If a board knows
136 * it only has a maximum of 200, then it should register its own
137 * limits. */
138
139 s3c2410_cpufreq_info.max.fclk = 266000000;
140 s3c2410_cpufreq_info.max.hclk = 133000000;
141 s3c2410_cpufreq_info.max.pclk = 66500000;
142 s3c2410_cpufreq_info.name = "s3c2410a";
143
144 return s3c2410_cpufreq_add(sysdev);
145}
146
147static struct sysdev_driver s3c2410a_cpufreq_driver = {
148 .add = s3c2410a_cpufreq_add,
149};
150
151static int __init s3c2410a_cpufreq_init(void)
152{
153 return sysdev_driver_register(&s3c2410a_sysclass,
154 &s3c2410a_cpufreq_driver);
155}
156
157arch_initcall(s3c2410a_cpufreq_init);
diff --git a/arch/arm/plat-s3c24xx/Kconfig b/arch/arm/plat-s3c24xx/Kconfig
index d82d30c2f059..a547c79ed6ce 100644
--- a/arch/arm/plat-s3c24xx/Kconfig
+++ b/arch/arm/plat-s3c24xx/Kconfig
@@ -116,6 +116,13 @@ config S3C2410_IOTIMING
116 Internal node to select io timing code that is common to the s3c2410 116 Internal node to select io timing code that is common to the s3c2410
117 and s3c2440/s3c2442 cpu frequency support. 117 and s3c2440/s3c2442 cpu frequency support.
118 118
119config S3C2410_CPUFREQ_UTILS
120 bool
121 depends on CPU_FREQ_S3C24XX
122 help
123 Internal node to select timing code that is common to the s3c2410
124 and s3c2440/s3c244 cpu frequency support.
125
119config MACH_SMDK 126config MACH_SMDK
120 bool 127 bool
121 help 128 help
diff --git a/arch/arm/plat-s3c24xx/Makefile b/arch/arm/plat-s3c24xx/Makefile
index 6f9afd13ab4f..b28fe9cb0e5e 100644
--- a/arch/arm/plat-s3c24xx/Makefile
+++ b/arch/arm/plat-s3c24xx/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_S3C2410_CLOCK) += s3c2410-clock.o
36obj-$(CONFIG_S3C2410_DMA) += dma.o 36obj-$(CONFIG_S3C2410_DMA) += dma.o
37obj-$(CONFIG_S3C24XX_ADC) += adc.o 37obj-$(CONFIG_S3C24XX_ADC) += adc.o
38obj-$(CONFIG_S3C2410_IOTIMING) += s3c2410-iotiming.o 38obj-$(CONFIG_S3C2410_IOTIMING) += s3c2410-iotiming.o
39obj-$(CONFIG_S3C2410_CPUFREQ_UTILS) += s3c2410-cpufreq-utils.o
39 40
40# device specific setup and/or initialisation 41# device specific setup and/or initialisation
41obj-$(CONFIG_ARCH_S3C2410) += setup-i2c.o 42obj-$(CONFIG_ARCH_S3C2410) += setup-i2c.o
diff --git a/arch/arm/plat-s3c24xx/s3c2410-cpufreq-utils.c b/arch/arm/plat-s3c24xx/s3c2410-cpufreq-utils.c
new file mode 100644
index 000000000000..43ea80190d87
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/s3c2410-cpufreq-utils.c
@@ -0,0 +1,64 @@
1/* linux/arch/arm/plat-s3c24xx/s3c2410-cpufreq-utils.c
2 *
3 * Copyright (c) 2009 Simtec Electronics
4 * http://armlinux.simtec.co.uk/
5 * Ben Dooks <ben@simtec.co.uk>
6 *
7 * S3C24XX CPU Frequency scaling - utils for S3C2410/S3C2440/S3C2442
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12*/
13
14#include <linux/kernel.h>
15#include <linux/errno.h>
16#include <linux/cpufreq.h>
17#include <linux/io.h>
18
19#include <mach/map.h>
20#include <mach/regs-mem.h>
21#include <mach/regs-clock.h>
22
23#include <plat/cpu-freq-core.h>
24
25/**
26 * s3c2410_cpufreq_setrefresh - set SDRAM refresh value
27 * @cfg: The frequency configuration
28 *
29 * Set the SDRAM refresh value appropriately for the configured
30 * frequency.
31 */
32void s3c2410_cpufreq_setrefresh(struct s3c_cpufreq_config *cfg)
33{
34 struct s3c_cpufreq_board *board = cfg->board;
35 unsigned long refresh;
36 unsigned long refval;
37
38 /* Reduce both the refresh time (in ns) and the frequency (in MHz)
39 * down to ensure that we do not overflow 32 bit numbers.
40 *
41 * This should work for HCLK up to 133MHz and refresh period up
42 * to 30usec.
43 */
44
45 refresh = (cfg->freq.hclk / 100) * (board->refresh / 10);
46 refresh = DIV_ROUND_UP(refresh, (1000 * 1000)); /* apply scale */
47 refresh = (1 << 11) + 1 - refresh;
48
49 s3c_freq_dbg("%s: refresh value %lu\n", __func__, refresh);
50
51 refval = __raw_readl(S3C2410_REFRESH);
52 refval &= ~((1 << 12) - 1);
53 refval |= refresh;
54 __raw_writel(refval, S3C2410_REFRESH);
55}
56
57/**
58 * s3c2410_set_fvco - set the PLL value
59 * @cfg: The frequency configuration
60 */
61void s3c2410_set_fvco(struct s3c_cpufreq_config *cfg)
62{
63 __raw_writel(cfg->pll.index, S3C2410_MPLLCON);
64}