#include <asm/io.h>
#include <linux/rockchip/grf.h>
#include <linux/rockchip/iomap.h>
+
+extern int rockchip_cpufreq_reboot_limit_freq(void);
+
static struct dvfs_node *clk_cpu_dvfs_node = NULL;
static int ddr_boost = 0;
-
+static int reboot_config_done = 0;
enum {
DEBUG_DDR = 1U << 0,
static void ddrfreq_mode(bool auto_self_refresh, unsigned long *target_rate, char *name)
{
+ unsigned int min_rate, max_rate;
+ int freq_limit_en;
+
ddr.mode = name;
if (auto_self_refresh != ddr.auto_self_refresh) {
ddr_set_auto_self_refresh(auto_self_refresh);
dprintk(DEBUG_DDR, "change auto self refresh to %d when %s\n", auto_self_refresh, name);
}
if (*target_rate != dvfs_clk_get_rate(ddr.clk_dvfs_node)) {
+ freq_limit_en = dvfs_clk_get_limit(clk_cpu_dvfs_node, &min_rate, &max_rate);
dvfs_clk_enable_limit(clk_cpu_dvfs_node, 600000000, -1);
if (dvfs_clk_set_rate(ddr.clk_dvfs_node, *target_rate) == 0) {
*target_rate = dvfs_clk_get_rate(ddr.clk_dvfs_node);
dprintk(DEBUG_DDR, "change freq to %lu MHz when %s\n", *target_rate / MHZ, name);
}
- dvfs_clk_enable_limit(clk_cpu_dvfs_node, 0, -1);
+
+ if (freq_limit_en) {
+ dvfs_clk_enable_limit(clk_cpu_dvfs_node, min_rate, max_rate);
+ } else {
+ dvfs_clk_disable_limit(clk_cpu_dvfs_node);
+ }
}
}
if (ddr.reboot_rate && (s & SYS_STATUS_REBOOT)) {
ddrfreq_mode(false, &ddr.reboot_rate, "shutdown/reboot");
+ rockchip_cpufreq_reboot_limit_freq();
+ reboot_config_done = 1;
} else if (ddr.suspend_rate && (s & SYS_STATUS_SUSPEND)) {
ddrfreq_mode(true, &ddr.suspend_rate, "suspend");
} else if (ddr.dualview_rate &&
unsigned long status = ddr.sys_status;
ddrfreq_work(status);
wait_event_freezable(ddr.wait, (status != ddr.sys_status) || kthread_should_stop());
- } while (!kthread_should_stop());
+ } while (!kthread_should_stop() && !reboot_config_done);
return 0;
}
{
u32 timeout = 1000; // 10s
ddrfreq_set_sys_status(SYS_STATUS_REBOOT);
- while (dvfs_clk_get_rate(ddr.clk_dvfs_node) != ddr.reboot_rate && --timeout) {
+ while (!reboot_config_done && --timeout) {
msleep(10);
}
if (!timeout) {
pr_err("failed to set ddr clk from %luMHz to %luMHz when shutdown/reboot\n", dvfs_clk_get_rate(ddr.clk_dvfs_node) / MHZ, ddr.reboot_rate / MHZ);
}
+
return NOTIFY_OK;
}
}
EXPORT_SYMBOL(dvfs_clk_disable_limit);
+void dvfs_disable_temp_limit(void) {
+ temp_limit_enable = 0;
+ cancel_delayed_work_sync(&dvfs_temp_limit_work);
+}
+
int dvfs_clk_get_limit(struct dvfs_node *clk_dvfs_node, unsigned int *min_rate, unsigned int *max_rate)
{
int freq_limit_en;
} else if (rate > clk_dvfs_node->max_rate) {
limit_rate = clk_dvfs_node->max_rate;
}
-
- if (limit_rate > clk_dvfs_node->temp_limit_rate) {
- limit_rate = clk_dvfs_node->temp_limit_rate;
+ if (temp_limit_enable) {
+ if (limit_rate > clk_dvfs_node->temp_limit_rate) {
+ limit_rate = clk_dvfs_node->temp_limit_rate;
+ }
}
}
#include <asm/unistd.h>
#include <asm/uaccess.h>
+extern void dvfs_disable_temp_limit(void);
+
#define VERSION "1.0"
#ifdef DEBUG
static int cpufreq_notifier_policy(struct notifier_block *nb, unsigned long val, void *data)
{
+ static unsigned int min_rate=0, max_rate=-1;
struct cpufreq_policy *policy = data;
if (val != CPUFREQ_ADJUST)
if (cpufreq_is_ondemand(policy)) {
FREQ_DBG("queue work\n");
- dvfs_clk_enable_limit(clk_cpu_dvfs_node, 0, ~0);
+ dvfs_clk_enable_limit(clk_cpu_dvfs_node, min_rate, max_rate);
} else {
FREQ_DBG("cancel work\n");
- dvfs_clk_disable_limit(clk_cpu_dvfs_node);
+ dvfs_clk_get_limit(clk_cpu_dvfs_node, &min_rate, &max_rate);
}
return 0;
return NOTIFY_OK;
}
+int cpufreq_reboot_limit_freq(void)
+{
+ dvfs_disable_temp_limit();
+ dvfs_clk_enable_limit(clk_cpu_dvfs_node, 1000*suspend_freq, 1000*suspend_freq);
+ printk("cpufreq: reboot set core rate=%lu, volt=%d\n", dvfs_clk_get_rate(clk_cpu_dvfs_node),
+ regulator_get_voltage(clk_cpu_dvfs_node->vd->regulator));
+
+ return 0;
+}
+
static struct notifier_block cpufreq_reboot_notifier = {
.notifier_call = cpufreq_reboot_notifier_event,
};
static int __init cpufreq_driver_init(void)
{
register_pm_notifier(&cpufreq_pm_notifier);
- register_reboot_notifier(&cpufreq_reboot_notifier);
+ //register_reboot_notifier(&cpufreq_reboot_notifier);
return cpufreq_register_driver(&cpufreq_driver);
}