rk29: move ddr frequency scaling from cpufreq.c to ddrfreq.c
author黄涛 <huangtao@rock-chips.com>
Fri, 9 Sep 2011 09:13:55 +0000 (17:13 +0800)
committer黄涛 <huangtao@rock-chips.com>
Wed, 14 Sep 2011 02:53:13 +0000 (10:53 +0800)
arch/arm/mach-rk29/Makefile
arch/arm/mach-rk29/cpufreq.c
arch/arm/mach-rk29/ddrfreq.c [new file with mode: 0644]

index bc91143c770d13770298be0ced4ab6b06bafb2a1..ea3f7a12425d0e896ce941b08d8194a11ec3f211 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_RK29_LAST_LOG) += last_log.o
 obj-$(CONFIG_USB_GADGET) += usb_detect.o
 obj-$(CONFIG_PM) += pm.o
 obj-$(CONFIG_CPU_FREQ) += cpufreq.o
+obj-$(CONFIG_DDR_FREQ) += ddrfreq.o
 obj-$(CONFIG_RK29_VPU) += vpu_mem.o
 obj-y += spi_sram.o
 obj-$(CONFIG_RK29_VPU_SERVICE) += vpu_service.o
index 8d73cfb519a04c43ac92cb8ae6a837856bd66d38..6da7b65b4f46b190da36087f5e5d408b9b79b51e 100755 (executable)
@@ -29,7 +29,6 @@
 #include <linux/workqueue.h>
 #include <mach/clock.h>
 #include <mach/cpufreq.h>
-#include <mach/ddr.h>
 #include <../../../drivers/video/rk29_fb.h>
 
 #define MHZ    (1000*1000)
@@ -84,9 +83,8 @@ enum {
        DEBUG_CHANGE    = 1U << 0,
        DEBUG_TEMP      = 1U << 1,
        DEBUG_DISP      = 1U << 2,
-       DEBUG_DDR       = 1U << 3,
 };
-static uint debug_mask = DEBUG_CHANGE | DEBUG_DDR;
+static uint debug_mask = DEBUG_CHANGE;
 module_param(debug_mask, uint, 0644);
 #define dprintk(mask, fmt, ...) do { if (mask & debug_mask) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); } while (0)
 
@@ -125,12 +123,6 @@ static int limit_index_1008 = -1;
 static unsigned int limit_freq_1008;
 #endif
 
