summaryrefslogtreecommitdiff
path: root/drivers/cpufreq
diff options
context:
space:
mode:
authorAnson Huang <Anson.Huang@nxp.com>2017-09-18 12:41:40 +0800
committerLeonard Crestez <leonard.crestez@nxp.com>2018-08-24 12:41:33 +0300
commit95c518121580ba316308b2fc1f0a1058ab539d40 (patch)
tree926a1fde42c48aea1f311ddfd5db93b5038eac84 /drivers/cpufreq
parentd8f214df87f327989fc1416338c672d70040d353 (diff)
MLK-16477 cpufreq: imx8: switch cpufreq governor to schedutil for multi-cluster
For multi-cluster platforms like i.MX8QM, the best cpufreq governor is schedutil, as common cpufreq framework decides default cpufreq governor in static compile, so this patch adds dynamic switch of cpufreq governor according to cluster number, changing it via sysfs interface, although it is ugly, but it realizes dynamic cpufreq governor select for users. Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r--drivers/cpufreq/imx8-cpufreq.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/drivers/cpufreq/imx8-cpufreq.c b/drivers/cpufreq/imx8-cpufreq.c
index 10b664cdbbe4..e64b2b01d7ee 100644
--- a/drivers/cpufreq/imx8-cpufreq.c
+++ b/drivers/cpufreq/imx8-cpufreq.c
@@ -17,10 +17,13 @@
#include <linux/pm_opp.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
+#include <linux/syscalls.h>
#include <soc/imx/fsl_sip.h>
#define MAX_CLUSTER_NUM 2
+static struct delayed_work cpufreq_governor_daemon;
+
static DEFINE_SPINLOCK(cpufreq_psci_lock);
struct imx8_cpufreq {
@@ -33,6 +36,36 @@ static unsigned int transition_latency[MAX_CLUSTER_NUM];
struct device *cpu_dev;
static struct thermal_cooling_device *cdev[2];
+static void cpufreq_governor_daemon_handler(struct work_struct *work)
+{
+ int fd, i;
+ unsigned char cluster_governor[MAX_CLUSTER_NUM][54] = {
+ "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor",
+ "",
+ };
+
+ /* generate second cluster's cpufreq governor path */
+ sprintf(cluster_governor[MAX_CLUSTER_NUM - 1],
+ "%s%d%s", "/sys/devices/system/cpu/cpu", num_online_cpus() - 1,
+ "/cpufreq/scaling_governor");
+
+ for (i = 0; i < MAX_CLUSTER_NUM; i++) {
+ fd = sys_open((const char __user __force *)cluster_governor[i],
+ O_RDWR, 0700);
+ if (fd >= 0) {
+ sys_write(fd, "schedutil", strlen("schedutil"));
+ sys_close(fd);
+ pr_info("switch cluster %d cpu-freq governor to schedutil\n",
+ i);
+ } else {
+ /* re-schedule if sys write is NOT ready */
+ schedule_delayed_work(&cpufreq_governor_daemon,
+ msecs_to_jiffies(3000));
+ break;
+ }
+ }
+}
+
static int imx8_set_target(struct cpufreq_policy *policy, unsigned int index)
{
struct arm_smccc_res res;
@@ -173,6 +206,11 @@ static int imx8_cpufreq_probe(struct platform_device *pdev)
for (i = 1; i < num_online_cpus(); i++) {
if (topology_physical_package_id(i) == topology_physical_package_id(0))
continue;
+
+ INIT_DELAYED_WORK(&cpufreq_governor_daemon,
+ cpufreq_governor_daemon_handler);
+ schedule_delayed_work(&cpufreq_governor_daemon,
+ msecs_to_jiffies(3000));
first_cpu_dev = cpu_dev;
cpu_dev = get_cpu_device(i);
if (!cpu_dev) {