2 * This confidential and proprietary software may be used only as
3 * authorised by a licensing agreement from ARM Limited
4 * (C) COPYRIGHT 2009-2012 ARM Limited
6 * The entire notice above must be reproduced on all authorised
7 * copies and copies may only be made to the extent permitted
8 * by a licensing agreement from ARM Limited.
12 * @file mali_platform.c
13 * Platform specific Mali driver functions for a default platform
15 #include <linux/workqueue.h>
16 #include <linux/kernel.h>
17 #include <linux/slab.h>
18 #include <linux/gfp.h>
20 #include <linux/clk.h>
21 #include <linux/device.h>
22 #include <linux/regulator/driver.h>
23 #include <linux/miscdevice.h>
24 #include <linux/uaccess.h>
25 #include <linux/cpufreq.h>
28 #include "mali_kernel_common.h"
30 #include "arm_core_scaling.h"
31 #include "mali_platform.h"
34 static int mali_core_scaling_enable;
38 struct device *mali_dev;
40 int mali_set_level(struct device *dev, int level)
42 struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
45 unsigned int current_level;
47 _mali_osk_mutex_wait(drv_data->clock_set_lock);
49 current_level = drv_data->dvfs.current_level;
50 freq = drv_data->fv_info[level].freq;
52 if (level == current_level) {
53 _mali_osk_mutex_signal(drv_data->clock_set_lock);
57 ret = dvfs_clk_set_rate(drv_data->clk, freq);
59 _mali_osk_mutex_signal(drv_data->clock_set_lock);
63 dev_dbg(dev, "set freq %lu\n", freq);
65 drv_data->dvfs.current_level = level;
67 _mali_osk_mutex_signal(drv_data->clock_set_lock);
72 static int mali_clock_init(struct device *dev)
76 struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
78 drv_data->pd = devm_clk_get(dev, "pd_gpu");
79 if (IS_ERR(drv_data->pd)) {
80 ret = PTR_ERR(drv_data->pd);
81 /* rk3228 gpu has no power domain,save NULL for compatible*/
83 dev_err(dev, "get pd_clk failed, %d\n", ret);
90 ret = clk_prepare_enable(drv_data->pd);
92 dev_err(dev, "prepare pd_clk failed, %d\n", ret);
97 drv_data->clk = clk_get_dvfs_node("clk_gpu");
98 if (IS_ERR(drv_data->clk)) {
99 ret = PTR_ERR(drv_data->clk);
100 dev_err(dev, "prepare clk gpu failed, %d\n", ret);
104 ret = dvfs_clk_prepare_enable(drv_data->clk);
106 dev_err(dev, "prepare clk failed, %d\n", ret);
110 drv_data->power_state = true;
115 static void mali_clock_term(struct device *dev)
117 struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
119 dvfs_clk_disable_unprepare(drv_data->clk);
121 clk_disable_unprepare(drv_data->pd);
122 drv_data->power_state = false;
125 static ssize_t show_available_frequencies(struct device *dev,
126 struct device_attribute *attr,
129 struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
133 for (i = 0; i < drv_data->fv_info_length; i++)
134 ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%lu\n",
135 drv_data->fv_info[i].freq);
140 static ssize_t show_clock(struct device *dev,
141 struct device_attribute *attr, char *buf)
143 struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
145 return scnprintf(buf,
148 dvfs_clk_get_rate(drv_data->clk));
151 static ssize_t set_clock(struct device *dev, struct device_attribute *attr,
152 const char *buf, size_t count)
154 struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
159 ret = kstrtoul(buf, 10, &freq);
163 for (level = drv_data->fv_info_length - 1; level > 0; level--) {
164 unsigned long tmp = drv_data->fv_info[level].freq;
170 dev_info(dev, "Using fv_info table %d: for %lu Hz\n", level, freq);
172 ret = mali_set_level(dev, level);
179 static ssize_t show_dvfs_enable(struct device *dev,
180 struct device_attribute *attr,
183 return scnprintf(buf, PAGE_SIZE, "%u\n", mali_dvfs_is_enabled(dev));
186 static ssize_t set_dvfs_enable(struct device *dev,
187 struct device_attribute *attr,
191 unsigned long enable;
194 ret = kstrtoul(buf, 0, &enable);
199 mali_dvfs_enable(dev);
200 else if (enable == 0)
201 mali_dvfs_disable(dev);
208 static ssize_t show_utilisation(struct device *dev,
209 struct device_attribute *attr,
212 return scnprintf(buf, PAGE_SIZE, "%u\n", mali_dvfs_utilisation(dev));
215 static int error_count_show(struct device *dev,
216 struct device_attribute *attr,
219 return sprintf(buf, "%d\n", mali_group_error);
222 DEVICE_ATTR(available_frequencies, S_IRUGO, show_available_frequencies, NULL);
223 DEVICE_ATTR(clock, S_IRUGO | S_IWUSR, show_clock, set_clock);
224 DEVICE_ATTR(dvfs_enable, S_IRUGO | S_IWUSR, show_dvfs_enable, set_dvfs_enable);
225 DEVICE_ATTR(utilisation, S_IRUGO, show_utilisation, NULL);
226 DEVICE_ATTR(error_count, 0644, error_count_show, NULL);
228 static struct attribute *mali_sysfs_entries[] = {
229 &dev_attr_available_frequencies.attr,
230 &dev_attr_clock.attr,
231 &dev_attr_dvfs_enable.attr,
232 &dev_attr_utilisation.attr,
233 &dev_attr_error_count.attr,
237 static const struct attribute_group mali_attr_group = {
238 .attrs = mali_sysfs_entries,
241 static int mali_create_sysfs(struct device *dev)
245 ret = sysfs_create_group(&dev->kobj, &mali_attr_group);
247 dev_err(dev, "create sysfs group error, %d\n", ret);
252 void mali_remove_sysfs(struct device *dev)
254 sysfs_remove_group(&dev->kobj, &mali_attr_group);
257 _mali_osk_errcode_t mali_platform_init(struct platform_device *pdev)
259 struct device *dev = &pdev->dev;
260 struct mali_platform_drv_data *mali_drv_data;
263 mali_drv_data = devm_kzalloc(dev, sizeof(*mali_drv_data), GFP_KERNEL);
264 if (!mali_drv_data) {
265 dev_err(dev, "no mem\n");
266 return _MALI_OSK_ERR_NOMEM;
269 dev_set_drvdata(dev, mali_drv_data);
271 mali_drv_data->dev = dev;
275 ret = mali_clock_init(dev);
279 ret = mali_dvfs_init(dev);
283 ret = mali_create_sysfs(dev);
287 mali_drv_data->clock_set_lock =
288 _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_ORDERED,
289 _MALI_OSK_LOCK_ORDER_UTILIZATION);
290 mali_core_scaling_enable = 1;
294 mali_clock_term(dev);
296 return _MALI_OSK_ERR_FAULT;
299 _mali_osk_errcode_t mali_platform_deinit(struct platform_device *pdev)
301 struct device *dev = &pdev->dev;
302 struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
304 mali_core_scaling_term();
305 mali_clock_term(dev);
306 _mali_osk_mutex_term(drv_data->clock_set_lock);
311 _mali_osk_errcode_t mali_power_domain_control(u32 bpower_off)
313 struct mali_platform_drv_data *drv_data = dev_get_drvdata(mali_dev);
315 if (bpower_off == 0) {
316 if (!drv_data->power_state) {
317 dvfs_clk_prepare_enable(drv_data->clk);
319 clk_prepare_enable(drv_data->pd);
320 drv_data->power_state = true;
322 } else if (bpower_off == 1) {
323 if (drv_data->power_state) {
324 dvfs_clk_disable_unprepare(drv_data->clk);
326 clk_disable_unprepare(drv_data->pd);
327 drv_data->power_state = false;
334 _mali_osk_errcode_t mali_platform_power_mode_change(
335 enum mali_power_mode power_mode)
337 switch (power_mode) {
338 case MALI_POWER_MODE_ON:
339 MALI_DEBUG_PRINT(2, ("MALI_POWER_MODE_ON\r\n"));
340 mali_power_domain_control(MALI_POWER_MODE_ON);
342 case MALI_POWER_MODE_LIGHT_SLEEP:
343 MALI_DEBUG_PRINT(2, ("MALI_POWER_MODE_LIGHT_SLEEP\r\n"));
344 mali_power_domain_control(MALI_POWER_MODE_LIGHT_SLEEP);
346 case MALI_POWER_MODE_DEEP_SLEEP:
347 MALI_DEBUG_PRINT(2, ("MALI_POWER_MODE_DEEP_SLEEP\r\n"));
348 mali_power_domain_control(MALI_POWER_MODE_DEEP_SLEEP);
352 (":power_mode(%d) not support \r\n",
358 void mali_gpu_utilization_handler(struct mali_gpu_utilization_data *data)
360 if (data->utilization_pp > 256)
363 if (mali_core_scaling_enable)
364 mali_core_scaling_update(data);
366 /* dev_dbg(mali_dev, "utilization:%d\r\n", data->utilization_pp); */
368 mali_dvfs_event(mali_dev, data->utilization_pp);