rk30xx: add dvfs table auto adjust by leakage interface
authorchenxing <chenxing@rock-chips.com>
Sat, 10 Aug 2013 01:50:19 +0000 (09:50 +0800)
committerchenxing <chenxing@rock-chips.com>
Sat, 10 Aug 2013 01:50:19 +0000 (09:50 +0800)
arch/arm/mach-rk30/dvfs.c
arch/arm/mach-rk30/include/mach/dvfs.h
arch/arm/plat-rk/efuse.c

index 0d6e5aef869da472b9bc0dc9c6b0edabe9ab13f6..0b3cbd52e01a88e0fe6ad1ec945ceccb93c44b18 100755 (executable)
@@ -26,6 +26,7 @@
 #include <linux/delay.h>\r
 #include <linux/io.h>\r
 #include <linux/hrtimer.h>\r
+#include <plat/efuse.h>\r
 \r
 static int rk_dvfs_clk_notifier_event(struct notifier_block *this,\r
                unsigned long event, void *ptr)\r
@@ -76,6 +77,86 @@ static int rk_dvfs_clk_notifier_event(struct notifier_block *this,
 static struct notifier_block rk_dvfs_clk_notifier = {\r
        .notifier_call = rk_dvfs_clk_notifier_event,\r
 };\r
+\r
+struct lkg_maxvolt {\r
+       int leakage_level;\r
+       unsigned int maxvolt;\r
+};\r
+static struct lkg_maxvolt lkg_volt_table[] = {\r
+       {.leakage_level = 3,    .maxvolt = 1350 * 1000},\r
+       {.leakage_level = 6,    .maxvolt = 1300 * 1000},\r
+       {.leakage_level = 15,   .maxvolt = 1250 * 1000},\r
+};\r
+static int leakage_level = 0;\r
+#define MHZ    (1000 * 1000)\r
+#define KHZ    (1000)\r
+// Delayline bound for nandc = 148.5MHz, Varm = Vlog = 1.00V\r
+#define HIGH_DELAYLINE 125\r
+#define LOW_DELAYLINE  125\r
+static u8 rk30_get_avs_val(void);\r
+void dvfs_adjust_table_lmtvolt(struct clk *clk, struct cpufreq_frequency_table *table)\r
+{\r
+       int i = 0;\r
+       unsigned int maxvolt = 0;\r
+       if (IS_ERR_OR_NULL(clk) || IS_ERR_OR_NULL(table)) {\r
+               DVFS_ERR("%s: clk error OR table error\n", __func__);\r
+               return ;\r
+       }\r
+\r
+       leakage_level = rk_leakage_val();\r
+       printk("DVFS MSG: %s: %s get leakage_level = %d\n", clk->name, __func__, leakage_level);\r
+       if (leakage_level == 0) {\r
+\r
+               /*\r
+                * This is for delayline auto scale voltage,\r
+                * FIXME: HIGH_DELAYLINE / LOW_DELAYLINE value maybe redefined under\r
+                * Varm = Vlog = 1.00V.\r
+                * Warning: this value is frequency/voltage sensitive, care\r
+                * about Freq nandc/Volt log.\r
+                *\r
+                */\r
+\r
+               unsigned long delayline_val = 0;\r
+               unsigned long high_delayline = 0, low_delayline = 0;\r
+               unsigned long rate_nandc = 0;\r
+\r
+               // rk3168: do nothing\r
+               return;\r
+\r
+               rate_nandc = clk_get_rate(clk_get(NULL, "nandc")) / KHZ;\r
+               printk("Get nandc rate = %lu KHz\n", rate_nandc);\r
+               high_delayline = HIGH_DELAYLINE * 148500 / rate_nandc;\r
+               low_delayline = LOW_DELAYLINE * 148500 / rate_nandc;\r
+               delayline_val = rk30_get_avs_val();\r
+               printk("This chip no leakage msg, use delayline instead, val = %lu.(HDL=%lu, LDL=%lu)\n",\r
+                               delayline_val, high_delayline, low_delayline);\r
+\r
+               if (delayline_val >= high_delayline) {\r
+                       leakage_level = 4;      //same as leakage_level > 4\r
+\r
+               } else if (delayline_val <= low_delayline) {\r
+                       leakage_level = 1;\r
+                       printk("Delayline TOO LOW, high voltage request\n");\r
+\r
+               } else\r
+                       leakage_level = 2;      //same as leakage_level = 3\r
+       }\r
+\r
+       for (i = 0; i < ARRAY_SIZE(lkg_volt_table); i++) {\r
+               if (leakage_level <= lkg_volt_table[i].leakage_level) {\r
+                       maxvolt = lkg_volt_table[i].maxvolt;\r
+                       break;\r
+               }\r
+       }\r
+\r
+       for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {\r
+               if (table[i].index > maxvolt) {\r
+                       printk("\t\tadjust table freq=%d KHz, index=%d mV", table[i].frequency, table[i].index);\r
+                       table[i].index = maxvolt;\r
+                       printk(" to index=%d mV\n", table[i].index);\r
+               }\r
+       }\r
+}\r
 #ifdef CONFIG_ARCH_RK3066B\r
 static int g_arm_high_logic = 0 * 1000;\r
 static int g_logic_high_arm = 50 * 1000;\r
index cd9f96bbb613e3a44d090f59f26b0a75bf40b7fe..b10f53e41ed7c832ed1932da851107074c9bc23c 100644 (file)
@@ -5,8 +5,10 @@
 
 #ifdef CONFIG_DVFS
 int rk_dvfs_init(void);
+void dvfs_adjust_table_lmtvolt(struct clk *clk, struct cpufreq_frequency_table *table);
 #else
 static inline int rk_dvfs_init(void){ return 0; }
+static inline void dvfs_adjust_table_lmtvolt(struct clk *clk, struct cpufreq_frequency_table *table){}
 #endif
 
 #endif
index ff46d9eb9509629be1aa05e1cdb08aeb147e014b..3a5821c3bb2db6d55afbd5ef9ac45d4021816611 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/spinlock.h>
 #include <plat/efuse.h>
 
-#if defined(CONFIG_ARCH_RK3188) || defined(CONFIG_SOC_RK3028)
+#if defined(CONFIG_ARCH_RK3188) || defined(CONFIG_SOC_RK3028) || defined(CONFIG_ARCH_RK3066B)
 #define efuse_readl(offset)            readl_relaxed(RK30_EFUSE_BASE + offset)
 #define efuse_writel(val, offset)      writel_relaxed(val, RK30_EFUSE_BASE + offset)
 #endif