From ac93aae8496a8e8572f4297ce4e05b13507ba6bf Mon Sep 17 00:00:00 2001
From: chenxing <chenxing@rock-chips.com>
Date: Mon, 17 Jun 2013 14:39:08 +0800
Subject: [PATCH] rk3188: use leakage or delayline auto scale voltage

---
 arch/arm/mach-rk3188/cpufreq.c           |  9 ++++
 arch/arm/mach-rk3188/dvfs.c              | 54 ++++++++++++++++++++++++
 arch/arm/mach-rk3188/include/mach/dvfs.h |  2 +
 3 files changed, 65 insertions(+)

diff --git a/arch/arm/mach-rk3188/cpufreq.c b/arch/arm/mach-rk3188/cpufreq.c
index 12a41f312e27..599fe9cae0fe 100644
--- a/arch/arm/mach-rk3188/cpufreq.c
+++ b/arch/arm/mach-rk3188/cpufreq.c
@@ -346,6 +346,7 @@ static int rk3188_cpufreq_verify(struct cpufreq_policy *policy)
 static int rk3188_cpufreq_init_cpu0(struct cpufreq_policy *policy)
 {
 	unsigned int i;
+	struct cpufreq_frequency_table *table_adjust;
 
 	gpu_is_mali400 = cpu_is_rk3188();
 	gpu_clk = clk_get(NULL, "gpu");
@@ -363,6 +364,14 @@ static int rk3188_cpufreq_init_cpu0(struct cpufreq_policy *policy)
 	if (IS_ERR(cpu_clk))
 		return PTR_ERR(cpu_clk);
 
+	if (soc_is_rk3188()) {
+		/* Adjust dvfs table avoid overheat */
+		table_adjust = dvfs_get_freq_volt_table(cpu_clk);
+		dvfs_adjust_table_lmtvolt(cpu_clk, table_adjust);
+		table_adjust = dvfs_get_freq_volt_table(gpu_clk);
+		dvfs_adjust_table_lmtvolt(gpu_clk, table_adjust);
+	}
+
 	dvfs_clk_register_set_rate_callback(cpu_clk, cpufreq_scale_rate_for_dvfs);
 	freq_table = dvfs_get_freq_volt_table(cpu_clk);
 	if (freq_table == NULL) {
diff --git a/arch/arm/mach-rk3188/dvfs.c b/arch/arm/mach-rk3188/dvfs.c
index 6f409c752497..772af60ae6f9 100755
--- a/arch/arm/mach-rk3188/dvfs.c
+++ b/arch/arm/mach-rk3188/dvfs.c
@@ -26,6 +26,7 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/hrtimer.h>
+#include <plat/efuse.h>
 
 static int rk_dvfs_clk_notifier_event(struct notifier_block *this,
 		unsigned long event, void *ptr)
@@ -77,6 +78,59 @@ static struct notifier_block rk_dvfs_clk_notifier = {
 	.notifier_call = rk_dvfs_clk_notifier_event,
 };
 
+struct lkg_maxvolt {
+	int leakage_level;
+	unsigned int maxvolt;
+};
+static struct lkg_maxvolt lkg_volt_table[] = {
+	{.leakage_level = 1,	.maxvolt = 1350 * 1000},
+	{.leakage_level = 3,	.maxvolt = 1275 * 1000},
+	{.leakage_level = 15,	.maxvolt = 1200 * 1000},
+};
+
+static int leakage_level = 0;
+#define HIGH_DELAYLINE	125
+#define LOW_DELAYLINE	110
+static u8 rk30_get_avs_val(void);
+void dvfs_adjust_table_lmtvolt(struct clk *clk, struct cpufreq_frequency_table *table)
+{
+	int i = 0;
+	unsigned int maxvolt = 0;
+
+	leakage_level = rk_leakage_val();
+	printk("DVFS MSG: %s: %s get leakage_level = %d\n", clk->name, __func__, leakage_level);
+	if (leakage_level == 0) {
+		int delayline_val = 0;
+		delayline_val = rk30_get_avs_val();
+		printk("This chip no leakage msg, use delayline instead, val = %d\n", delayline_val);
+
+		if (delayline_val >= HIGH_DELAYLINE) {
+			leakage_level = 4;	//same as leakage_level > 4
+
+		} else if (delayline_val <= LOW_DELAYLINE) {
+			leakage_level = 1;
+			printk("Delayline TOO LOW, maybe need high voltage\n");
+
+		} else
+			leakage_level = 2;	//same as leakage_level = 3
+	}
+
+	for (i = 0; i < ARRAY_SIZE(lkg_volt_table); i++) {
+		if (leakage_level <= lkg_volt_table[i].leakage_level) {
+			maxvolt = lkg_volt_table[i].maxvolt;
+			break;
+		}
+	}
+
+	for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
+		if (table[i].index > maxvolt) {
+			printk("\t\tadjust table freq=%d KHz, index=%d mV", table[i].frequency, table[i].index);
+			table[i].index = maxvolt;
+			printk(" to index=%d mV\n", table[i].index);
+		}
+	}
+}
+
 #define NO_VOLT_DIFF
 #ifdef NO_VOLT_DIFF
 
diff --git a/arch/arm/mach-rk3188/include/mach/dvfs.h b/arch/arm/mach-rk3188/include/mach/dvfs.h
index 9a9b3bdbc8e4..77d5949e6928 100644
--- a/arch/arm/mach-rk3188/include/mach/dvfs.h
+++ b/arch/arm/mach-rk3188/include/mach/dvfs.h
@@ -5,8 +5,10 @@
 
 #ifdef CONFIG_DVFS
 int rk3188_dvfs_init(void);
+void dvfs_adjust_table_lmtvolt(struct clk *clk, struct cpufreq_frequency_table *table);
 #else
 static inline int rk3188_dvfs_init(void){ return 0; }
+static inline void dvfs_adjust_table_lmtvolt(struct clk *clk, struct cpufreq_frequency_table *table){}
 #endif
 
 #endif
-- 
2.34.1