summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/msm/msm_gpu_devfreq.c
diff options
context:
space:
mode:
authorRob Clark <robdclark@chromium.org>2021-07-26 17:46:48 +0300
committerRob Clark <robdclark@chromium.org>2021-07-28 03:54:36 +0300
commitaf5b4fff0fe80c8a43fa218e10c55ab8d2ff4dcb (patch)
tree794c8612611e3944e1d952b86dc3d52f03bfef79 /drivers/gpu/drm/msm/msm_gpu_devfreq.c
parent298287f6e79a8a695d9e3a8a0b040f13d0805c77 (diff)
downloadlinux-af5b4fff0fe80c8a43fa218e10c55ab8d2ff4dcb.tar.xz
drm/msm: Split out devfreq handling
Before we start adding more cleverness, split it into it's own file. Signed-off-by: Rob Clark <robdclark@chromium.org> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> Link: https://lore.kernel.org/r/20210726144653.2180096-2-robdclark@gmail.com Signed-off-by: Rob Clark <robdclark@chromium.org>
Diffstat (limited to 'drivers/gpu/drm/msm/msm_gpu_devfreq.c')
-rw-r--r--drivers/gpu/drm/msm/msm_gpu_devfreq.c133
1 files changed, 133 insertions, 0 deletions
diff --git a/drivers/gpu/drm/msm/msm_gpu_devfreq.c b/drivers/gpu/drm/msm/msm_gpu_devfreq.c
new file mode 100644
index 000000000000..3bcea0baddab
--- /dev/null
+++ b/drivers/gpu/drm/msm/msm_gpu_devfreq.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ */
+
+#include "msm_gpu.h"
+#include "msm_gpu_trace.h"
+
+#include <linux/devfreq.h>
+#include <linux/devfreq_cooling.h>
+
+/*
+ * Power Management:
+ */
+
+static int msm_devfreq_target(struct device *dev, unsigned long *freq,
+ u32 flags)
+{
+ struct msm_gpu *gpu = dev_to_gpu(dev);
+ struct dev_pm_opp *opp;
+
+ opp = devfreq_recommended_opp(dev, freq, flags);
+
+ if (IS_ERR(opp))
+ return PTR_ERR(opp);
+
+ trace_msm_gpu_freq_change(dev_pm_opp_get_freq(opp));
+
+ if (gpu->funcs->gpu_set_freq)
+ gpu->funcs->gpu_set_freq(gpu, opp);
+ else
+ clk_set_rate(gpu->core_clk, *freq);
+
+ dev_pm_opp_put(opp);
+
+ return 0;
+}
+
+static int msm_devfreq_get_dev_status(struct device *dev,
+ struct devfreq_dev_status *status)
+{
+ struct msm_gpu *gpu = dev_to_gpu(dev);
+ ktime_t time;
+
+ if (gpu->funcs->gpu_get_freq)
+ status->current_frequency = gpu->funcs->gpu_get_freq(gpu);
+ else
+ status->current_frequency = clk_get_rate(gpu->core_clk);
+
+ status->busy_time = gpu->funcs->gpu_busy(gpu);
+
+ time = ktime_get();
+ status->total_time = ktime_us_delta(time, gpu->devfreq.time);
+ gpu->devfreq.time = time;
+
+ return 0;
+}
+
+static int msm_devfreq_get_cur_freq(struct device *dev, unsigned long *freq)
+{
+ struct msm_gpu *gpu = dev_to_gpu(dev);
+
+ if (gpu->funcs->gpu_get_freq)
+ *freq = gpu->funcs->gpu_get_freq(gpu);
+ else
+ *freq = clk_get_rate(gpu->core_clk);
+
+ return 0;
+}
+
+static struct devfreq_dev_profile msm_devfreq_profile = {
+ .polling_ms = 10,
+ .target = msm_devfreq_target,
+ .get_dev_status = msm_devfreq_get_dev_status,
+ .get_cur_freq = msm_devfreq_get_cur_freq,
+};
+
+void msm_devfreq_init(struct msm_gpu *gpu)
+{
+ /* We need target support to do devfreq */
+ if (!gpu->funcs->gpu_busy)
+ return;
+
+ msm_devfreq_profile.initial_freq = gpu->fast_rate;
+
+ /*
+ * Don't set the freq_table or max_state and let devfreq build the table
+ * from OPP
+ * After a deferred probe, these may have be left to non-zero values,
+ * so set them back to zero before creating the devfreq device
+ */
+ msm_devfreq_profile.freq_table = NULL;
+ msm_devfreq_profile.max_state = 0;
+
+ gpu->devfreq.devfreq = devm_devfreq_add_device(&gpu->pdev->dev,
+ &msm_devfreq_profile, DEVFREQ_GOV_SIMPLE_ONDEMAND,
+ NULL);
+
+ if (IS_ERR(gpu->devfreq.devfreq)) {
+ DRM_DEV_ERROR(&gpu->pdev->dev, "Couldn't initialize GPU devfreq\n");
+ gpu->devfreq.devfreq = NULL;
+ return;
+ }
+
+ devfreq_suspend_device(gpu->devfreq.devfreq);
+
+ gpu->cooling = of_devfreq_cooling_register(gpu->pdev->dev.of_node,
+ gpu->devfreq.devfreq);
+ if (IS_ERR(gpu->cooling)) {
+ DRM_DEV_ERROR(&gpu->pdev->dev,
+ "Couldn't register GPU cooling device\n");
+ gpu->cooling = NULL;
+ }
+}
+
+void msm_devfreq_cleanup(struct msm_gpu *gpu)
+{
+ devfreq_cooling_unregister(gpu->cooling);
+}
+
+void msm_devfreq_resume(struct msm_gpu *gpu)
+{
+ gpu->devfreq.busy_cycles = 0;
+ gpu->devfreq.time = ktime_get();
+
+ devfreq_resume_device(gpu->devfreq.devfreq);
+}
+
+void msm_devfreq_suspend(struct msm_gpu *gpu)
+{
+ devfreq_suspend_device(gpu->devfreq.devfreq);
+}