*
* Cpuquiet driver for Tegra CPUs
*
- * Copyright (c) 2012-2013 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2012-2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
*/
static int no_lp;
static bool enable;
+static unsigned int idle_bottom_freq;
#ifdef CONFIG_TEGRA_CLUSTER_CONTROL
static unsigned long up_delay;
static unsigned long down_delay;
static unsigned int idle_top_freq;
-static unsigned int idle_bottom_freq;
static struct clk *cpu_clk;
static struct clk *cpu_g_clk;
static struct clk *cpu_lp_clk;
}
}
}
+#else
+static inline void __update_target_cluster(unsigned int cpu_freq, bool suspend)
+{ }
#endif
static int update_core_config(unsigned int cpunumber, bool up)
return -EINVAL;
}
-
if (up) {
cpumask_set_cpu(cpunumber, &cr_online_requests);
cpumask_clear_cpu(cpunumber, &cr_offline_requests);
return NOTIFY_OK;
}
-#ifdef CONFIG_TEGRA_CLUSTER_CONTROL
+#ifndef CONFIG_TEGRA_CLUSTER_CONTROL
+/* Must be called with tegra_cpu_lock held */
+static void __idle_stop_governor(unsigned int freq)
+{
+ if (cpq_state == TEGRA_CPQ_DISABLED)
+ return;
+
+ if (freq <= idle_bottom_freq && num_online_cpus() == 1)
+ cpuquiet_device_busy();
+ else
+ cpuquiet_device_free();
+}
+#endif
+
static int __cpuinit cpu_online_notify(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
+ unsigned int freq;
+
switch (action) {
case CPU_POST_DEAD:
if (num_online_cpus() == 1) {
mutex_lock(tegra_cpu_lock);
- __update_target_cluster(tegra_getspeed(0), false);
+ freq = tegra_getspeed(0);
+ __update_target_cluster(freq, false);
+#ifndef CONFIG_TEGRA_CLUSTER_CONTROL
+ __idle_stop_governor(freq);
+#endif
mutex_unlock(tegra_cpu_lock);
}
break;
case CPU_ONLINE:
case CPU_ONLINE_FROZEN:
mutex_lock(tegra_cpu_lock);
- __update_target_cluster(tegra_getspeed(0), false);
+ freq = tegra_getspeed(0);
+ __update_target_cluster(freq, false);
+#ifndef CONFIG_TEGRA_CLUSTER_CONTROL
+ __idle_stop_governor(freq);
+#endif
mutex_unlock(tegra_cpu_lock);
break;
}
return NOTIFY_OK;
}
+#ifdef CONFIG_TEGRA_CLUSTER_CONTROL
/* must be called with tegra_cpu_lock held */
void tegra_auto_hotplug_governor(unsigned int cpu_freq, bool suspend)
{
__update_target_cluster(cpu_freq, suspend);
}
+#else
+void tegra_auto_hotplug_governor(unsigned int cpu_freq, bool suspend)
+{
+ __idle_stop_governor(cpu_freq);
+}
+#endif
static struct notifier_block __cpuinitdata cpu_online_notifier = {
.notifier_call = cpu_online_notify,
};
-#endif
static struct notifier_block min_cpus_notifier = {
.notifier_call = min_cpus_notify,
CPQ_ATTRIBUTE_CUSTOM(no_lp, 0644, show_int_attribute, store_no_lp);
CPQ_BASIC_ATTRIBUTE(idle_top_freq, 0644, uint);
-CPQ_BASIC_ATTRIBUTE(idle_bottom_freq, 0644, uint);
CPQ_ATTRIBUTE(up_delay, 0644, ulong, delay_callback);
CPQ_ATTRIBUTE(down_delay, 0644, ulong, delay_callback);
#endif
+CPQ_BASIC_ATTRIBUTE(idle_bottom_freq, 0644, uint);
CPQ_ATTRIBUTE(hotplug_timeout, 0644, ulong, delay_callback);
CPQ_ATTRIBUTE(enable, 0644, bool, enable_callback);
&up_delay_attr.attr,
&down_delay_attr.attr,
&idle_top_freq_attr.attr,
- &idle_bottom_freq_attr.attr,
#endif
+ &idle_bottom_freq_attr.attr,
&enable_attr.attr,
&hotplug_timeout_attr.attr,
NULL,
if (pm_qos_add_notifier(PM_QOS_MAX_ONLINE_CPUS, &max_cpus_notifier))
pr_err("%s: Failed to register max cpus PM QoS notifier\n",
__func__);
-#ifdef CONFIG_TEGRA_CLUSTER_CONTROL
+
register_hotcpu_notifier(&cpu_online_notifier);
+
+#ifndef CONFIG_TEGRA_CLUSTER_CONTROL
+ idle_bottom_freq = 714000;
#endif
err = cpuquiet_register_driver(&tegra_cpuquiet_driver);