3 * (C) COPYRIGHT ARM Limited. All rights reserved.
5 * This program is free software and is provided to you under the terms of the
6 * GNU General Public License version 2 as published by the Free Software
7 * Foundation, and any use by you of this program is subject to the terms
11 /* #define ENABLE_DEBUG_LOG */
12 #include "custom_log.h"
14 #include <mali_kbase.h>
15 #include <mali_kbase_defs.h>
16 #include <mali_kbase_config.h>
17 #include <backend/gpu/mali_kbase_pm_internal.h>
19 #include <linux/pm_runtime.h>
20 #include <linux/suspend.h>
22 #include <linux/delay.h>
24 #include "mali_kbase_rk.h"
27 * @file mali_kbase_config_rk.c
28 * 对 platform_config_of_rk 的具体实现.
30 * mali_device_driver 包含两部分 :
31 * .DP : platform_dependent_part_in_mdd :
33 * 源码在 <mdd_src_dir>/platform/<platform_name>/
34 * 在 mali_device_driver 内部,
35 * 记为 platform_dependent_part,
36 * 也被记为 platform_specific_code.
37 * .DP : common_parts_in_mdd :
39 * 源码在 <mdd_src_dir>/ 下.
40 * 在 mali_device_driver 内部, 记为 common_parts.
43 /*---------------------------------------------------------------------------*/
45 #ifdef CONFIG_REGULATOR
46 static int rk_pm_enable_regulator(struct kbase_device *kbdev);
47 static void rk_pm_disable_regulator(struct kbase_device *kbdev);
49 static inline int rk_pm_enable_regulator(struct kbase_device *kbdev)
53 static inline void rk_pm_disable_regulator(struct kbase_device *kbdev)
58 static int rk_pm_enable_clk(struct kbase_device *kbdev);
60 static void rk_pm_disable_clk(struct kbase_device *kbdev);
62 static int kbase_platform_rk_create_sysfs_files(struct device *dev);
64 static void kbase_platform_rk_remove_sysfs_files(struct device *dev);
66 /*---------------------------------------------------------------------------*/
68 static void rk_pm_power_off_delay_work(struct work_struct *work)
70 struct rk_context *platform =
71 container_of(to_delayed_work(work), struct rk_context, work);
72 struct kbase_device *kbdev = platform->kbdev;
74 if (!platform->is_powered) {
75 D("mali_dev is already powered off.");
79 if (pm_runtime_enabled(kbdev->dev)) {
80 D("to put_sync_suspend mali_dev.");
81 pm_runtime_put_sync_suspend(kbdev->dev);
84 rk_pm_disable_regulator(kbdev);
86 platform->is_powered = false;
87 KBASE_TIMELINE_GPU_POWER(kbdev, 0);
90 static int kbase_platform_rk_init(struct kbase_device *kbdev)
93 struct rk_context *platform;
95 platform = kzalloc(sizeof(*platform), GFP_KERNEL);
101 platform->is_powered = false;
102 platform->kbdev = kbdev;
104 platform->delay_ms = 200;
105 if (of_property_read_u32(kbdev->dev->of_node, "power-off-delay-ms",
106 &platform->delay_ms))
107 W("power-off-delay-ms not available.");
109 platform->power_off_wq = create_freezable_workqueue("gpu_power_off_wq");
110 if (!platform->power_off_wq) {
111 E("couldn't create workqueue");
114 INIT_DEFERRABLE_WORK(&platform->work, rk_pm_power_off_delay_work);
115 platform->utilisation_period = DEFAULT_UTILISATION_PERIOD_IN_MS;
117 ret = kbase_platform_rk_create_sysfs_files(kbdev->dev);
119 E("fail to create sysfs_files. ret = %d.", ret);
123 kbdev->platform_context = (void *)platform;
124 pm_runtime_enable(kbdev->dev);
130 static void kbase_platform_rk_term(struct kbase_device *kbdev)
132 struct rk_context *platform =
133 (struct rk_context *)kbdev->platform_context;
135 pm_runtime_disable(kbdev->dev);
136 kbdev->platform_context = NULL;
139 destroy_workqueue(platform->power_off_wq);
140 platform->is_powered = false;
141 platform->kbdev = NULL;
144 kbase_platform_rk_remove_sysfs_files(kbdev->dev);
147 struct kbase_platform_funcs_conf platform_funcs = {
148 .platform_init_func = &kbase_platform_rk_init,
149 .platform_term_func = &kbase_platform_rk_term,
152 /*---------------------------------------------------------------------------*/
154 static int rk_pm_callback_runtime_on(struct kbase_device *kbdev)
159 static void rk_pm_callback_runtime_off(struct kbase_device *kbdev)
163 static int rk_pm_callback_power_on(struct kbase_device *kbdev)
165 int ret = 1; /* Assume GPU has been powered off */
167 struct rk_context *platform = get_rk_context(kbdev);
169 cancel_delayed_work_sync(&platform->work);
171 err = rk_pm_enable_clk(kbdev);
173 E("failed to enable clk: %d", err);
177 if (platform->is_powered) {
178 D("mali_device is already powered.");
182 /* we must enable vdd_gpu before pd_gpu_in_chip. */
183 err = rk_pm_enable_regulator(kbdev);
185 E("fail to enable regulator, err : %d.", err);
189 /* 若 mali_dev 的 runtime_pm 是 enabled 的, 则... */
190 if (pm_runtime_enabled(kbdev->dev)) {
191 D("to resume mali_dev syncly.");
192 /* 对 pd_in_chip 的 on 操作,
193 * 将在 pm_domain 的 runtime_pm_callbacks 中完成.
195 err = pm_runtime_get_sync(kbdev->dev);
197 E("failed to runtime resume device: %d.", err);
199 } else if (err == 1) { /* runtime_pm_status is still active */
200 D("chip has NOT been powered off, no need to re-init.");
205 platform->is_powered = true;
206 KBASE_TIMELINE_GPU_POWER(kbdev, 1);
211 static void rk_pm_callback_power_off(struct kbase_device *kbdev)
213 struct rk_context *platform = get_rk_context(kbdev);
215 rk_pm_disable_clk(kbdev);
216 queue_delayed_work(platform->power_off_wq, &platform->work,
217 msecs_to_jiffies(platform->delay_ms));
220 int rk_kbase_device_runtime_init(struct kbase_device *kbdev)
225 void rk_kbase_device_runtime_disable(struct kbase_device *kbdev)
229 struct kbase_pm_callback_conf pm_callbacks = {
230 .power_on_callback = rk_pm_callback_power_on,
231 .power_off_callback = rk_pm_callback_power_off,
233 .power_runtime_init_callback = rk_kbase_device_runtime_init,
234 .power_runtime_term_callback = rk_kbase_device_runtime_disable,
235 .power_runtime_on_callback = rk_pm_callback_runtime_on,
236 .power_runtime_off_callback = rk_pm_callback_runtime_off,
237 #else /* CONFIG_PM */
238 .power_runtime_init_callback = NULL,
239 .power_runtime_term_callback = NULL,
240 .power_runtime_on_callback = NULL,
241 .power_runtime_off_callback = NULL,
242 #endif /* CONFIG_PM */
245 int kbase_platform_early_init(void)
247 /* Nothing needed at this stage */
251 /*---------------------------------------------------------------------------*/
253 void kbase_platform_rk_shutdown(struct kbase_device *kbdev)
255 I("to make vdd_gpu enabled for turning off pd_gpu in pm_framework.");
256 rk_pm_enable_regulator(kbdev);
259 /*---------------------------------------------------------------------------*/
261 #ifdef CONFIG_REGULATOR
262 static int rk_pm_enable_regulator(struct kbase_device *kbdev)
266 if (!kbdev->regulator) {
267 W("no mali regulator control, no need to enable.");
271 D("to enable regulator.");
272 ret = regulator_enable(kbdev->regulator);
274 E("fail to enable regulator, ret : %d.", ret);
282 static void rk_pm_disable_regulator(struct kbase_device *kbdev)
284 if (!(kbdev->regulator)) {
285 W("no mali regulator control, no need to disable.");
289 D("to disable regulator.");
290 regulator_disable(kbdev->regulator);
294 static int rk_pm_enable_clk(struct kbase_device *kbdev)
298 if (!(kbdev->clock)) {
299 W("no mali clock control, no need to enable.");
302 err = clk_enable(kbdev->clock);
304 E("failed to enable clk: %d.", err);
310 static void rk_pm_disable_clk(struct kbase_device *kbdev)
312 if (!(kbdev->clock)) {
313 W("no mali clock control, no need to disable.");
315 D("to disable clk.");
316 clk_disable(kbdev->clock);
320 /*---------------------------------------------------------------------------*/
322 static ssize_t utilisation_period_show(struct device *dev,
323 struct device_attribute *attr,
326 struct kbase_device *kbdev = dev_get_drvdata(dev);
327 struct rk_context *platform = get_rk_context(kbdev);
330 ret += snprintf(buf, PAGE_SIZE, "%u\n", platform->utilisation_period);
335 static ssize_t utilisation_period_store(struct device *dev,
336 struct device_attribute *attr,
340 struct kbase_device *kbdev = dev_get_drvdata(dev);
341 struct rk_context *platform = get_rk_context(kbdev);
344 ret = kstrtouint(buf, 0, &platform->utilisation_period);
346 E("invalid input period : %s.", buf);
349 D("set utilisation_period to '%d'.", platform->utilisation_period);
354 static ssize_t utilisation_show(struct device *dev,
355 struct device_attribute *attr,
358 struct kbase_device *kbdev = dev_get_drvdata(dev);
359 struct rk_context *platform = get_rk_context(kbdev);
361 unsigned long period_in_us = platform->utilisation_period * 1000;
362 unsigned long total_time;
363 unsigned long busy_time;
364 unsigned long utilisation;
366 kbase_pm_reset_dvfs_utilisation(kbdev);
367 usleep_range(period_in_us, period_in_us + 100);
368 kbase_pm_get_dvfs_utilisation(kbdev, &total_time, &busy_time);
369 /* 'devfreq_dev_profile' instance registered to devfreq
370 * also uses kbase_pm_reset_dvfs_utilisation
371 * and kbase_pm_get_dvfs_utilisation.
372 * it's better to cat this file when DVFS is disabled.
374 D("total_time : %lu, busy_time : %lu.", total_time, busy_time);
376 utilisation = busy_time * 100 / total_time;
377 ret += snprintf(buf, PAGE_SIZE, "%ld\n", utilisation);
382 static DEVICE_ATTR_RW(utilisation_period);
383 static DEVICE_ATTR_RO(utilisation);
385 static int kbase_platform_rk_create_sysfs_files(struct device *dev)
389 ret = device_create_file(dev, &dev_attr_utilisation_period);
391 E("fail to create sysfs file 'utilisation_period'.");
395 ret = device_create_file(dev, &dev_attr_utilisation);
397 E("fail to create sysfs file 'utilisation'.");
398 goto remove_utilisation_period;
403 remove_utilisation_period:
404 device_remove_file(dev, &dev_attr_utilisation_period);
409 static void kbase_platform_rk_remove_sysfs_files(struct device *dev)
411 device_remove_file(dev, &dev_attr_utilisation_period);
412 device_remove_file(dev, &dev_attr_utilisation);