-#ifdef CONFIG_DDR_FREQ
-static void rk29_cpufreq_change_ddr_freq(unsigned long mhz);
-#else
-static inline void rk29_cpufreq_change_ddr_freq(unsigned long mhz) {}
-#endif
-
 static bool rk29_cpufreq_is_ondemand_policy(struct cpufreq_policy *policy)
 {
        char c = 0;
@@ -366,7 +358,6 @@ static int rk29_cpufreq_do_target(struct cpufreq_policy *policy, unsigned int ta
        cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
        dprintk(DEBUG_CHANGE, "pre change\n");
        clk_set_rate(arm_clk, freqs.new * KHZ + aclk_limit());
-       rk29_cpufreq_change_ddr_freq(0);
        dprintk(DEBUG_CHANGE, "post change\n");
        freqs.new = clk_get_rate(arm_clk) / KHZ;
        cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
@@ -485,119 +476,6 @@ static struct notifier_block rk29_cpufreq_fb_notifier = {
 };
 #endif
 
-#ifdef CONFIG_DDR_FREQ
-static struct clk *ddr_pll_clk;
-static struct clk *aclk_lcdc;
-static bool ddr_pll_can_change;
-static bool aclk_lcdc_disabled;
-static bool disable_ddr_freq;
-module_param(ddr_pll_can_change, bool, 0644);
-module_param(aclk_lcdc_disabled, bool, 0644);
-module_param(disable_ddr_freq, bool, 0644);
-static unsigned long ddr_max_mhz;
-static unsigned long ddr_min_mhz;
-module_param(ddr_max_mhz, ulong, 0644);
-module_param(ddr_min_mhz, ulong, 0644);
-#define DDR_ARM_RATE (408 * MHZ)
-
-static void rk29_cpufreq_change_ddr_freq(unsigned long mhz)
-{
-       unsigned long flags;
-       unsigned long ddr_rate, arm_rate;
-       bool changed = false;
-
-       if (disable_ddr_freq)
-               return;
-
-       if (DEBUG_DDR & debug_mask) {
-               unsigned long _mhz = mhz;
-               ddr_rate = clk_get_rate(ddr_clk);
-               if (!mhz && ddr_pll_can_change && aclk_lcdc_disabled) {
-                       arm_rate = clk_get_rate(arm_clk);
-                       if (arm_rate <= DDR_ARM_RATE && ddr_rate == ddr_max_rate)
-                               _mhz = ddr_min_mhz;
-                       else if (arm_rate > DDR_ARM_RATE && ddr_rate < ddr_max_rate)
-                               _mhz = ddr_max_mhz;
-               }
-               if (_mhz) {
-                       unsigned long hz = _mhz * MHZ;
-                       if (hz != ddr_rate)
-                               dprintk(DEBUG_DDR, "ddr %lu -> %lu Hz\n", ddr_rate, hz);
-               }
-       }
-
-       local_irq_save(flags);
-       ddr_rate = clk_get_rate(ddr_clk);
-       if (!mhz && ddr_pll_can_change && aclk_lcdc_disabled) {
-               arm_rate = clk_get_rate(arm_clk);
-               if (arm_rate <= DDR_ARM_RATE && ddr_rate == ddr_max_rate)
-                       mhz = ddr_min_mhz;
-               else if (arm_rate > DDR_ARM_RATE && ddr_rate < ddr_max_rate)
-                       mhz = ddr_max_mhz;
-       }
-       if (mhz && (mhz * MHZ) != ddr_rate) {
-               ddr_change_freq(mhz);
-               changed = true;
-       }
-       local_irq_restore(flags);
-
-       if (changed)
-               dprintk(DEBUG_DDR, "ok, got %lu Hz\n", clk_get_rate(ddr_clk));
-}
-
-static int rk29_cpufreq_ddr_pll_notifier_event(struct notifier_block *this,
-               unsigned long event, void *ptr)
-{
-       switch (event) {
-       case CLK_PRE_ENABLE:
-               ddr_pll_can_change = false;
-               break;
-       case CLK_ABORT_ENABLE:
-       case CLK_POST_DISABLE:
-               ddr_pll_can_change = true;
-               break;
-       default:
-               return NOTIFY_DONE;
-       }
-
-       if (!disable_ddr_freq) {
-               dprintk(DEBUG_DDR, "event: %lu ddr_pll_can_change: %d\n", event, ddr_pll_can_change);
-               rk29_cpufreq_change_ddr_freq(ddr_pll_can_change ? 0 : ddr_max_mhz);
-       }
-       return NOTIFY_OK;
-}
-
-static struct notifier_block rk29_cpufreq_ddr_pll_notifier = {
-       .notifier_call = rk29_cpufreq_ddr_pll_notifier_event,
-};
-
-static int rk29_cpufreq_aclk_lcdc_notifier_event(struct notifier_block *this,
-               unsigned long event, void *ptr)
-{
-       switch (event) {
-       case CLK_PRE_ENABLE:
-               aclk_lcdc_disabled = false;
-               break;
-       case CLK_ABORT_ENABLE:
-       case CLK_POST_DISABLE:
-               aclk_lcdc_disabled = true;
-               break;
-       default:
-               return NOTIFY_DONE;
-       }
-
-       if (!disable_ddr_freq) {
-               dprintk(DEBUG_DDR, "event: %lu aclk_lcdc_disabled: %d\n", event, aclk_lcdc_disabled);
-               rk29_cpufreq_change_ddr_freq(aclk_lcdc_disabled ? 0 : ddr_max_mhz);
-       }
-       return NOTIFY_OK;
-}
-
-static struct notifier_block rk29_cpufreq_aclk_lcdc_notifier = {
-       .notifier_call = rk29_cpufreq_aclk_lcdc_notifier_event,
-};
-#endif
-
 static int rk29_cpufreq_init(struct cpufreq_policy *policy)
 {
        if (policy->cpu != 0)
@@ -620,23 +498,6 @@ static int rk29_cpufreq_init(struct cpufreq_policy *policy)
        }
        ddr_max_rate = clk_get_rate(ddr_clk);
 
-#ifdef CONFIG_DDR_FREQ
-       ddr_max_mhz = ddr_max_rate / MHZ;
-       {
-               unsigned long ddr_min_rate;
-               ddr_min_rate = ddr_max_rate >> 1;
-               if (ddr_min_rate > 150 * MHZ)
-                       ddr_min_rate >>= 1;
-               ddr_min_mhz = ddr_min_rate / MHZ;
-       }
-
-       ddr_pll_clk = clk_get(NULL, "ddr_pll");
-       aclk_lcdc = clk_get(NULL, "aclk_lcdc");
-
-       clk_notifier_register(ddr_pll_clk, &rk29_cpufreq_ddr_pll_notifier);
-       clk_notifier_register(aclk_lcdc, &rk29_cpufreq_aclk_lcdc_notifier);
-#endif
-
 #ifdef CONFIG_REGULATOR
        vcore = regulator_get(NULL, "vcore");
        if (IS_ERR(vcore)) {
@@ -673,10 +534,6 @@ static int rk29_cpufreq_init(struct cpufreq_policy *policy)
 
 static int rk29_cpufreq_exit(struct cpufreq_policy *policy)
 {
-#ifdef CONFIG_DDR_FREQ
-       clk_notifier_unregister(ddr_pll_clk, &rk29_cpufreq_ddr_pll_notifier);
-       clk_notifier_unregister(aclk_lcdc, &rk29_cpufreq_aclk_lcdc_notifier);
-#endif
 #ifdef CONFIG_RK29_CPU_FREQ_LIMIT_BY_DISP
        rk29fb_unregister_notifier(&rk29_cpufreq_fb_notifier);
 #endif
diff --git a/arch/arm/mach-rk29/ddrfreq.c b/arch/arm/mach-rk29/ddrfreq.c
new file mode 100644 (file)
index 0000000..a183ba3
--- /dev/null
@@ -0,0 +1,155 @@
+/* arch/arm/mach-rk29/ddrfreq.c
+ *
+ * Copyright (C) 2011 ROCKCHIP, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <mach/clock.h>
+#include <mach/ddr.h>
+
+#define MHZ    (1000*1000)
+
+enum {
+       DEBUG_CHANGE    = 1U << 0,
+       DEBUG_EVENT     = 1U << 1,
+};
+static uint debug_mask = DEBUG_CHANGE;
+module_param(debug_mask, uint, 0644);
+#define dprintk(mask, fmt, ...) do { if (mask & debug_mask) printk(KERN_DEBUG "ddrfreq: " fmt, ##__VA_ARGS__); } while (0)
+
+static struct clk *clk_ddr;
+static struct clk *ddr_pll_clk;
+static struct clk *aclk_lcdc;
+static bool ddr_pll_can_change;
+static bool aclk_lcdc_disabled;
+static bool disable_ddr_freq;
+module_param(ddr_pll_can_change, bool, 0644);
+module_param(aclk_lcdc_disabled, bool, 0644);
+module_param(disable_ddr_freq, bool, 0644);
+
+static unsigned long ddr_max_mhz;
+static unsigned long ddr_min_mhz = 96;
+static void rk29_ddrfreq_change_freq(void);
+static int rk29_ddrfreq_set_ddr_mhz(const char *val, struct kernel_param *kp)
+{
+       int err = param_set_uint(val, kp);
+       if (!err) {
+               rk29_ddrfreq_change_freq();
+       }
+       return err;
+}
+module_param_call(ddr_max_mhz, rk29_ddrfreq_set_ddr_mhz, param_get_uint, &ddr_max_mhz, 0644);
+module_param_call(ddr_min_mhz, rk29_ddrfreq_set_ddr_mhz, param_get_uint, &ddr_min_mhz, 0644);
+
+static DEFINE_SPINLOCK(ddr_lock);
+
+static void rk29_ddrfreq_change_freq(void)
+{
+       unsigned long ddr_rate, mhz;
+
+       if (disable_ddr_freq)
+               return;
+
+       ddr_rate = clk_get_rate(clk_ddr);
+       mhz = (ddr_pll_can_change && aclk_lcdc_disabled) ? ddr_min_mhz : ddr_max_mhz;
+       if ((mhz * MHZ) != ddr_rate) {
+               dprintk(DEBUG_CHANGE, "%lu -> %lu Hz\n", ddr_rate, mhz * MHZ);
+               ddr_change_freq(mhz);
+               dprintk(DEBUG_CHANGE, "got %lu Hz\n", clk_get_rate(clk_ddr));
+       }
+}
+
+static int rk29_ddrfreq_ddr_pll_notifier_event(struct notifier_block *this,
+               unsigned long event, void *ptr)
+{
+       spin_lock_bh(&ddr_lock);
+       switch (event) {
+       case CLK_PRE_ENABLE:
+               ddr_pll_can_change = false;
+               break;
+       case CLK_ABORT_ENABLE:
+       case CLK_POST_DISABLE:
+               ddr_pll_can_change = true;
+               break;
+       default:
+               goto out;
+       }
+
+       if (!disable_ddr_freq) {
+               dprintk(DEBUG_EVENT, "event: %lu ddr_pll_can_change: %d\n", event, ddr_pll_can_change);
+               rk29_ddrfreq_change_freq();
+       }
+out:
+       spin_unlock_bh(&ddr_lock);
+       return NOTIFY_OK;
+}
+
+static struct notifier_block rk29_ddrfreq_ddr_pll_notifier = {
+       .notifier_call = rk29_ddrfreq_ddr_pll_notifier_event,
+};
+
+static int rk29_ddrfreq_aclk_lcdc_notifier_event(struct notifier_block *this,
+               unsigned long event, void *ptr)
+{
+       spin_lock_bh(&ddr_lock);
+       switch (event) {
+       case CLK_PRE_ENABLE:
+               aclk_lcdc_disabled = false;
+               break;
+       case CLK_ABORT_ENABLE:
+       case CLK_POST_DISABLE:
+               aclk_lcdc_disabled = true;
+               break;
+       default:
+               goto out;
+       }
+
+       if (!disable_ddr_freq) {
+               dprintk(DEBUG_EVENT, "event: %lu aclk_lcdc_disabled: %d\n", event, aclk_lcdc_disabled);
+               rk29_ddrfreq_change_freq();
+       }
+out:
+       spin_unlock_bh(&ddr_lock);
+       return NOTIFY_OK;
+}
+
+static struct notifier_block rk29_ddrfreq_aclk_lcdc_notifier = {
+       .notifier_call = rk29_ddrfreq_aclk_lcdc_notifier_event,
+};
+
+static int __init rk29_ddrfreq_init(void)
+{
+       clk_ddr = clk_get(NULL, "ddr");
+       if (IS_ERR(clk_ddr)) {
+               int err = PTR_ERR(clk_ddr);
+               pr_err("fail to get ddr clk: %d\n", err);
+               clk_ddr = NULL;
+               return err;
+       }
+
+       ddr_max_mhz = clk_get_rate(clk_ddr) / MHZ;
+
+       ddr_pll_clk = clk_get(NULL, "ddr_pll");
+       aclk_lcdc = clk_get(NULL, "aclk_lcdc");
+
+       clk_notifier_register(ddr_pll_clk, &rk29_ddrfreq_ddr_pll_notifier);
+       clk_notifier_register(aclk_lcdc, &rk29_ddrfreq_aclk_lcdc_notifier);
+
+       printk("ddrfreq: version 1.0\n");
+       return 0;
+}
+
+late_initcall(rk29_ddrfreq_init);