Commit cf821923 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/davej/cpufreq

Pull cpufreq updates for 3.4 from Dave Jones: new drivers and some fixes.

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/davej/cpufreq:
  provide disable_cpufreq() function to disable the API.
  EXYNOS5250: Add support cpufreq for EXYNOS5250
  EXYNOS4X12: Add support cpufreq for EXYNOS4X12
  [CPUFREQ] CPUfreq ondemand: update sampling rate without waiting for next sampling
  [CPUFREQ] Add S3C2416/S3C2450 cpufreq driver
  [CPUFREQ] Fix exposure of ARM_EXYNOS4210_CPUFREQ
  [CPUFREQ] EXYNOS4210: update the name of EXYNOS clock register
  [CPUFREQ] EXYNOS: Initialize locking_frequency with initial frequency
  [CPUFREQ] s3c64xx: Fix mis-cherry pick of VDDINT

Fix up trivial conflicts in Kconfig and Makefile due to just changes
next to each other (OMAP2PLUS changes vs some new EXYNOS cpufreq
drivers).
parents 4416b0ea a7b422cd
......@@ -32,3 +32,5 @@ struct exynos_dvfs_info {
};
extern int exynos4210_cpufreq_init(struct exynos_dvfs_info *);
extern int exynos4x12_cpufreq_init(struct exynos_dvfs_info *);
extern int exynos5250_cpufreq_init(struct exynos_dvfs_info *);
......@@ -7,6 +7,28 @@ config ARM_OMAP2PLUS_CPUFREQ
default ARCH_OMAP2PLUS
select CPU_FREQ_TABLE
config ARM_S3C2416_CPUFREQ
bool "S3C2416 CPU Frequency scaling support"
depends on CPU_S3C2416
help
This adds the CPUFreq driver for the Samsung S3C2416 and
S3C2450 SoC. The S3C2416 supports changing the rate of the
armdiv clock source and also entering a so called dynamic
voltage scaling mode in which it is possible to reduce the
core voltage of the cpu.
If in doubt, say N.
config ARM_S3C2416_CPUFREQ_VCORESCALE
bool "Allow voltage scaling for S3C2416 arm core (EXPERIMENTAL)"
depends on ARM_S3C2416_CPUFREQ && REGULATOR && EXPERIMENTAL
help
Enable CPU voltage scaling when entering the dvs mode.
It uses information gathered through existing hardware and
tests but not documented in any datasheet.
If in doubt, say N.
config ARM_S3C64XX_CPUFREQ
bool "Samsung S3C64XX"
depends on CPU_S3C6410
......@@ -30,6 +52,8 @@ config ARM_EXYNOS_CPUFREQ
bool "SAMSUNG EXYNOS SoCs"
depends on ARCH_EXYNOS
select ARM_EXYNOS4210_CPUFREQ if CPU_EXYNOS4210
select ARM_EXYNOS4X12_CPUFREQ if (SOC_EXYNOS4212 || SOC_EXYNOS4412)
select ARM_EXYNOS5250_CPUFREQ if SOC_EXYNOS5250
default y
help
This adds the CPUFreq driver common part for Samsung
......@@ -39,6 +63,19 @@ config ARM_EXYNOS_CPUFREQ
config ARM_EXYNOS4210_CPUFREQ
bool "Samsung EXYNOS4210"
depends on ARCH_EXYNOS
help
This adds the CPUFreq driver for Samsung EXYNOS4210
SoC (S5PV310 or S5PC210).
config ARM_EXYNOS4X12_CPUFREQ
bool "Samsung EXYNOS4X12"
help
This adds the CPUFreq driver for Samsung EXYNOS4X12
SoC (EXYNOS4212 or EXYNOS4412).
config ARM_EXYNOS5250_CPUFREQ
bool "Samsung EXYNOS5250"
help
This adds the CPUFreq driver for Samsung EXYNOS5250
SoC.
......@@ -40,10 +40,13 @@ obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o
##################################################################################
# ARM SoC drivers
obj-$(CONFIG_UX500_SOC_DB8500) += db8500-cpufreq.o
obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o
obj-$(CONFIG_ARM_S3C64XX_CPUFREQ) += s3c64xx-cpufreq.o
obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o
obj-$(CONFIG_ARM_EXYNOS_CPUFREQ) += exynos-cpufreq.o
obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o
obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ) += exynos4x12-cpufreq.o
obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ) += exynos5250-cpufreq.o
obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o
##################################################################################
......
......@@ -126,6 +126,15 @@ static int __init init_cpufreq_transition_notifier_list(void)
}
pure_initcall(init_cpufreq_transition_notifier_list);
static int off __read_mostly;
int cpufreq_disabled(void)
{
return off;
}
void disable_cpufreq(void)
{
off = 1;
}
static LIST_HEAD(cpufreq_governor_list);
static DEFINE_MUTEX(cpufreq_governor_mutex);
......@@ -1441,6 +1450,9 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
{
int retval = -EINVAL;
if (cpufreq_disabled())
return -ENODEV;
pr_debug("target for CPU %u: %u kHz, relation %u\n", policy->cpu,
target_freq, relation);
if (cpu_online(policy->cpu) && cpufreq_driver->target)
......@@ -1549,6 +1561,9 @@ int cpufreq_register_governor(struct cpufreq_governor *governor)
if (!governor)
return -EINVAL;
if (cpufreq_disabled())
return -ENODEV;
mutex_lock(&cpufreq_governor_mutex);
err = -EBUSY;
......@@ -1572,6 +1587,9 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor)
if (!governor)
return;
if (cpufreq_disabled())
return;
#ifdef CONFIG_HOTPLUG_CPU
for_each_present_cpu(cpu) {
if (cpu_online(cpu))
......@@ -1814,6 +1832,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
unsigned long flags;
int ret;
if (cpufreq_disabled())
return -ENODEV;
if (!driver_data || !driver_data->verify || !driver_data->init ||
((!driver_data->setpolicy) && (!driver_data->target)))
return -EINVAL;
......@@ -1901,6 +1922,9 @@ static int __init cpufreq_core_init(void)
{
int cpu;
if (cpufreq_disabled())
return -ENODEV;
for_each_possible_cpu(cpu) {
per_cpu(cpufreq_policy_cpu, cpu) = -1;
init_rwsem(&per_cpu(cpu_policy_rwsem, cpu));
......
......@@ -257,6 +257,62 @@ show_one(sampling_down_factor, sampling_down_factor);
show_one(ignore_nice_load, ignore_nice);
show_one(powersave_bias, powersave_bias);
/**
* update_sampling_rate - update sampling rate effective immediately if needed.
* @new_rate: new sampling rate
*
* If new rate is smaller than the old, simply updaing
* dbs_tuners_int.sampling_rate might not be appropriate. For example,
* if the original sampling_rate was 1 second and the requested new sampling
* rate is 10 ms because the user needs immediate reaction from ondemand
* governor, but not sure if higher frequency will be required or not,
* then, the governor may change the sampling rate too late; up to 1 second
* later. Thus, if we are reducing the sampling rate, we need to make the
* new value effective immediately.
*/
static void update_sampling_rate(unsigned int new_rate)
{
int cpu;
dbs_tuners_ins.sampling_rate = new_rate
= max(new_rate, min_sampling_rate);
for_each_online_cpu(cpu) {
struct cpufreq_policy *policy;
struct cpu_dbs_info_s *dbs_info;
unsigned long next_sampling, appointed_at;
policy = cpufreq_cpu_get(cpu);
if (!policy)
continue;
dbs_info = &per_cpu(od_cpu_dbs_info, policy->cpu);
cpufreq_cpu_put(policy);
mutex_lock(&dbs_info->timer_mutex);
if (!delayed_work_pending(&dbs_info->work)) {
mutex_unlock(&dbs_info->timer_mutex);
continue;
}
next_sampling = jiffies + usecs_to_jiffies(new_rate);
appointed_at = dbs_info->work.timer.expires;
if (time_before(next_sampling, appointed_at)) {
mutex_unlock(&dbs_info->timer_mutex);
cancel_delayed_work_sync(&dbs_info->work);
mutex_lock(&dbs_info->timer_mutex);
schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work,
usecs_to_jiffies(new_rate));
}
mutex_unlock(&dbs_info->timer_mutex);
}
}
static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
const char *buf, size_t count)
{
......@@ -265,7 +321,7 @@ static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
ret = sscanf(buf, "%u", &input);
if (ret != 1)
return -EINVAL;
dbs_tuners_ins.sampling_rate = max(input, min_sampling_rate);
update_sampling_rate(input);
return count;
}
......
......@@ -210,6 +210,8 @@ static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
cpufreq_frequency_table_get_attr(exynos_info->freq_table, policy->cpu);
locking_frequency = exynos_getspeed(0);
/* set the transition latency value */
policy->cpuinfo.transition_latency = 100000;
......@@ -252,6 +254,10 @@ static int __init exynos_cpufreq_init(void)
if (soc_is_exynos4210())
ret = exynos4210_cpufreq_init(exynos_info);
else if (soc_is_exynos4212() || soc_is_exynos4412())
ret = exynos4x12_cpufreq_init(exynos_info);
else if (soc_is_exynos5250())
ret = exynos5250_cpufreq_init(exynos_info);
else
pr_err("%s: CPU type not found\n", __func__);
......
......@@ -121,25 +121,25 @@ static void exynos4210_set_clkdiv(unsigned int div_index)
tmp = exynos4210_clkdiv_table[div_index].clkdiv;
__raw_writel(tmp, S5P_CLKDIV_CPU);
__raw_writel(tmp, EXYNOS4_CLKDIV_CPU);
do {
tmp = __raw_readl(S5P_CLKDIV_STATCPU);
tmp = __raw_readl(EXYNOS4_CLKDIV_STATCPU);
} while (tmp & 0x1111111);
/* Change Divider - CPU1 */
tmp = __raw_readl(S5P_CLKDIV_CPU1);
tmp = __raw_readl(EXYNOS4_CLKDIV_CPU1);
tmp &= ~((0x7 << 4) | 0x7);
tmp |= ((clkdiv_cpu1[div_index][0] << 4) |
(clkdiv_cpu1[div_index][1] << 0));
__raw_writel(tmp, S5P_CLKDIV_CPU1);
__raw_writel(tmp, EXYNOS4_CLKDIV_CPU1);
do {
tmp = __raw_readl(S5P_CLKDIV_STATCPU1);
tmp = __raw_readl(EXYNOS4_CLKDIV_STATCPU1);
} while (tmp & 0x11);
}
......@@ -151,32 +151,32 @@ static void exynos4210_set_apll(unsigned int index)
clk_set_parent(moutcore, mout_mpll);
do {
tmp = (__raw_readl(S5P_CLKMUX_STATCPU)
>> S5P_CLKSRC_CPU_MUXCORE_SHIFT);
tmp = (__raw_readl(EXYNOS4_CLKMUX_STATCPU)
>> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT);
tmp &= 0x7;
} while (tmp != 0x2);
/* 2. Set APLL Lock time */
__raw_writel(S5P_APLL_LOCKTIME, S5P_APLL_LOCK);
__raw_writel(EXYNOS4_APLL_LOCKTIME, EXYNOS4_APLL_LOCK);
/* 3. Change PLL PMS values */
tmp = __raw_readl(S5P_APLL_CON0);
tmp = __raw_readl(EXYNOS4_APLL_CON0);
tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
tmp |= exynos4210_apll_pms_table[index];
__raw_writel(tmp, S5P_APLL_CON0);
__raw_writel(tmp, EXYNOS4_APLL_CON0);
/* 4. wait_lock_time */
do {
tmp = __raw_readl(S5P_APLL_CON0);
} while (!(tmp & (0x1 << S5P_APLLCON0_LOCKED_SHIFT)));
tmp = __raw_readl(EXYNOS4_APLL_CON0);
} while (!(tmp & (0x1 << EXYNOS4_APLLCON0_LOCKED_SHIFT)));
/* 5. MUX_CORE_SEL = APLL */
clk_set_parent(moutcore, mout_apll);
do {
tmp = __raw_readl(S5P_CLKMUX_STATCPU);
tmp &= S5P_CLKMUX_STATCPU_MUXCORE_MASK;
} while (tmp != (0x1 << S5P_CLKSRC_CPU_MUXCORE_SHIFT));
tmp = __raw_readl(EXYNOS4_CLKMUX_STATCPU);
tmp &= EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK;
} while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
}
bool exynos4210_pms_change(unsigned int old_index, unsigned int new_index)
......@@ -198,10 +198,10 @@ static void exynos4210_set_frequency(unsigned int old_index,
exynos4210_set_clkdiv(new_index);
/* 2. Change just s value in apll m,p,s value */
tmp = __raw_readl(S5P_APLL_CON0);
tmp = __raw_readl(EXYNOS4_APLL_CON0);
tmp &= ~(0x7 << 0);
tmp |= (exynos4210_apll_pms_table[new_index] & 0x7);
__raw_writel(tmp, S5P_APLL_CON0);
__raw_writel(tmp, EXYNOS4_APLL_CON0);
} else {
/* Clock Configuration Procedure */
/* 1. Change the system clock divider values */
......@@ -212,10 +212,10 @@ static void exynos4210_set_frequency(unsigned int old_index,
} else if (old_index < new_index) {
if (!exynos4210_pms_change(old_index, new_index)) {
/* 1. Change just s value in apll m,p,s value */
tmp = __raw_readl(S5P_APLL_CON0);
tmp = __raw_readl(EXYNOS4_APLL_CON0);
tmp &= ~(0x7 << 0);
tmp |= (exynos4210_apll_pms_table[new_index] & 0x7);
__raw_writel(tmp, S5P_APLL_CON0);
__raw_writel(tmp, EXYNOS4_APLL_CON0);
/* 2. Change the system clock divider values */
exynos4210_set_clkdiv(new_index);
......@@ -253,24 +253,24 @@ int exynos4210_cpufreq_init(struct exynos_dvfs_info *info)
if (IS_ERR(mout_apll))
goto err_mout_apll;
tmp = __raw_readl(S5P_CLKDIV_CPU);
tmp = __raw_readl(EXYNOS4_CLKDIV_CPU);
for (i = L0; i < CPUFREQ_LEVEL_END; i++) {
tmp &= ~(S5P_CLKDIV_CPU0_CORE_MASK |
S5P_CLKDIV_CPU0_COREM0_MASK |
S5P_CLKDIV_CPU0_COREM1_MASK |
S5P_CLKDIV_CPU0_PERIPH_MASK |
S5P_CLKDIV_CPU0_ATB_MASK |
S5P_CLKDIV_CPU0_PCLKDBG_MASK |
S5P_CLKDIV_CPU0_APLL_MASK);
tmp |= ((clkdiv_cpu0[i][0] << S5P_CLKDIV_CPU0_CORE_SHIFT) |
(clkdiv_cpu0[i][1] << S5P_CLKDIV_CPU0_COREM0_SHIFT) |
(clkdiv_cpu0[i][2] << S5P_CLKDIV_CPU0_COREM1_SHIFT) |
(clkdiv_cpu0[i][3] << S5P_CLKDIV_CPU0_PERIPH_SHIFT) |
(clkdiv_cpu0[i][4] << S5P_CLKDIV_CPU0_ATB_SHIFT) |
(clkdiv_cpu0[i][5] << S5P_CLKDIV_CPU0_PCLKDBG_SHIFT) |
(clkdiv_cpu0[i][6] << S5P_CLKDIV_CPU0_APLL_SHIFT));
tmp &= ~(EXYNOS4_CLKDIV_CPU0_CORE_MASK |
EXYNOS4_CLKDIV_CPU0_COREM0_MASK |
EXYNOS4_CLKDIV_CPU0_COREM1_MASK |
EXYNOS4_CLKDIV_CPU0_PERIPH_MASK |
EXYNOS4_CLKDIV_CPU0_ATB_MASK |
EXYNOS4_CLKDIV_CPU0_PCLKDBG_MASK |
EXYNOS4_CLKDIV_CPU0_APLL_MASK);
tmp |= ((clkdiv_cpu0[i][0] << EXYNOS4_CLKDIV_CPU0_CORE_SHIFT) |
(clkdiv_cpu0[i][1] << EXYNOS4_CLKDIV_CPU0_COREM0_SHIFT) |
(clkdiv_cpu0[i][2] << EXYNOS4_CLKDIV_CPU0_COREM1_SHIFT) |
(clkdiv_cpu0[i][3] << EXYNOS4_CLKDIV_CPU0_PERIPH_SHIFT) |
(clkdiv_cpu0[i][4] << EXYNOS4_CLKDIV_CPU0_ATB_SHIFT) |
(clkdiv_cpu0[i][5] << EXYNOS4_CLKDIV_CPU0_PCLKDBG_SHIFT) |
(clkdiv_cpu0[i][6] << EXYNOS4_CLKDIV_CPU0_APLL_SHIFT));
exynos4210_clkdiv_table[i].clkdiv = tmp;
}
......
This diff is collapsed.
/*
* Copyright (c) 2010-20122Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* EXYNOS5250 - CPU frequency scaling support
*
* 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/module.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/cpufreq.h>
#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/cpufreq.h>
#define CPUFREQ_LEVEL_END (L15 + 1)
static int max_support_idx;
static int min_support_idx = (CPUFREQ_LEVEL_END - 1);
static struct clk *cpu_clk;
static struct clk *moutcore;
static struct clk *mout_mpll;
static struct clk *mout_apll;
struct cpufreq_clkdiv {
unsigned int index;
unsigned int clkdiv;
unsigned int clkdiv1;
};
static unsigned int exynos5250_volt_table[CPUFREQ_LEVEL_END];
static struct cpufreq_frequency_table exynos5250_freq_table[] = {
{L0, 1700 * 1000},
{L1, 1600 * 1000},
{L2, 1500 * 1000},
{L3, 1400 * 1000},
{L4, 1300 * 1000},
{L5, 1200 * 1000},
{L6, 1100 * 1000},
{L7, 1000 * 1000},
{L8, 900 * 1000},
{L9, 800 * 1000},
{L10, 700 * 1000},
{L11, 600 * 1000},
{L12, 500 * 1000},
{L13, 400 * 1000},
{L14, 300 * 1000},
{L15, 200 * 1000},
{0, CPUFREQ_TABLE_END},
};
static struct cpufreq_clkdiv exynos5250_clkdiv_table[CPUFREQ_LEVEL_END];
static unsigned int clkdiv_cpu0_5250[CPUFREQ_LEVEL_END][8] = {
/*
* Clock divider value for following
* { ARM, CPUD, ACP, PERIPH, ATB, PCLK_DBG, APLL, ARM2 }
*/
{ 0, 3, 7, 7, 6, 1, 3, 0 }, /* 1700 MHz - N/A */
{ 0, 3, 7, 7, 6, 1, 3, 0 }, /* 1600 MHz - N/A */
{ 0, 3, 7, 7, 5, 1, 3, 0 }, /* 1500 MHz - N/A */
{ 0, 3, 7, 7, 6, 1, 3, 0 }, /* 1400 MHz */
{ 0, 3, 7, 7, 6, 1, 3, 0 }, /* 1300 MHz */
{ 0, 3, 7, 7, 5, 1, 3, 0 }, /* 1200 MHz */
{ 0, 2, 7, 7, 5, 1, 2, 0 }, /* 1100 MHz */
{ 0, 2, 7, 7, 4, 1, 2, 0 }, /* 1000 MHz */
{ 0, 2, 7, 7, 4, 1, 2, 0 }, /* 900 MHz */
{ 0, 2, 7, 7, 3, 1, 1, 0 }, /* 800 MHz */
{ 0, 1, 7, 7, 3, 1, 1, 0 }, /* 700 MHz */
{ 0, 1, 7, 7, 2, 1, 1, 0 }, /* 600 MHz */
{ 0, 1, 7, 7, 2, 1, 1, 0 }, /* 500 MHz */
{ 0, 1, 7, 7, 1, 1, 1, 0 }, /* 400 MHz */
{ 0, 1, 7, 7, 1, 1, 1, 0 }, /* 300 MHz */
{ 0, 1, 7, 7, 1, 1, 1, 0 }, /* 200 MHz */
};
static unsigned int clkdiv_cpu1_5250[CPUFREQ_LEVEL_END][2] = {
/* Clock divider value for following
* { COPY, HPM }
*/
{ 0, 2 }, /* 1700 MHz - N/A */
{ 0, 2 }, /* 1600 MHz - N/A */
{ 0, 2 }, /* 1500 MHz - N/A */
{ 0, 2 }, /* 1400 MHz */
{ 0, 2 }, /* 1300 MHz */
{ 0, 2 }, /* 1200 MHz */
{ 0, 2 }, /* 1100 MHz */
{ 0, 2 }, /* 1000 MHz */
{ 0, 2 }, /* 900 MHz */
{ 0, 2 }, /* 800 MHz */
{ 0, 2 }, /* 700 MHz */
{ 0, 2 }, /* 600 MHz */
{ 0, 2 }, /* 500 MHz */
{ 0, 2 }, /* 400 MHz */
{ 0, 2 }, /* 300 MHz */
{ 0, 2 }, /* 200 MHz */
};
static unsigned int exynos5_apll_pms_table[CPUFREQ_LEVEL_END] = {
(0), /* 1700 MHz - N/A */
(0), /* 1600 MHz - N/A */
(0), /* 1500 MHz - N/A */
(0), /* 1400 MHz */
((325 << 16) | (6 << 8) | 0), /* 1300 MHz */
((200 << 16) | (4 << 8) | 0), /* 1200 MHz */
((275 << 16) | (6 << 8) | 0), /* 1100 MHz */
((125 << 16) | (3 << 8) | 0), /* 1000 MHz */
((150 << 16) | (4 << 8) | 0), /* 900 MHz */
((100 << 16) | (3 << 8) | 0), /* 800 MHz */
((175 << 16) | (3 << 8) | 1), /* 700 MHz */
((200 << 16) | (4 << 8) | 1), /* 600 MHz */
((125 << 16) | (3 << 8) | 1), /* 500 MHz */
((100 << 16) | (3 << 8) | 1), /* 400 MHz */
((200 << 16) | (4 << 8) | 2), /* 300 MHz */
((100 << 16) | (3 << 8) | 2), /* 200 MHz */
};
/* ASV group voltage table */
static const unsigned int asv_voltage_5250[CPUFREQ_LEVEL_END] = {
0, 0, 0, 0, 0, 0, 0, /* 1700 MHz ~ 1100 MHz Not supported */
1175000, 1125000, 1075000, 1050000, 1000000,
950000, 925000, 925000, 900000
};
static void set_clkdiv(unsigned int div_index)
{
unsigned int tmp;
/* Change Divider - CPU0 */
tmp = exynos5250_clkdiv_table[div_index].clkdiv;
__raw_writel(tmp, EXYNOS5_CLKDIV_CPU0);
while (__raw_readl(EXYNOS5_CLKDIV_STATCPU0) & 0x11111111)
cpu_relax();
/* Change Divider - CPU1 */
tmp = exynos5250_clkdiv_table[div_index].clkdiv1;
__raw_writel(tmp, EXYNOS5_CLKDIV_CPU1);
while (__raw_readl(EXYNOS5_CLKDIV_STATCPU1) & 0x11)
cpu_relax();
}
static void set_apll(unsigned int new_index,
unsigned int old_index)
{
unsigned int tmp, pdiv;
/* 1. MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
clk_set_parent(moutcore, mout_mpll);
do {
cpu_relax();
tmp = (__raw_readl(EXYNOS5_CLKMUX_STATCPU) >> 16);
tmp &= 0x7;
} while (tmp != 0x2);
/* 2. Set APLL Lock time */
pdiv = ((exynos5_apll_pms_table[new_index] >> 8) & 0x3f);
__raw_writel((pdiv * 250), EXYNOS5_APLL_LOCK);
/* 3. Change PLL PMS values */
tmp = __raw_readl(EXYNOS5_APLL_CON0);
tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
tmp |= exynos5_apll_pms_table[new_index];
__raw_writel(tmp, EXYNOS5_APLL_CON0);
/* 4. wait_lock_time */
do {
cpu_relax();
tmp = __raw_readl(EXYNOS5_APLL_CON0);
} while (!(tmp & (0x1 << 29)));
/* 5. MUX_CORE_SEL = APLL */
clk_set_parent(moutcore, mout_apll);
do {
cpu_relax();
tmp = __raw_readl(EXYNOS5_CLKMUX_STATCPU);
tmp &= (0x7 << 16);
} while (tmp != (0x1 << 16));
}
bool exynos5250_pms_change(unsigned int old_index, unsigned int new_index)
{
unsigned int old_pm = (exynos5_apll_pms_table[old_index] >> 8);
unsigned int new_pm = (exynos5_apll_pms_table[new_index] >> 8);
return (old_pm == new_pm) ? 0 : 1;
}
static void exynos5250_set_frequency(unsigned int old_index,
unsigned int new_index)
{
unsigned int tmp;
if (old_index > new_index) {
if (!exynos5250_pms_change(old_index, new_index)) {
/* 1. Change the system clock divider values */
set_clkdiv(new_index);
/* 2. Change just s value in apll m,p,s value */
tmp = __raw_readl(EXYNOS5_APLL_CON0);
tmp &= ~(0x7 << 0);
tmp |= (exynos5_apll_pms_table[new_index] & 0x7);
__raw_writel(tmp, EXYNOS5_APLL_CON0);
} else {
/* Clock Configuration Procedure */
/* 1. Change the system clock divider values */
set_clkdiv(new_index);
/* 2. Change the apll m,p,s value */
set_apll(new_index, old_index);
}
} else if (old_index < new_index) {
if (!exynos5250_pms_change(old_index, new_index)) {
/* 1. Change just s value in apll m,p,s value */
tmp = __raw_readl(EXYNOS5_APLL_CON0);
tmp &= ~(0x7 << 0);
tmp |= (exynos5_apll_pms_table[new_index] & 0x7);
__raw_writel(tmp, EXYNOS5_APLL_CON0);
/* 2. Change the system clock divider values */
set_clkdiv(new_index);
} else {
/* Clock Configuration Procedure */
/* 1. Change the apll m,p,s value */
set_apll(new_index, old_index);
/* 2. Change the system clock divider values */
set_clkdiv(new_index);
}
}
}
static void __init set_volt_table(void)
{
unsigned int i;
exynos5250_freq_table[L0].frequency = CPUFREQ_ENTRY_INVALID;
exynos5250_freq_table[L1].frequency = CPUFREQ_ENTRY_INVALID;
exynos5250_freq_table[L2].frequency = CPUFREQ_ENTRY_INVALID;
exynos5250_freq_table[L3].frequency = CPUFREQ_ENTRY_INVALID;
exynos5250_freq_table[L4].frequency = CPUFREQ_ENTRY_INVALID;
exynos5250_freq_table[L5].frequency = CPUFREQ_ENTRY_INVALID;
exynos5250_freq_table[L6].frequency = CPUFREQ_ENTRY_INVALID;
max_support_idx = L7;
for (i = 0 ; i < CPUFREQ_LEVEL_END ; i++)
exynos5250_volt_table[i] = asv_voltage_5250[i];
}
int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
{
int i;
unsigned int tmp;
unsigned long rate;
set_volt_table();
cpu_clk = clk_get(NULL, "armclk");
if (IS_ERR(cpu_clk))
return PTR_ERR(cpu_clk);
moutcore = clk_get(NULL, "mout_cpu");
if (IS_ERR(moutcore))
goto err_moutcore;
mout_mpll = clk_get(NULL, "mout_mpll");
if (IS_ERR(mout_mpll))
goto err_mout_mpll;
rate = clk_get_rate(mout_mpll) / 1000;
mout_apll = clk_get(NULL, "mout_apll");
if (IS_ERR(mout_apll))
goto err_mout_apll;
for (i = L0; i < CPUFREQ_LEVEL_END; i++) {
exynos5250_clkdiv_table[i].index = i;
tmp = __raw_readl(EXYNOS5_CLKDIV_CPU0);
tmp &= ~((0x7 << 0) | (0x7 << 4) | (0x7 << 8) |
(0x7 << 12) | (0x7 << 16) | (0x7 << 20) |
(0x7 << 24) | (0x7 << 28));
tmp |= ((clkdiv_cpu0_5250[i][0] << 0) |
(clkdiv_cpu0_5250[i][1] << 4) |
(clkdiv_cpu0_5250[i][2] << 8) |
(clkdiv_cpu0_5250[i][3] << 12) |
(clkdiv_cpu0_5250[i][4] << 16) |
(clkdiv_cpu0_5250[i][5] << 20) |
(clkdiv_cpu0_5250[i][6] << 24) |
(clkdiv_cpu0_5250[i][7] << 28));
exynos5250_clkdiv_table[i].clkdiv = tmp;
tmp = __raw_readl(EXYNOS5_CLKDIV_CPU1);
tmp &= ~((0x7 << 0) | (0x7 << 4));
tmp |= ((clkdiv_cpu1_5250[i][0] << 0) |
(clkdiv_cpu1_5250[i][1] << 4));
exynos5250_clkdiv_table[i].clkdiv1 = tmp;
}
info->mpll_freq_khz = rate;
/* 1000Mhz */
info->pm_lock_idx = L7;
/* 800Mhz */
info->pll_safe_idx = L9;
info->max_support_idx = max_support_idx;
info->min_support_idx = min_support_idx;
info->cpu_clk = cpu_clk;
info->volt_table = exynos5250_volt_table;
info->freq_table = exynos5250_freq_table;
info->set_freq = exynos5250_set_frequency;
info->need_apll_change = exynos5250_pms_change;
return 0;
err_mout_apll:
clk_put(mout_mpll);
err_mout_mpll:
clk_put(moutcore);
err_moutcore:
clk_put(cpu_clk);
pr_err("%s: failed initialization\n", __func__);
return -EINVAL;
}
EXPORT_SYMBOL(exynos5250_cpufreq_init);
This diff is collapsed.
......@@ -217,13 +217,6 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
} else {
s3c64xx_cpufreq_config_regulator();
}
vddint = regulator_get(NULL, "vddint");
if (IS_ERR(vddint)) {
ret = PTR_ERR(vddint);
pr_err("Failed to obtain VDDINT: %d\n", ret);
vddint = NULL;
}
#endif
freq = s3c64xx_freq_table;
......
......@@ -35,6 +35,7 @@
#ifdef CONFIG_CPU_FREQ
int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);
int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);
extern void disable_cpufreq(void);
#else /* CONFIG_CPU_FREQ */
static inline int cpufreq_register_notifier(struct notifier_block *nb,
unsigned int list)
......@@ -46,6 +47,7 @@ static inline int cpufreq_unregister_notifier(struct notifier_block *nb,
{
return 0;
}
static inline void disable_cpufreq(void) { }
#endif /* CONFIG_CPU_FREQ */
/* if (cpufreq_driver->target) exists, the ->governor decides what frequency
......
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