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 <asm/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->clockSetlock);
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->clockSetlock);
57 ret = dvfs_clk_set_rate(drv_data->clk, freq);
59 _mali_osk_mutex_signal(drv_data->clockSetlock);
63 dev_dbg(dev, "set freq %lu\n", freq);
65 drv_data->dvfs.current_level = level;
67 _mali_osk_mutex_signal(drv_data->clockSetlock);
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 dev_err(dev, "get pd_clk failed, %d\n", ret);
85 ret = clk_prepare_enable(drv_data->pd);
87 dev_err(dev, "prepare pd_clk failed, %d\n", ret);
91 drv_data->clk = clk_get_dvfs_node("clk_gpu");
92 if (IS_ERR(drv_data->clk)) {
93 ret = PTR_ERR(drv_data->clk);
94 dev_err(dev, "prepare clk gpu failed, %d\n", ret);
98 ret = dvfs_clk_prepare_enable(drv_data->clk);
100 dev_err(dev, "prepare clk failed, %d\n", ret);
104 drv_data->power_state = true;
109 static void mali_clock_term(struct device *dev)
111 struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
113 dvfs_clk_disable_unprepare(drv_data->clk);
114 clk_disable_unprepare(drv_data->pd);
115 drv_data->power_state = false;
118 static ssize_t show_available_frequencies(struct device *dev,
119 struct device_attribute *attr,
122 struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
126 for (i = 0; i < drv_data->fv_info_length; i++)
127 ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%lu\n",
128 drv_data->fv_info[i].freq);
133 static ssize_t show_clock(struct device *dev,
134 struct device_attribute *attr, char *buf)
136 struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
138 return scnprintf(buf, PAGE_SIZE, "%lu\n", dvfs_clk_get_rate(drv_data->clk));
141 static ssize_t set_clock(struct device *dev, struct device_attribute *attr,
142 const char *buf, size_t count)
144 struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
149 ret = kstrtoul(buf, 10, &freq);
153 for (level = drv_data->fv_info_length - 1; level > 0; level--) {
154 unsigned long tmp = drv_data->fv_info[level].freq;
159 dev_info(dev, "Using fv_info table %d: for %lu Hz\n", level, freq);
161 ret = mali_set_level(dev, level);
168 static ssize_t show_dvfs_enable(struct device *dev,
169 struct device_attribute *attr, char *buf)
171 return scnprintf(buf, PAGE_SIZE, "%u\n", mali_dvfs_is_enabled(dev));
174 static ssize_t set_dvfs_enable(struct device *dev,
175 struct device_attribute *attr, const char *buf,
178 unsigned long enable;
181 ret = kstrtoul(buf, 0, &enable);
186 mali_dvfs_enable(dev);
187 else if (enable == 0)
188 mali_dvfs_disable(dev);
195 static ssize_t show_utilisation(struct device *dev,
196 struct device_attribute *attr, char *buf)
198 return scnprintf(buf, PAGE_SIZE, "%u\n", mali_dvfs_utilisation(dev));
201 static int error_count_show(struct device *dev,struct device_attribute *attr, char *buf)
203 return sprintf(buf, "%d\n", mali_group_error);
206 DEVICE_ATTR(available_frequencies, S_IRUGO, show_available_frequencies, NULL);
207 DEVICE_ATTR(clock, S_IRUGO | S_IWUSR, show_clock, set_clock);
208 DEVICE_ATTR(dvfs_enable, S_IRUGO | S_IWUSR, show_dvfs_enable, set_dvfs_enable);
209 DEVICE_ATTR(utilisation, S_IRUGO, show_utilisation, NULL);
210 DEVICE_ATTR(error_count, 0644, error_count_show, NULL);
212 static struct attribute *mali_sysfs_entries[] = {
213 &dev_attr_available_frequencies.attr,
214 &dev_attr_clock.attr,
215 &dev_attr_dvfs_enable.attr,
216 &dev_attr_utilisation.attr,
217 &dev_attr_error_count.attr,
221 static const struct attribute_group mali_attr_group = {
222 .attrs = mali_sysfs_entries,
225 static int mali_create_sysfs(struct device *dev)
229 ret = sysfs_create_group(&dev->kobj, &mali_attr_group);
231 dev_err(dev, "create sysfs group error, %d\n", ret);
236 void mali_remove_sysfs(struct device *dev)
238 sysfs_remove_group(&dev->kobj, &mali_attr_group);
241 _mali_osk_errcode_t mali_platform_init(struct platform_device *pdev)
243 struct device *dev = &pdev->dev;
244 struct mali_platform_drv_data *mali_drv_data;
247 mali_drv_data = devm_kzalloc(dev, sizeof(*mali_drv_data), GFP_KERNEL);
248 if (!mali_drv_data) {
249 dev_err(dev, "no mem\n");
250 return _MALI_OSK_ERR_NOMEM;
253 dev_set_drvdata(dev, mali_drv_data);
255 mali_drv_data->dev = dev;
259 ret = mali_clock_init(dev);
263 ret = mali_dvfs_init(dev);
267 ret = mali_create_sysfs(dev);
271 mali_drv_data->clockSetlock = _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_ORDERED,
272 _MALI_OSK_LOCK_ORDER_UTILIZATION);
273 mali_core_scaling_enable = 1;
277 mali_clock_term(dev);
279 return _MALI_OSK_ERR_FAULT;
282 _mali_osk_errcode_t mali_platform_deinit(struct platform_device *pdev)
284 struct device *dev = &pdev->dev;
285 struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
287 mali_core_scaling_term();
288 mali_clock_term(dev);
289 _mali_osk_mutex_term(drv_data->clockSetlock);
294 _mali_osk_errcode_t mali_power_domain_control(u32 bpower_off)
296 struct mali_platform_drv_data *drv_data = dev_get_drvdata(mali_dev);
298 if (bpower_off == 0) {
299 if (!drv_data->power_state) {
300 dvfs_clk_prepare_enable(drv_data->clk);
301 clk_prepare_enable(drv_data->pd);
302 drv_data->power_state = true;
304 } else if (bpower_off == 1) {
305 if (drv_data->power_state) {
306 dvfs_clk_disable_unprepare(drv_data->clk);
307 clk_disable_unprepare(drv_data->pd);
308 drv_data->power_state = false;
315 _mali_osk_errcode_t mali_platform_power_mode_change(mali_power_mode power_mode)
318 case MALI_POWER_MODE_ON:
319 MALI_DEBUG_PRINT(2, ("MALI_POWER_MODE_ON\r\n"));
320 mali_power_domain_control(MALI_POWER_MODE_ON);
322 case MALI_POWER_MODE_LIGHT_SLEEP:
323 MALI_DEBUG_PRINT(2, ("MALI_POWER_MODE_LIGHT_SLEEP\r\n"));
324 mali_power_domain_control(MALI_POWER_MODE_LIGHT_SLEEP);
326 case MALI_POWER_MODE_DEEP_SLEEP:
327 MALI_DEBUG_PRINT(2, ("MALI_POWER_MODE_DEEP_SLEEP\r\n"));
328 mali_power_domain_control(MALI_POWER_MODE_DEEP_SLEEP);
331 MALI_DEBUG_PRINT(2, ("mali_platform_power_mode_change:power_mode(%d) not support \r\n",
337 void mali_gpu_utilization_handler(struct mali_gpu_utilization_data *data)
339 if(data->utilization_pp > 256)
342 if (mali_core_scaling_enable)
343 mali_core_scaling_update(data);
345 // dev_dbg(mali_dev, "utilization:%d\r\n", data->utilization_pp);
347 mali_dvfs_event(mali_dev, data->utilization_pp);