1 /* drivers/gpu/t6xx/kbase/src/platform/manta/mali_kbase_dvfs.c
4 * Rockchip SoC Mali-T764 DVFS driver
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software FoundatIon.
12 * @file mali_kbase_dvfs.c
16 #include <mali_kbase.h>
17 #include <mali_kbase_uku.h>
18 #include <mali_kbase_mem.h>
19 #include <mali_midg_regmap.h>
20 #include <mali_kbase_mem_linux.h>
22 #include <linux/module.h>
23 #include <linux/init.h>
24 #include <linux/poll.h>
25 #include <linux/kernel.h>
26 #include <linux/errno.h>
27 #include <linux/platform_device.h>
28 #include <linux/pci.h>
29 #include <linux/miscdevice.h>
30 #include <linux/list.h>
31 #include <linux/semaphore.h>
33 #include <linux/uaccess.h>
34 #include <linux/interrupt.h>
36 #include <linux/cpufreq.h>
38 #include <linux/clk.h>
39 #include <linux/delay.h>
40 #include <linux/regulator/consumer.h>
41 #include <linux/regulator/driver.h>
42 #include <platform/rk/mali_kbase_platform.h>
43 #include <platform/rk/mali_kbase_dvfs.h>
44 #include <mali_kbase_gator.h>
45 #include <linux/rockchip/dvfs.h>
46 /***********************************************************/
47 /* This table and variable are using the check time share of GPU Clock */
48 /***********************************************************/
50 static mali_dvfs_info mali_dvfs_infotbl[] = {
51 {925000, 100000, 0, 70, 0},
52 {925000, 160000, 50, 65, 0},
53 {1025000, 266000, 60, 78, 0},
54 {1075000, 350000, 65, 75, 0},
55 {1125000, 400000, 70, 75, 0},
56 {1200000, 500000, 90, 100, 0},
58 mali_dvfs_info *p_mali_dvfs_infotbl = NULL;
60 unsigned int MALI_DVFS_STEP = ARRAY_SIZE(mali_dvfs_infotbl);
62 static struct cpufreq_frequency_table *mali_freq_table = NULL;
63 #ifdef CONFIG_MALI_MIDGARD_DVFS
64 typedef struct _mali_dvfs_status_type {
68 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
75 static struct workqueue_struct *mali_dvfs_wq = 0;
76 spinlock_t mali_dvfs_spinlock;
77 struct mutex mali_set_clock_lock;
78 struct mutex mali_enable_clock_lock;
80 #ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS
81 static void update_time_in_state(int level);
85 static mali_dvfs_status mali_dvfs_status_current;
87 static void mali_dvfs_event_proc(struct work_struct *w)
90 mali_dvfs_status *dvfs_status;
91 struct rk_context *platform;
93 mutex_lock(&mali_enable_clock_lock);
94 dvfs_status = &mali_dvfs_status_current;
96 if (!kbase_platform_dvfs_get_enable_status()) {
97 mutex_unlock(&mali_enable_clock_lock);
101 platform = (struct rk_context *)dvfs_status->kbdev->platform_context;
103 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
104 if ((dvfs_status->utilisation > mali_dvfs_infotbl[dvfs_status->step].max_threshold) && (dvfs_status->step < MALI_DVFS_STEP-1))
107 if (dvfs_status->step==kbase_platform_dvfs_get_level(450))
109 if (platform->utilisation > mali_dvfs_infotbl[dvfs_status->step].max_threshold)
111 BUG_ON(dvfs_status->step >= MALI_DVFS_STEP);
116 BUG_ON(dvfs_status->step >= MALI_DVFS_STEP);
120 BUG_ON(dvfs_status->step >= MALI_DVFS_STEP);
123 //else if((dvfs_status->step > 0) && (dvfs_status->utilisation < mali_dvfs_infotbl[dvfs_status->step].min_threshold))
124 else if((dvfs_status->step > 0) && (platform->time_tick == MALI_DVFS_TIME_INTERVAL) && (platform->utilisation < mali_dvfs_infotbl[dvfs_status->step].min_threshold))
126 BUG_ON(dvfs_status->step <= 0);
129 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
130 if ((dvfs_status->upper_lock >= 0) && (dvfs_status->step > dvfs_status->upper_lock))
132 dvfs_status->step = dvfs_status->upper_lock;
135 if (dvfs_status->under_lock > 0)
137 if (dvfs_status->step < dvfs_status->under_lock)
138 dvfs_status->step = dvfs_status->under_lock;
141 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
142 //printk("%n",__func__);
143 kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step);
145 mutex_unlock(&mali_enable_clock_lock);
148 static DECLARE_WORK(mali_dvfs_work, mali_dvfs_event_proc);
150 int kbase_platform_dvfs_event(struct kbase_device *kbdev, u32 utilisation)
153 struct rk_context *platform;
156 platform = (struct rk_context *)kbdev->platform_context;
158 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
159 if (platform->time_tick < MALI_DVFS_TIME_INTERVAL) {
160 platform->time_tick++;
161 platform->time_busy += kbdev->pm.metrics.time_busy;
162 platform->time_idle += kbdev->pm.metrics.time_idle;
164 platform->time_busy = kbdev->pm.metrics.time_busy;
165 platform->time_idle = kbdev->pm.metrics.time_idle;
166 platform->time_tick = 0;
169 if ((platform->time_tick == MALI_DVFS_TIME_INTERVAL) && (platform->time_idle + platform->time_busy > 0))
170 platform->utilisation = (100 * platform->time_busy) / (platform->time_idle + platform->time_busy);
172 mali_dvfs_status_current.utilisation = utilisation;
173 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
175 queue_work_on(0, mali_dvfs_wq, &mali_dvfs_work);
176 /*add error handle here */
180 int kbase_platform_dvfs_get_utilisation(void)
185 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
186 utilisation = mali_dvfs_status_current.utilisation;
187 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
192 int kbase_platform_dvfs_get_enable_status(void)
194 struct kbase_device *kbdev;
198 kbdev = mali_dvfs_status_current.kbdev;
199 spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
200 enable = kbdev->pm.metrics.timer_active;
201 spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
206 int kbase_platform_dvfs_enable(bool enable, int freq)
208 mali_dvfs_status *dvfs_status;
209 struct kbase_device *kbdev;
211 struct rk_context *platform;
213 dvfs_status = &mali_dvfs_status_current;
214 kbdev = mali_dvfs_status_current.kbdev;
216 BUG_ON(kbdev == NULL);
217 platform = (struct rk_context *)kbdev->platform_context;
219 mutex_lock(&mali_enable_clock_lock);
221 if (enable != kbdev->pm.metrics.timer_active) {
223 spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
224 kbdev->pm.metrics.timer_active = MALI_TRUE;
225 spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
226 hrtimer_start(&kbdev->pm.metrics.timer,
227 HR_TIMER_DELAY_MSEC(KBASE_PM_DVFS_FREQUENCY),
230 spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
231 kbdev->pm.metrics.timer_active = MALI_FALSE;
232 spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
233 hrtimer_cancel(&kbdev->pm.metrics.timer);
237 if (freq != MALI_DVFS_CURRENT_FREQ) {
238 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
239 platform->time_tick = 0;
240 platform->time_busy = 0;
241 platform->time_idle = 0;
242 platform->utilisation = 0;
243 dvfs_status->step = kbase_platform_dvfs_get_level(freq);
244 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
245 //printk("%s,freq = %d\n",__func__,freq);
246 kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step);
249 mutex_unlock(&mali_enable_clock_lock);
254 int kbase_platform_dvfs_init(struct kbase_device *kbdev)
258 add here with the right function to get initilization value.
260 struct rk_context *platform;
263 platform = (struct rk_context *)kbdev->platform_context;
264 if (NULL == platform)
267 mali_freq_table = dvfs_get_freq_volt_table(platform->mali_clk_node);
269 if (mali_freq_table == NULL)
271 printk("mali freq table not assigned yet,use default\n");
278 for (i = 0; mali_freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
280 if((mali_freq_table[i].frequency > 0) && (mali_freq_table[i].frequency <= 100000))
282 mali_dvfs_infotbl[i].clock = mali_freq_table[i].frequency;
283 mali_dvfs_infotbl[i].min_threshold = 0;
284 mali_dvfs_infotbl[i].max_threshold = 70;
287 else if ((mali_freq_table[i].frequency > 100000) && (mali_freq_table[i].frequency <= 200000))
289 mali_dvfs_infotbl[i].clock = mali_freq_table[i].frequency;
290 mali_dvfs_infotbl[i].min_threshold = 50;
291 mali_dvfs_infotbl[i].max_threshold = 65;
294 else if ((mali_freq_table[i].frequency > 200000) && (mali_freq_table[i].frequency <= 300000))
296 mali_dvfs_infotbl[i].clock = mali_freq_table[i].frequency;
297 mali_dvfs_infotbl[i].min_threshold = 60;
298 mali_dvfs_infotbl[i].max_threshold = 78;
301 else if ((mali_freq_table[i].frequency > 300000) && (mali_freq_table[i].frequency <= 400000))
303 mali_dvfs_infotbl[i].clock = mali_freq_table[i].frequency;
304 mali_dvfs_infotbl[i].min_threshold = 65;
305 mali_dvfs_infotbl[i].max_threshold = 75;
308 else if ((mali_freq_table[i].frequency > 400000) && (mali_freq_table[i].frequency <= 500000))
310 mali_dvfs_infotbl[i].clock = mali_freq_table[i].frequency;
311 mali_dvfs_infotbl[i].min_threshold = 90;
312 mali_dvfs_infotbl[i].max_threshold = 100;
316 p_mali_dvfs_infotbl = mali_dvfs_infotbl;
320 mali_dvfs_wq = create_singlethread_workqueue("mali_dvfs");
322 spin_lock_init(&mali_dvfs_spinlock);
323 mutex_init(&mali_set_clock_lock);
324 mutex_init(&mali_enable_clock_lock);
326 /*add a error handling here */
327 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
328 mali_dvfs_status_current.kbdev = kbdev;
329 mali_dvfs_status_current.utilisation = 0;
330 mali_dvfs_status_current.step = 0;
331 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
332 mali_dvfs_status_current.upper_lock = -1;
333 mali_dvfs_status_current.under_lock = -1;
336 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
341 void kbase_platform_dvfs_term(void)
344 destroy_workqueue(mali_dvfs_wq);
348 #endif /*CONFIG_MALI_MIDGARD_DVFS*/
350 int mali_get_dvfs_upper_locked_freq(void)
353 int locked_level = -1;
355 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
356 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
357 if (mali_dvfs_status_current.upper_lock >= 0)
358 locked_level = mali_dvfs_infotbl[mali_dvfs_status_current.upper_lock].clock;
359 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
364 int mali_get_dvfs_under_locked_freq(void)
367 int locked_level = -1;
369 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
370 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
371 if (mali_dvfs_status_current.under_lock >= 0)
372 locked_level = mali_dvfs_infotbl[mali_dvfs_status_current.under_lock].clock;
373 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
378 int mali_get_dvfs_current_level(void)
381 int current_level = -1;
383 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
384 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
385 current_level = mali_dvfs_status_current.step;
386 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
388 return current_level;
391 int mali_dvfs_freq_lock(int level)
394 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
395 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
396 if (mali_dvfs_status_current.under_lock >= 0 && mali_dvfs_status_current.under_lock > level) {
397 printk(KERN_ERR " Upper lock Error : Attempting to set upper lock to below under lock\n");
398 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
401 mali_dvfs_status_current.upper_lock = level;
402 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
404 printk(KERN_DEBUG " Upper Lock Set : %d\n", level);
409 void mali_dvfs_freq_unlock(void)
412 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
413 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
414 mali_dvfs_status_current.upper_lock = -1;
415 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
417 printk(KERN_DEBUG "mali Upper Lock Unset\n");
420 int mali_dvfs_freq_under_lock(int level)
423 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
424 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
425 if (mali_dvfs_status_current.upper_lock >= 0 && mali_dvfs_status_current.upper_lock < level) {
426 printk(KERN_ERR "mali Under lock Error : Attempting to set under lock to above upper lock\n");
427 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
430 mali_dvfs_status_current.under_lock = level;
431 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
433 printk(KERN_DEBUG "mali Under Lock Set : %d\n", level);
438 void mali_dvfs_freq_under_unlock(void)
441 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
442 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
443 mali_dvfs_status_current.under_lock = -1;
444 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
446 printk(KERN_DEBUG " mali clock Under Lock Unset\n");
449 void kbase_platform_dvfs_set_clock(kbase_device *kbdev, int freq)
451 struct rk_context *platform;
456 platform = (struct rk_context *)kbdev->platform_context;
457 if (NULL == platform)
460 if (!platform->mali_clk_node)
462 printk("mali_clk_node not init\n");
465 mali_dvfs_clk_set(platform->mali_clk_node,freq);
471 int kbase_platform_dvfs_get_level(int freq)
474 for (i = 0; i < MALI_DVFS_STEP; i++) {
475 if (mali_dvfs_infotbl[i].clock == freq)
480 void kbase_platform_dvfs_set_level(kbase_device *kbdev, int level)
482 static int prev_level = -1;
484 if (level == prev_level)
487 if (WARN_ON((level >= MALI_DVFS_STEP) || (level < 0)))
489 printk("unkown mali dvfs level:level = %d,set clock not done \n",level);
492 //panic("invalid level");
493 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
494 if (mali_dvfs_status_current.upper_lock >= 0 && level > mali_dvfs_status_current.upper_lock)
495 level = mali_dvfs_status_current.upper_lock;
496 if (mali_dvfs_status_current.under_lock >= 0 && level < mali_dvfs_status_current.under_lock)
497 level = mali_dvfs_status_current.under_lock;
499 #ifdef CONFIG_MALI_MIDGARD_DVFS
500 mutex_lock(&mali_set_clock_lock);
502 kbase_platform_dvfs_set_clock(kbdev, mali_dvfs_infotbl[level].clock);
503 #if defined(CONFIG_MALI_MIDGARD_DEBUG_SYS) && defined(CONFIG_MALI_MIDGARD_DVFS)
504 update_time_in_state(prev_level);
507 #ifdef CONFIG_MALI_MIDGARD_DVFS
508 mutex_unlock(&mali_set_clock_lock);
512 #ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS
513 #ifdef CONFIG_MALI_MIDGARD_DVFS
514 static void update_time_in_state(int level)
517 static u64 prev_time=0;
522 if (!kbase_platform_dvfs_get_enable_status())
526 prev_time=get_jiffies_64();
528 current_time = get_jiffies_64();
529 mali_dvfs_infotbl[level].time += current_time-prev_time;
531 prev_time = current_time;
535 ssize_t show_time_in_state(struct device *dev, struct device_attribute *attr, char *buf)
537 struct kbase_device *kbdev;
541 kbdev = dev_get_drvdata(dev);
543 #ifdef CONFIG_MALI_MIDGARD_DVFS
544 update_time_in_state(mali_dvfs_status_current.step);
549 for (i = 0; i < MALI_DVFS_STEP; i++)
550 ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d %llu\n", mali_dvfs_infotbl[i].clock, mali_dvfs_infotbl[i].time);
552 if (ret < PAGE_SIZE - 1)
553 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
555 buf[PAGE_SIZE - 2] = '\n';
556 buf[PAGE_SIZE - 1] = '\0';
563 ssize_t set_time_in_state(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
567 for (i = 0; i < MALI_DVFS_STEP; i++)
568 mali_dvfs_infotbl[i].time = 0;
570 printk(KERN_DEBUG "time_in_state value is reset complete.\n");