On SoCs, where the governor and the mechanism to control the frequency for
devices like caches is hosted on the System Control Processor (SCP), there
exists a need track the frequency changes in a reliable way and provide
ways to tweaking parameters on the remote governor.

To address this introduce the new remote devfreq governor that provides for
a way to track the frequency changes on remote devices. It uses the newly
introduced target_freq attribute flag and track_remote flag to achieve
this.

Signed-off-by: Sibi Sankar <[email protected]>
---
 drivers/devfreq/Kconfig           |  8 ++++
 drivers/devfreq/Makefile          |  1 +
 drivers/devfreq/governor_remote.c | 80 +++++++++++++++++++++++++++++++
 include/linux/devfreq.h           |  1 +
 4 files changed, 90 insertions(+)
 create mode 100644 drivers/devfreq/governor_remote.c

diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index c999c4a1e567..2caa87554914 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -56,6 +56,14 @@ config DEVFREQ_GOV_POWERSAVE
          the DEVFREQ framework returns the lowest frequency available
          at any time.
 
+config DEVFREQ_GOV_REMOTE
+       tristate "Remote"
+       help
+         A simple governor to track the frequency of devices whose
+         dvfs control lies outside the kernel. This governor acts
+         as an observer and provides for ways to track frequency and
+         set/get information related to the remote dvfs device.
+
 config DEVFREQ_GOV_USERSPACE
        tristate "Userspace"
        help
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
index 404179d79a9d..cde57c8cda76 100644
--- a/drivers/devfreq/Makefile
+++ b/drivers/devfreq/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_PM_DEVFREQ_EVENT)  += devfreq-event.o
 obj-$(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)      += governor_simpleondemand.o
 obj-$(CONFIG_DEVFREQ_GOV_PERFORMANCE)  += governor_performance.o
 obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE)    += governor_powersave.o
+obj-$(CONFIG_DEVFREQ_GOV_REMOTE)       += governor_remote.o
 obj-$(CONFIG_DEVFREQ_GOV_USERSPACE)    += governor_userspace.o
 obj-$(CONFIG_DEVFREQ_GOV_PASSIVE)      += governor_passive.o
 
diff --git a/drivers/devfreq/governor_remote.c 
b/drivers/devfreq/governor_remote.c
new file mode 100644
index 000000000000..6bff3cdaf1e5
--- /dev/null
+++ b/drivers/devfreq/governor_remote.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/devfreq.h>
+#include <linux/devfreq-governor.h>
+
+static int devfreq_remote_track_func(struct devfreq *devfreq, unsigned long 
*freq)
+{
+       unsigned long cur_freq = 0;
+
+       if (devfreq->profile->get_cur_freq)
+               devfreq->profile->get_cur_freq(devfreq->dev.parent, &cur_freq);
+
+       *freq = cur_freq;
+
+       return 0;
+}
+
+static int devfreq_remote_track_handler(struct devfreq *devfreq, unsigned int 
event, void *data)
+{
+       switch (event) {
+       case DEVFREQ_GOV_START:
+               devfreq_monitor_start(devfreq);
+               break;
+
+       case DEVFREQ_GOV_STOP:
+               devfreq_monitor_stop(devfreq);
+               break;
+
+       case DEVFREQ_GOV_UPDATE_INTERVAL:
+               devfreq_update_interval(devfreq, (unsigned int *)data);
+               break;
+
+       case DEVFREQ_GOV_SUSPEND:
+               devfreq_monitor_suspend(devfreq);
+               break;
+
+       case DEVFREQ_GOV_RESUME:
+               devfreq_monitor_resume(devfreq);
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static struct devfreq_governor devfreq_remote_track = {
+       .name = DEVFREQ_GOV_REMOTE,
+       .attrs = DEVFREQ_GOV_ATTR_POLLING_INTERVAL
+               | DEVFREQ_GOV_ATTR_TIMER,
+       .flags = DEVFREQ_GOV_FLAG_IMMUTABLE
+               | DEVFREQ_GOV_FLAG_TRACK_REMOTE,
+       .get_target_freq = devfreq_remote_track_func,
+       .event_handler = devfreq_remote_track_handler,
+};
+
+static int __init devfreq_remote_track_init(void)
+{
+       return devfreq_add_governor(&devfreq_remote_track);
+}
+subsys_initcall(devfreq_remote_track_init);
+
+static void __exit devfreq_remote_track_exit(void)
+{
+       int ret;
+
+       ret = devfreq_remove_governor(&devfreq_remote_track);
+       if (ret)
+               pr_err("%s: failed remove governor %d\n", __func__, ret);
+}
+module_exit(devfreq_remote_track_exit);
+
+MODULE_DESCRIPTION("DEVFREQ Remote Tracking governor");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index dc1075dc3446..4d50cf230950 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -21,6 +21,7 @@
 #define DEVFREQ_GOV_POWERSAVE          "powersave"
 #define DEVFREQ_GOV_USERSPACE          "userspace"
 #define DEVFREQ_GOV_PASSIVE            "passive"
+#define DEVFREQ_GOV_REMOTE             "remote"
 
 /* DEVFREQ notifier interface */
 #define DEVFREQ_TRANSITION_NOTIFIER    (0)
-- 
2.34.1

Reply via email to