Commit a24c091d authored by Ben Dooks's avatar Ben Dooks Committed by Ben Dooks

ARM: S3C2410: CPUFREQ: Add core support.

Add core support for frequency scaling on the S3C2410 SoC.
Signed-off-by: default avatarBen Dooks <ben@simtec.co.uk>
Signed-off-by: default avatarBen Dooks <ben-linux@fluff.org>
parent 831a6fcb
...@@ -12,6 +12,7 @@ config CPU_S3C2410 ...@@ -12,6 +12,7 @@ config CPU_S3C2410
select S3C2410_GPIO select S3C2410_GPIO
select CPU_LLSERIAL_S3C2410 select CPU_LLSERIAL_S3C2410
select S3C2410_PM if PM select S3C2410_PM if PM
select S3C2410_CPUFREQ if CPU_FREQ_S3C24XX
help help
Support for S3C2410 and S3C2410A family from the S3C24XX line Support for S3C2410 and S3C2410A family from the S3C24XX line
of Samsung Mobile CPUs. of Samsung Mobile CPUs.
...@@ -45,6 +46,15 @@ config MACH_BAST_IDE ...@@ -45,6 +46,15 @@ config MACH_BAST_IDE
Internal node for machines with an BAST style IDE Internal node for machines with an BAST style IDE
interface interface
# cpu frequency scaling support
config S3C2410_CPUFREQ
bool
depends on CPU_FREQ_S3C24XX && CPU_S3C2410
select S3C2410_CPUFREQ_UTILS
help
CPU Frequency scaling support for S3C2410
menu "S3C2410 Machines" menu "S3C2410 Machines"
config ARCH_SMDK2410 config ARCH_SMDK2410
...@@ -79,6 +89,7 @@ config MACH_N30 ...@@ -79,6 +89,7 @@ config MACH_N30
config ARCH_BAST config ARCH_BAST
bool "Simtec Electronics BAST (EB2410ITX)" bool "Simtec Electronics BAST (EB2410ITX)"
select CPU_S3C2410 select CPU_S3C2410
select S3C2410_IOTIMING if S3C2410_CPUFREQ
select PM_SIMTEC if PM select PM_SIMTEC if PM
select SIMTEC_NOR select SIMTEC_NOR
select MACH_BAST_IDE select MACH_BAST_IDE
......
...@@ -15,6 +15,7 @@ obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o ...@@ -15,6 +15,7 @@ obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o
obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o
obj-$(CONFIG_S3C2410_PM) += pm.o sleep.o obj-$(CONFIG_S3C2410_PM) += pm.o sleep.o
obj-$(CONFIG_S3C2410_GPIO) += gpio.o obj-$(CONFIG_S3C2410_GPIO) += gpio.o
obj-$(CONFIG_S3C2410_CPUFREQ) += cpu-freq.o
# Machine support # Machine support
......
/* linux/arch/arm/mach-s3c2410/cpu-freq.c
*
* Copyright (c) 2006,2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 CPU Frequency scaling
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/cpufreq.h>
#include <linux/sysdev.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <mach/regs-clock.h>
#include <plat/cpu.h>
#include <plat/clock.h>
#include <plat/cpu-freq-core.h>
/* Note, 2410A has an extra mode for 1:4:4 ratio, bit 2 of CLKDIV */
static void s3c2410_cpufreq_setdivs(struct s3c_cpufreq_config *cfg)
{
u32 clkdiv = 0;
if (cfg->divs.h_divisor == 2)
clkdiv |= S3C2410_CLKDIVN_HDIVN;
if (cfg->divs.p_divisor != cfg->divs.h_divisor)
clkdiv |= S3C2410_CLKDIVN_PDIVN;
__raw_writel(clkdiv, S3C2410_CLKDIVN);
}
static int s3c2410_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg)
{
unsigned long hclk, fclk, pclk;
unsigned int hdiv, pdiv;
unsigned long hclk_max;
fclk = cfg->freq.fclk;
hclk_max = cfg->max.hclk;
cfg->freq.armclk = fclk;
s3c_freq_dbg("%s: fclk is %lu, max hclk %lu\n",
__func__, fclk, hclk_max);
hdiv = (fclk > cfg->max.hclk) ? 2 : 1;
hclk = fclk / hdiv;
if (hclk > cfg->max.hclk) {
s3c_freq_dbg("%s: hclk too big\n", __func__);
return -EINVAL;
}
pdiv = (hclk > cfg->max.pclk) ? 2 : 1;
pclk = hclk / pdiv;
if (pclk > cfg->max.pclk) {
s3c_freq_dbg("%s: pclk too big\n", __func__);
return -EINVAL;
}
pdiv *= hdiv;
/* record the result */
cfg->divs.p_divisor = pdiv;
cfg->divs.h_divisor = hdiv;
return 0 ;
}
static struct s3c_cpufreq_info s3c2410_cpufreq_info = {
.max = {
.fclk = 200000000,
.hclk = 100000000,
.pclk = 50000000,
},
/* transition latency is about 5ms worst-case, so
* set 10ms to be sure */
.latency = 10000000,
.locktime_m = 150,
.locktime_u = 150,
.locktime_bits = 12,
.need_pll = 1,
.name = "s3c2410",
.calc_iotiming = s3c2410_iotiming_calc,
.set_iotiming = s3c2410_iotiming_set,
.get_iotiming = s3c2410_iotiming_get,
.resume_clocks = s3c2410_setup_clocks,
.set_fvco = s3c2410_set_fvco,
.set_refresh = s3c2410_cpufreq_setrefresh,
.set_divs = s3c2410_cpufreq_setdivs,
.calc_divs = s3c2410_cpufreq_calcdivs,
};
static int s3c2410_cpufreq_add(struct sys_device *sysdev)
{
return s3c_cpufreq_register(&s3c2410_cpufreq_info);
}
static struct sysdev_driver s3c2410_cpufreq_driver = {
.add = s3c2410_cpufreq_add,
};
static int __init s3c2410_cpufreq_init(void)
{
return sysdev_driver_register(&s3c2410_sysclass,
&s3c2410_cpufreq_driver);
}
arch_initcall(s3c2410_cpufreq_init);
static int s3c2410a_cpufreq_add(struct sys_device *sysdev)
{
/* alter the maximum freq settings for S3C2410A. If a board knows
* it only has a maximum of 200, then it should register its own
* limits. */
s3c2410_cpufreq_info.max.fclk = 266000000;
s3c2410_cpufreq_info.max.hclk = 133000000;
s3c2410_cpufreq_info.max.pclk = 66500000;
s3c2410_cpufreq_info.name = "s3c2410a";
return s3c2410_cpufreq_add(sysdev);
}
static struct sysdev_driver s3c2410a_cpufreq_driver = {
.add = s3c2410a_cpufreq_add,
};
static int __init s3c2410a_cpufreq_init(void)
{
return sysdev_driver_register(&s3c2410a_sysclass,
&s3c2410a_cpufreq_driver);
}
arch_initcall(s3c2410a_cpufreq_init);
...@@ -116,6 +116,13 @@ config S3C2410_IOTIMING ...@@ -116,6 +116,13 @@ config S3C2410_IOTIMING
Internal node to select io timing code that is common to the s3c2410 Internal node to select io timing code that is common to the s3c2410
and s3c2440/s3c2442 cpu frequency support. and s3c2440/s3c2442 cpu frequency support.
config S3C2410_CPUFREQ_UTILS
bool
depends on CPU_FREQ_S3C24XX
help
Internal node to select timing code that is common to the s3c2410
and s3c2440/s3c244 cpu frequency support.
config MACH_SMDK config MACH_SMDK
bool bool
help help
......
...@@ -36,6 +36,7 @@ obj-$(CONFIG_S3C2410_CLOCK) += s3c2410-clock.o ...@@ -36,6 +36,7 @@ obj-$(CONFIG_S3C2410_CLOCK) += s3c2410-clock.o
obj-$(CONFIG_S3C2410_DMA) += dma.o obj-$(CONFIG_S3C2410_DMA) += dma.o
obj-$(CONFIG_S3C24XX_ADC) += adc.o obj-$(CONFIG_S3C24XX_ADC) += adc.o
obj-$(CONFIG_S3C2410_IOTIMING) += s3c2410-iotiming.o obj-$(CONFIG_S3C2410_IOTIMING) += s3c2410-iotiming.o
obj-$(CONFIG_S3C2410_CPUFREQ_UTILS) += s3c2410-cpufreq-utils.o
# device specific setup and/or initialisation # device specific setup and/or initialisation
obj-$(CONFIG_ARCH_S3C2410) += setup-i2c.o obj-$(CONFIG_ARCH_S3C2410) += setup-i2c.o
......
/* linux/arch/arm/plat-s3c24xx/s3c2410-cpufreq-utils.c
*
* Copyright (c) 2009 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
* S3C24XX CPU Frequency scaling - utils for S3C2410/S3C2440/S3C2442
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/cpufreq.h>
#include <linux/io.h>
#include <mach/map.h>
#include <mach/regs-mem.h>
#include <mach/regs-clock.h>
#include <plat/cpu-freq-core.h>
/**
* s3c2410_cpufreq_setrefresh - set SDRAM refresh value
* @cfg: The frequency configuration
*
* Set the SDRAM refresh value appropriately for the configured
* frequency.
*/
void s3c2410_cpufreq_setrefresh(struct s3c_cpufreq_config *cfg)
{
struct s3c_cpufreq_board *board = cfg->board;
unsigned long refresh;
unsigned long refval;
/* Reduce both the refresh time (in ns) and the frequency (in MHz)
* down to ensure that we do not overflow 32 bit numbers.
*
* This should work for HCLK up to 133MHz and refresh period up
* to 30usec.
*/
refresh = (cfg->freq.hclk / 100) * (board->refresh / 10);
refresh = DIV_ROUND_UP(refresh, (1000 * 1000)); /* apply scale */
refresh = (1 << 11) + 1 - refresh;
s3c_freq_dbg("%s: refresh value %lu\n", __func__, refresh);
refval = __raw_readl(S3C2410_REFRESH);
refval &= ~((1 << 12) - 1);
refval |= refresh;
__raw_writel(refval, S3C2410_REFRESH);
}
/**
* s3c2410_set_fvco - set the PLL value
* @cfg: The frequency configuration
*/
void s3c2410_set_fvco(struct s3c_cpufreq_config *cfg)
{
__raw_writel(cfg->pll.index, S3C2410_MPLLCON);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment