PD#99098(98799):Fix sys pll mode for m8baby project

commit cb0f984b6a81a5ebffa13b812b6b41148f8d54db
Author: tao.zeng <tao.zeng@amlogic.com>
Date:   Wed Oct 29 14:56:01 2014 +0800

    PD #98799: Enable Fix sys pll mode for ALL m8baby project

    Change-Id: I55058f0e54d8d49afe6463c5a649afab67c5efb8

commit de9c47904f3d717d1b8034ea06bc3784141e9482
Author: tao.zeng <tao.zeng@amlogic.com>
Date:   Tue Oct 28 10:49:42 2014 +0800

    PD #98799: Import fix syspll mode for cpu frequent scaling

    If we FIX syspll to a certain frequent and only change OD or external
    divider to get different frequent, this mechanism is more stable when
    chip temperature is over than 80 Celsius.

    Note: this feature can only be opened based on M8bay right now

Change-Id: Ieebe2e645ffc594f5229ade97c2b3420b29b7ffb
This commit is contained in:
alex.cao
2014-08-27 02:21:17 +00:00
committed by Mauro Ribeiro
parent 537312b443
commit 5df72f4e83
6 changed files with 133 additions and 13 deletions

View File

@@ -334,7 +334,7 @@
vcck_dvfs {
dvfs_id = <1>; /** must be value of (1 << n) */
table_count = <12>; /** must be correct count for dvfs_table */
table_count = <13>; /** must be correct count for dvfs_table */
change-frequent-only;
dvfs_table = <
/* NOTE: frequent in this table must be ascending order */
@@ -349,8 +349,9 @@
816000 850000 850000
1008000 875000 875000
1200000 925000 925000
1320000 1000000 1000000
1488000 1075000 1075000
1320000 1100000 1100000
1488000 1100000 1100000
1536000 1140000 1140000
>;
};
};
@@ -596,6 +597,7 @@
cpufreq-meson{
compatible = "amlogic,cpufreq-meson";
syspll_fixed;
status = "okay";
};

View File

@@ -494,6 +494,7 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set
# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
CONFIG_AMLOGIC_MESON_CPUFREQ=y
CONFIG_FIX_SYSPLL=y
# CONFIG_CPU_IDLE is not set
# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set

67
arch/arm/mach-meson8b/clock.c Normal file → Executable file
View File

@@ -55,12 +55,13 @@ extern struct arm_delay_ops arm_delay_ops;
static DEFINE_SPINLOCK(clockfw_lock);
static DEFINE_MUTEX(clock_ops_lock);
static int measure_cpu_clock = 0;
/**************** SYS PLL**************************/
#define SYS_PLL_TABLE_MIN 24000000
#define SYS_PLL_TABLE_MAX 2112000000
#define CPU_FREQ_LIMIT 1488000000
#define CPU_FREQ_LIMIT 1536000000
struct sys_pll_s {
unsigned int freq;
@@ -339,10 +340,11 @@ long clk_round_rate_sys(struct clk *clk, unsigned long rate)
dst = setup_a9_clk_min;
else if(dst > setup_a9_clk_max)
dst = setup_a9_clk_max;
idx = ((dst - SYS_PLL_TABLE_MIN) / 1000000) / 24;
//printk("sys round rate: %d -- %d\n",rate,sys_pll_settings[idx][0]);
rate = sys_pll_settings[idx][0] * 1000000;
if ((rate != 1250000000)) {
idx = ((dst - SYS_PLL_TABLE_MIN) / 1000000) / 24;
//printk("sys round rate: %ld -- %d\n",rate,sys_pll_settings[idx][0]);
rate = sys_pll_settings[idx][0] * 1000000;
}
return rate;
}
@@ -744,8 +746,11 @@ static unsigned long clk_get_rate_a9(struct clk * clkdev)
parent_clk = clk_get_rate_xtal(NULL);
else if(pll_sel == 1)
parent_clk = clk_get_rate_sys(clkdev->parent);
else
else if (pll_sel == 2) {
clk = 1250000000; // from MPLL / 2
} else {
printk(KERN_INFO "Error : A9 parent pll selection incorrect!\n");
}
if(parent_clk > 0){
unsigned int N = (aml_read_reg32(P_HHI_SYS_CPU_CLK_CNTL1) >> 20) & 0x3FF;
unsigned int div = 1;
@@ -792,11 +797,14 @@ static int _clk_set_rate_cpu(struct clk *clk, unsigned long cpu, unsigned long g
unsigned long parent = 0;
unsigned long oldcpu = clk_get_rate_a9(clk);
unsigned int cpu_clk_cntl = aml_read_reg32(P_HHI_SYS_CPU_CLK_CNTL);
int test_n = 0;
// if ((cpu_clk_cntl & 3) == 1) {
{
unsigned long real_cpu;
parent = clk_get_rate_sys(clk->parent);
// CPU switch to xtal
aml_write_reg32(P_HHI_SYS_CPU_CLK_CNTL, cpu_clk_cntl & ~(1 << 7));
if (oldcpu <= cpu) {
// when increasing frequency, lpj has already been adjusted
@@ -805,7 +813,19 @@ static int _clk_set_rate_cpu(struct clk *clk, unsigned long cpu, unsigned long g
// when decreasing frequency, lpj has not yet been adjusted
udelay_scaled(10, oldcpu / 1000000, 24 /*clk_get_rate_xtal*/);
}
set_sys_pll(clk->parent, cpu);
aml_set_reg32_bits(P_HHI_SYS_CPU_CLK_CNTL, 1, 0, 2); // path select to syspll
if (cpu == 1250000000) {
aml_set_reg32_bits(P_HHI_MPLL_CNTL6, 1, 27, 1);
aml_set_reg32_bits(P_HHI_SYS_CPU_CLK_CNTL, 2, 0, 2); // select to mpll
aml_set_reg32_bits(P_HHI_SYS_CPU_CLK_CNTL, 0, 2, 2); // cancel external od
udelay_scaled(500, oldcpu / 1000000, 24 /*clk_get_rate_xtal*/);
printk(KERN_DEBUG"CTS_CPU_CLK %4ld --> %4ld (MHz)\n",
clk->rate / 1000000, cpu / 1000000);
clk->parent->rate = cpu;
} else {
set_sys_pll(clk->parent, cpu);
}
// Read CBUS for short delay, then CPU switch to sys pll
cpu_clk_cntl = aml_read_reg32(P_HHI_SYS_CPU_CLK_CNTL);
@@ -818,6 +838,16 @@ static int _clk_set_rate_cpu(struct clk *clk, unsigned long cpu, unsigned long g
udelay_scaled(100, oldcpu / 1000000, cpu / 1000000);
}
if (measure_cpu_clock) {
while (test_n < 5) {
real_cpu = clk_util_clk_msr(18) << 4;
if ((real_cpu < cpu && (cpu - real_cpu) > 48000000) ||
(real_cpu > cpu && (real_cpu - cpu) > 48000000)) {
pr_info("hope to set cpu clk as %ld, real value is %ld, time %d\n", cpu, real_cpu, test_n);
}
test_n++;
}
}
// CPU switch to sys pll
//cpu_clk_cntl = aml_read_reg32(P_HHI_SYS_CPU_CLK_CNTL);
//aml_set_reg32_mask(P_HHI_SYS_CPU_CLK_CNTL, (1 << 7));
@@ -1173,7 +1203,12 @@ SETPLL:
aml_set_reg32_bits(P_HHI_SYS_CPU_CLK_CNTL, 3, 2, 2);
else
aml_set_reg32_bits(P_HHI_SYS_CPU_CLK_CNTL, 0, 2, 2);
aml_write_reg32(P_HHI_SYS_PLL_CNTL, cpu_clk_cntl | (1 << 29));
//aml_write_reg32(P_HHI_SYS_PLL_CNTL, cpu_clk_cntl | (1 << 29));
if((cpu_clk_cntl & 0x3fff) != (curr_cntl & 0x3fff)) {
//dest M,N is equal to curr_cntl, So, we neednot reset the pll, just change the OD.
aml_write_reg32(P_HHI_SYS_PLL_CNTL, cpu_clk_cntl | (1 << 29));
}
if(only_once == 99){
only_once = 1;
aml_write_reg32(P_HHI_SYS_PLL_CNTL2, M8_SYS_PLL_CNTL_2);
@@ -1684,9 +1719,25 @@ static ssize_t freq_limit_show(struct class *cla, struct class_attribute *attr,
return sprintf(buf, "%d\n", freq_limit);
}
static ssize_t check_clock_store(struct class *cla, struct class_attribute *attr, const char *buf, size_t count)
{
unsigned int input;
int ret;
ret = sscanf(buf, "%u", &input);
if (ret != 1)
return -EINVAL;
measure_cpu_clock = input;
return count;
}
static ssize_t check_clock_show(struct class *cla, struct class_attribute *attr, char *buf)
{
printk("%u\n", measure_cpu_clock);
return sprintf(buf, "%d\n", measure_cpu_clock);
}
static struct class_attribute freq_limit_class_attrs[] = {
__ATTR(limit, S_IRUGO|S_IWUSR|S_IWGRP, freq_limit_show, freq_limit_store),
__ATTR(check_clock, S_IRUGO|S_IWUSR|S_IWGRP, check_clock_show, check_clock_store),
__ATTR_NULL,
};

18
arch/arm/mach-meson8b/include/mach/cpufreq_table.h Normal file → Executable file
View File

@@ -21,3 +21,21 @@ static struct cpufreq_frequency_table meson_freq_table[]=
{14 , 1488000 },
{15 , CPUFREQ_TABLE_END},
};
#ifdef CONFIG_FIX_SYSPLL
static struct cpufreq_frequency_table meson_freq_table_fix_syspll[]=
{
{0 , 96000 },
{1 , 192000 },
{2 , 384000 },
{3 , 768000 },
#if 1
{4 , 1250000 },
{5 , 1536000 },
{6 , CPUFREQ_TABLE_END},
#else
{4 , 1536000 },
{5 , CPUFREQ_TABLE_END},
#endif
};
#endif

View File

@@ -3,3 +3,9 @@ config AMLOGIC_MESON_CPUFREQ
depends on PLAT_MESON
help
This adds the CPUFreq driver for Meson series CPU
config FIX_SYSPLL
bool "Meson CPU Fix syspll mode support"
depends on ARCH_MESON8B
help
This add fix sys pll mode support for M8baby

View File

@@ -42,6 +42,9 @@ struct meson_cpufreq {
};
static struct meson_cpufreq cpufreq;
#ifdef CONFIG_FIX_SYSPLL
static int fix_syspll = 0;
#endif
static DEFINE_MUTEX(meson_cpufreq_mutex);
@@ -100,6 +103,11 @@ static int meson_cpufreq_target_locked(struct cpufreq_policy *policy,
uint cpu = policy ? policy->cpu : 0;
int ret = -EINVAL;
unsigned int freqInt = 0;
#ifdef CONFIG_FIX_SYSPLL
struct cpufreq_frequency_table *freq_table = NULL;
unsigned int freq_new, index;
#endif
if (cpu > (NR_CPUS - 1)) {
printk(KERN_ERR"cpu %d set target freq error\n",cpu);
return ret;
@@ -123,7 +131,23 @@ static int meson_cpufreq_target_locked(struct cpufreq_policy *policy,
}
}
#ifdef CONFIG_FIX_SYSPLL
/*
* CPU frequent should only select from aviliable frequent table
* if under fix syspll mode
*/
if (fix_syspll) {
freq_table = cpufreq_frequency_get_table(policy->cpu);
ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
CPUFREQ_RELATION_H, &index);
if(ret >= 0) {
freq_new = freq_table[index].frequency;
target_freq = freq_new;
} else {
printk(KERN_ERR"input frequent :%d cannot found in frequent table, ret:%d\n", target_freq, ret);
}
}
#endif
freqs.old = clk_get_rate(cpufreq.armclk) / 1000;
freqs.new = clk_round_rate(cpufreq.armclk, target_freq * 1000) / 1000;
@@ -226,9 +250,18 @@ static int meson_cpufreq_init(struct cpufreq_policy *policy)
cpufreq_frequency_table_get_attr(freq_table,
policy->cpu);
} else {
#endif
#ifdef CONFIG_FIX_SYSPLL
if (fix_syspll) { // select fix pll table if syspll_fixed is enabled in dts
cpufreq_frequency_table_get_attr(meson_freq_table_fix_syspll,
policy->cpu);
} else {
#endif
cpufreq_frequency_table_get_attr(meson_freq_table,
policy->cpu);
#ifdef CONFIG_FIX_SYSPLL
}
#endif
#if 0
}
#endif
@@ -348,7 +381,16 @@ static int __init meson_cpufreq_probe(struct platform_device *pdev)
#ifdef CONFIG_USE_OF
const void *prop;
#ifdef CONFIG_FIX_SYSPLL
int err = 0;
if (pdev->dev.of_node) {
err = of_property_read_bool(pdev->dev.of_node, "syspll_fixed");
if (err) {
printk("%s:SYSPLL request to be fixed\n", __func__);
fix_syspll = 1;
}
}
#endif
if (pdev->dev.of_node) {
prop = of_get_property(pdev->dev.of_node, "voltage_control", NULL);
if(prop)