85fa87a3ec77f353dbd819b779f8332a1b57c3f8
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / midgard / platform / rk / mali_kbase_platform.c
1 /* drivers/gpu/t6xx/kbase/src/platform/rk/mali_kbase_platform.c
2  *
3  * Rockchip SoC Mali-T764 platform-dependent codes
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software FoundatIon.
8  */
9
10 /**
11  * @file mali_kbase_platform.c
12  * 
13  * 对 mali_kbase_platform.h 声明的 pm, clk 等接口的具体实现. 
14  */
15
16 #include <mali_kbase.h>
17 #include <mali_kbase_pm.h>
18 #include <mali_kbase_uku.h>
19 #include <mali_kbase_mem.h>
20 #include <mali_midg_regmap.h>
21 #include <mali_kbase_mem_linux.h>
22
23 #include <linux/module.h>
24 #include <linux/init.h>
25 #include <linux/poll.h>
26 #include <linux/kernel.h>
27 #include <linux/errno.h>
28 #include <linux/platform_device.h>
29 #include <linux/pci.h>
30 #include <linux/miscdevice.h>
31 #include <linux/list.h>
32 #include <linux/semaphore.h>
33 #include <linux/fs.h>
34 #include <linux/uaccess.h>
35 #include <linux/interrupt.h>
36 #include <linux/io.h>
37
38 #include <linux/fb.h>
39 #include <linux/clk.h>
40 #include <linux/delay.h>
41 #include <platform/rk/mali_kbase_platform.h>
42 #include <platform/rk/mali_kbase_dvfs.h>
43
44 #include <mali_kbase_gator.h>
45
46 #include <linux/rockchip/dvfs.h> 
47
48 // #define ENABLE_DEBUG_LOG
49 #include "custom_log.h"
50
51 /* ############################################################################################# */
52
53 #define MALI_T7XX_DEFAULT_CLOCK 100000
54
55
56 /**
57  * clk_of_gpu_dvfs_node 的状态. 
58  * 1, clock 被使能.
59  * 0, 禁止.
60  */
61 static int mali_clk_status = 0;
62
63 /**
64  * gpu_power_domain 的状态. 
65  * 1, 上电. 
66  * 0, 掉电.
67  */
68 static int mali_pd_status = 0;
69
70 // u32 kbase_group_error = 0;
71 static struct kobject *rk_gpu;
72
73 int mali_dvfs_clk_set(struct dvfs_node *node, unsigned long rate)
74 {
75         int ret = 0;
76         if(!node)
77         {
78                 printk("clk_get_dvfs_node error \r\n");
79                 ret = -1;
80         }
81         /* .KP : 调用 dvfs_module 设置 gpu_clk. */
82         ret = dvfs_clk_set_rate(node,rate * MALI_KHZ);
83         if(ret)
84         {
85                 printk("dvfs_clk_set_rate error \r\n");
86         }
87         return ret;
88 }
89
90 /**
91  * 初始化和 gpu_pm 和 gpu_clk.
92  */
93 static int kbase_platform_power_clock_init(struct kbase_device *kbdev)
94 {
95         /*struct device *dev = kbdev->dev;*/
96         struct rk_context *platform;
97
98         platform = (struct rk_context *)kbdev->platform_context;
99         if (NULL == platform)
100                 panic("oops");
101         
102         /* enable mali t760 powerdomain*/       
103         platform->mali_pd = clk_get(NULL,"pd_gpu");
104         if(IS_ERR_OR_NULL(platform->mali_pd))
105         {
106                 platform->mali_pd = NULL;
107                 printk(KERN_ERR "%s, %s(): failed to get [platform->mali_pd]\n", __FILE__, __func__);
108                 goto out;
109         }
110         else
111         {
112                 clk_prepare_enable(platform->mali_pd);
113                 printk("mali pd enabled\n");
114         }
115         mali_pd_status = 1;
116         
117         /* enable mali t760 clock */
118         platform->mali_clk_node = clk_get_dvfs_node("clk_gpu");
119         if (IS_ERR_OR_NULL(platform->mali_clk_node)) 
120         {
121                 platform->mali_clk_node = NULL;
122                 printk(KERN_ERR "%s, %s(): failed to get [platform->mali_clk_node]\n", __FILE__, __func__);
123                 goto out;
124         } 
125         else 
126         {
127                 dvfs_clk_prepare_enable(platform->mali_clk_node);
128                 printk("clk enabled\n");
129         }
130         mali_dvfs_clk_set(platform->mali_clk_node, MALI_T7XX_DEFAULT_CLOCK);
131         mali_clk_status = 1;
132
133         return 0;
134         
135 out:
136         if(platform->mali_pd)
137                 clk_put(platform->mali_pd);
138         
139         return -EPERM;
140
141 }
142
143 int kbase_platform_clock_off(struct kbase_device *kbdev)
144 {
145         struct rk_context *platform;
146         if (!kbdev)
147                 return -ENODEV;
148
149         platform = (struct rk_context *)kbdev->platform_context;
150         if (!platform)
151                 return -ENODEV;
152
153         if (mali_clk_status == 0)
154                 return 0;
155         
156         if((platform->mali_clk_node))
157                 dvfs_clk_disable_unprepare(platform->mali_clk_node);
158         
159         mali_clk_status = 0;
160
161         return 0;
162 }
163
164 int kbase_platform_clock_on(struct kbase_device *kbdev)
165 {
166         struct rk_context *platform;
167         if (!kbdev)
168                 return -ENODEV;
169
170         platform = (struct rk_context *)kbdev->platform_context;
171         if (!platform)
172                 return -ENODEV;
173
174         if (mali_clk_status == 1)
175                 return 0;
176         
177         if(platform->mali_clk_node)
178                 dvfs_clk_prepare_enable(platform->mali_clk_node);
179
180         mali_clk_status = 1;
181
182         return 0;
183 }
184
185 int kbase_platform_is_power_on(void)
186 {
187         return mali_pd_status;
188 }
189
190 /*turn on power domain*/
191 int kbase_platform_power_on(struct kbase_device *kbdev)
192 {
193         struct rk_context *platform;
194         if (!kbdev)
195                 return -ENODEV;
196
197         platform = (struct rk_context *)kbdev->platform_context;
198         if (!platform)
199                 return -ENODEV;
200
201         if (mali_pd_status == 1)
202                 return 0;
203 #if 1   
204         if(platform->mali_pd)
205                 clk_prepare_enable(platform->mali_pd);
206 #endif
207         mali_pd_status = 1;
208         KBASE_TIMELINE_GPU_POWER(kbdev, 1);
209
210         return 0;
211 }
212
213 /*turn off power domain*/
214 int kbase_platform_power_off(struct kbase_device *kbdev)
215 {
216         struct rk_context *platform;
217         if (!kbdev)
218                 return -ENODEV;
219
220         platform = (struct rk_context *)kbdev->platform_context;
221         if (!platform)
222                 return -ENODEV;
223
224         if (mali_pd_status== 0)
225                 return 0;
226 #if 1
227         if(platform->mali_pd)
228                 clk_disable_unprepare(platform->mali_pd);
229 #endif
230         mali_pd_status = 0;
231         KBASE_TIMELINE_GPU_POWER(kbdev, 0);
232
233         return 0;
234 }
235
236
237 int kbase_platform_cmu_pmu_control(struct kbase_device *kbdev, int control)
238 {
239         unsigned long flags;
240         struct rk_context *platform;
241         if (!kbdev)
242                 return -ENODEV;
243
244         platform = (struct rk_context *)kbdev->platform_context;
245         if (!platform)
246                 return -ENODEV;
247
248         spin_lock_irqsave(&platform->cmu_pmu_lock, flags);
249
250         /* off */
251         if (control == 0) 
252         {
253                 /* 若已经关闭, 则... */
254                 if (platform->cmu_pmu_status == 0) 
255                 {
256                         spin_unlock_irqrestore(&platform->cmu_pmu_lock, flags);
257                         return 0;
258                 }
259
260                 /* 关闭 gpu_power_domain. */
261                 if (kbase_platform_power_off(kbdev))
262                 {
263                         panic("failed to turn off mali power domain\n");
264                 }
265                 /* 关闭 gpu_dvfs_node 的 clock. */
266                 if (kbase_platform_clock_off(kbdev))
267                 {
268                         panic("failed to turn off mali clock\n");
269                 }
270
271                 platform->cmu_pmu_status = 0;
272                 printk("turn off mali power \n");
273         } 
274         else /* on */
275         {
276                 if (platform->cmu_pmu_status == 1) 
277                 {
278                         spin_unlock_irqrestore(&platform->cmu_pmu_lock, flags);
279                         return 0;
280                 }
281
282                 /* 开启 gpu_power_domain. */
283                 if (kbase_platform_power_on(kbdev))
284                 {
285                         panic("failed to turn on mali power domain\n");
286                 }
287                 /* 使能 gpu_dvfs_node 的 clock. */
288                 if (kbase_platform_clock_on(kbdev))
289                 {
290                         panic("failed to turn on mali clock\n");
291                 }
292
293                 platform->cmu_pmu_status = 1;
294                 printk(KERN_ERR "turn on mali power\n");
295         }
296
297         spin_unlock_irqrestore(&platform->cmu_pmu_lock, flags);
298
299         return 0;
300 }
301
302 /*---------------------------------------------------------------------------*/
303
304 static ssize_t error_count_show(struct device *dev,struct device_attribute *attr, char *buf)
305 {
306         struct kbase_device *kbdev = dev_get_drvdata(dev);
307         ssize_t ret;
308
309         D_PTR(dev);
310         if ( NULL == kbdev )
311         {
312                 E("fail to get kbase_device instance.");
313                 return 0;
314         }
315
316         D_DEC(kbdev->kbase_group_error);
317         ret = scnprintf(buf, PAGE_SIZE, "%u\n", kbdev->kbase_group_error);
318         return ret;
319 }
320 static DEVICE_ATTR(error_count, S_IRUGO, error_count_show, NULL);
321
322
323 /*---------------------------------------------------------------------------*/
324 /* < 对在 sysfs_dir_of_mali_device 下的 rk_ext_file_nodes 的具体实现,  >*/
325 // .DP : impl_of_rk_ext_file_nodes.
326
327 /**
328  * .doc : 对 sysfs_dir_of_mali_device 下 rk_ext_file_nodes 提供的接口的定义
329  *
330  * sysfs_dir_of_mali_device 通常是 sys/devices/ffa30000.gpu
331  *
332  * 其下有如下的 rk_ext_file_nodes : 
333  *      clock, 
334  *              对该文件的 cat 操作, 将输出当前 gpu_clk_freq 和可能的 freq 的列表, 形如 : 
335  *                      current_gpu_clk_freq :  99000 KHz
336  *                      possible_freqs : 99000, 179000, 297000, 417000, 480000 (KHz)
337  *              出现在 "possible_freqs" 中的有效频点, 依赖在 .dts 文件中的配置.
338  *              可以使用 echo 命令向本文件写入待设置的 gpu_clk_freq_in_khz, 比如 : 
339  *                      echo 417000 > clock
340  *              注意, 这里写入的 gpu_clk_freq_in_khz "必须" 是出现在 possible_freqs 中的.
341  *              另外, mali_module 默认使能 dvfs, 
342  *              所以若希望将 gpu_clk 固定在上面的特定 freq, 要关闭 dvfs 先 :
343  *                      echo off > dvfs
344  *      fbdev, 
345  *              只支持 cat. 
346  *              .R : 目前不确定该提供接口的用意.
347  *      // dtlb,
348  *      dvfs,
349  *              cat 该节点, 将返回当前 mali_dvfs 的状态, 包括 mali_dvfs 是否开启, gpu 使用率, 当前 gpu_clk 频率.
350  *              若当前 mali_dvfs 被开启, 可能返回如下信息 : 
351  *                      mali_dvfs is ON 
352  *                      gpu_utilisation : 100 
353  *                      current_gpu_clk_freq : 480 MHz
354  *              若当前 mali_dvfs 被关闭, 可能返回 : 
355  *                      mali_dvfs is OFF 
356  *                      current_gpu_clk_freq : 99 MHz
357  *              若一段时间没有 job 下发到 gpu, common_parts 也会自动关闭 mali_dvfs.
358  *
359  *              将字串 off 写入该节点, 将关闭 mali_dvfs, 
360  *              且会将 gpu_clk_freq 固定到可能的最高的频率 或者 gpu_clk_freq_of_upper_limit(若有指定).
361  *              之后, 若将字串 on 写入该节点, 将重新开启 mali_dvfs.
362  *
363  *      dvfs_upper_lock,
364  *              cat 该节点, 返回当前 dvfs_level_upper_limit 的信息, 诸如
365  *                      upper_lock_freq : 417000 KHz
366  *                      possible upper_lock_freqs : 99000, 179000, 297000, 417000, 480000 (KHz)
367  *                      if you want to unset upper_lock_freq, to echo 'off' to this file.
368  *              
369  *              对该节点写入上面 possible upper_lock_freqs 中的某个 频率, 可以将该频率设置为 gpu_clk_freq_of_upper_limit, 比如.
370  *                      echo 417000 > dvfs_upper_lock
371  *              若要清除之前设置的 dvfs_level_upper_limit, 写入 off 即可.
372  *                      
373  *      dvfs_under_lock,
374  *              cat 该节点, 返回当前 dvfs_level_lower_limit 的信息, 诸如
375  *                      under_lock_freq : 179000 KHz 
376  *                      possible under_lock_freqs : 99000, 179000, 297000, 417000, 480000 (KHz) 
377  *                      if you want to unset under_lock_freq, to echo 'off' to this file.
378  *              对该节点写入上面 possible under_lock_freq 中的某个 频率, 可以将该频率设置为 gpu_clk_freq_of_lower_limit, 比如.
379  *                      echo 179000 > dvfs_under_lock
380  *              若要清除之前设置的 dvfs_level_lower_limit, 写入 off 即可.
381  *
382  *      time_in_state
383  *              cat 该节点, 返回 mali_dvfs 停留在不同 level 中的时间统计, 譬如
384  *                      ------------------------------------------------------------------------------
385  *                      index_of_level          gpu_clk_freq (KHz)              time_in_this_level (s)  
386  *                      ------------------------------------------------------------------------------
387  *                      0                       99                              206                     
388  *                      1                       179                             9                       
389  *                      2                       297                             0                       
390  *                      3                       417                             0                       
391  *                      4                       480                             47                      
392  *                      ------------------------------------------------------------------------------
393  *              若通过 dvfs 节点, 开启/关闭 mali_dvfs, 则本节点输出的信息可能不准确.
394  *
395  *              若要复位上述时间统计, 可以向该节点写入任意字串, 比如 : 
396  *                      echo dummy > time_in_state
397  */
398
399 #ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS
400 static ssize_t show_clock(struct device *dev, struct device_attribute *attr, char *buf)
401 {
402         struct kbase_device *kbdev;
403         struct rk_context *platform;
404         ssize_t ret = 0;
405         unsigned int clkrate = 0;       // 从 dvfs_module 获取的 gpu_clk_freq, Hz 为单位.
406         int i ;
407         kbdev = dev_get_drvdata(dev);
408
409         if (!kbdev)
410                 return -ENODEV;
411
412         platform = (struct rk_context *)kbdev->platform_context;
413         if (!platform)
414                 return -ENODEV;
415
416         if (!platform->mali_clk_node)
417         {
418                 printk("mali_clk_node not init\n");
419                 return -ENODEV;
420         }
421         clkrate = dvfs_clk_get_rate(platform->mali_clk_node);
422         ret += snprintf(buf + ret, PAGE_SIZE - ret, "current_gpu_clk_freq : %d KHz", clkrate / 1000);
423         
424         /* To be revised  */
425         ret += snprintf(buf + ret, PAGE_SIZE - ret, "\npossible_freqs : ");
426         for ( i = 0; i < MALI_DVFS_STEP; i++ )
427         {
428                 if ( i < (MALI_DVFS_STEP - 1) )
429                 {
430                         ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d, ", p_mali_dvfs_infotbl[i].clock);
431                 }
432                 else
433                 {
434                         ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d ", p_mali_dvfs_infotbl[i].clock);
435                 }
436         }
437         ret += snprintf(buf + ret, PAGE_SIZE - ret, "(KHz)");
438
439         if (ret < PAGE_SIZE - 1)
440         {
441                 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
442         }
443         else {
444                 buf[PAGE_SIZE - 2] = '\n';
445                 buf[PAGE_SIZE - 1] = '\0';
446                 ret = PAGE_SIZE - 1;
447         }
448
449         return ret;
450 }
451
452 static ssize_t set_clock(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
453 {
454         struct kbase_device *kbdev;
455         struct rk_context *platform;
456         unsigned int tmp = 0, freq = 0;
457         kbdev = dev_get_drvdata(dev);
458         tmp = 0;        
459         if (!kbdev)
460                 return -ENODEV;
461
462         platform = (struct rk_context *)kbdev->platform_context;
463         if (!platform)
464                 return -ENODEV;
465
466         if (!platform->mali_clk_node)
467                 return -ENODEV;
468 #if 0
469         if (sysfs_streq("500", buf)) {
470                 freq = 500;
471         } else if (sysfs_streq("400", buf)) {
472                 freq = 400;
473         } else if (sysfs_streq("350", buf)) {
474                 freq = 350;
475         } else if (sysfs_streq("266", buf)) {
476                 freq = 266;
477         } else if (sysfs_streq("160", buf)) {
478                 freq = 160;
479         } else if (sysfs_streq("100", buf)) {
480                 freq = 100;
481         } else {
482                 dev_err(dev, "set_clock: invalid value\n");
483                 return -ENOENT;
484         }
485 #endif
486         freq = simple_strtoul(buf, NULL, 10);
487         D("freq : %u.", freq);
488
489         kbase_platform_dvfs_set_level(kbdev, kbase_platform_dvfs_get_level(freq));
490         return count;
491 }
492
493 static ssize_t show_fbdev(struct device *dev, struct device_attribute *attr, char *buf)
494 {
495         struct kbase_device *kbdev;
496         ssize_t ret = 0;
497         int i;
498
499         kbdev = dev_get_drvdata(dev);
500
501         if (!kbdev)
502                 return -ENODEV;
503
504         for (i = 0; i < num_registered_fb; i++)
505         {
506                 ret += snprintf(buf + ret, 
507                                 PAGE_SIZE - ret,
508                                 "fb[%d] xres=%d, yres=%d, addr=0x%lx\n",
509                                 i,
510                                 registered_fb[i]->var.xres,
511                                 registered_fb[i]->var.yres,
512                                 registered_fb[i]->fix.smem_start);
513         }
514
515         if (ret < PAGE_SIZE - 1)
516                 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
517         else {
518                 buf[PAGE_SIZE - 2] = '\n';
519                 buf[PAGE_SIZE - 1] = '\0';
520                 ret = PAGE_SIZE - 1;
521         }
522
523         return ret;
524 }
525
526 typedef enum {
527         L1_I_tag_RAM = 0x00,
528         L1_I_data_RAM = 0x01,
529         L1_I_BTB_RAM = 0x02,
530         L1_I_GHB_RAM = 0x03,
531         L1_I_TLB_RAM = 0x04,
532         L1_I_indirect_predictor_RAM = 0x05,
533         L1_D_tag_RAM = 0x08,
534         L1_D_data_RAM = 0x09,
535         L1_D_load_TLB_array = 0x0A,
536         L1_D_store_TLB_array = 0x0B,
537         L2_tag_RAM = 0x10,
538         L2_data_RAM = 0x11,
539         L2_snoop_tag_RAM = 0x12,
540         L2_data_ECC_RAM = 0x13,
541         L2_dirty_RAM = 0x14,
542         L2_TLB_RAM = 0x18
543 } RAMID_type;
544
545 static inline void asm_ramindex_mrc(u32 *DL1Data0, u32 *DL1Data1, u32 *DL1Data2, u32 *DL1Data3)
546 {
547         u32 val;
548
549         if (DL1Data0) {
550                 asm volatile ("mrc p15, 0, %0, c15, c1, 0" : "=r" (val));
551                 *DL1Data0 = val;
552         }
553         if (DL1Data1) {
554                 asm volatile ("mrc p15, 0, %0, c15, c1, 1" : "=r" (val));
555                 *DL1Data1 = val;
556         }
557         if (DL1Data2) {
558                 asm volatile ("mrc p15, 0, %0, c15, c1, 2" : "=r" (val));
559                 *DL1Data2 = val;
560         }
561         if (DL1Data3) {
562                 asm volatile ("mrc p15, 0, %0, c15, c1, 3" : "=r" (val));
563                 *DL1Data3 = val;
564         }
565 }
566
567 static inline void asm_ramindex_mcr(u32 val)
568 {
569         asm volatile ("mcr p15, 0, %0, c15, c4, 0" : : "r" (val));
570         asm volatile ("dsb");
571         asm volatile ("isb");
572 }
573
574 static void get_tlb_array(u32 val, u32 *DL1Data0, u32 *DL1Data1, u32 *DL1Data2, u32 *DL1Data3)
575 {
576         asm_ramindex_mcr(val);
577         asm_ramindex_mrc(DL1Data0, DL1Data1, DL1Data2, DL1Data3);
578 }
579
580 static RAMID_type ramindex = L1_D_load_TLB_array;
581 static ssize_t show_dtlb(struct device *dev, struct device_attribute *attr, char *buf)
582 {
583         struct kbase_device *kbdev;
584         ssize_t ret = 0;
585         int entries, ways;
586         u32 DL1Data0 = 0, DL1Data1 = 0, DL1Data2 = 0, DL1Data3 = 0;
587
588         kbdev = dev_get_drvdata(dev);
589
590         if (!kbdev)
591                 return -ENODEV;
592
593         /* L1-I tag RAM */
594         if (ramindex == L1_I_tag_RAM)
595                 printk(KERN_DEBUG "Not implemented yet\n");
596         /* L1-I data RAM */
597         else if (ramindex == L1_I_data_RAM)
598                 printk(KERN_DEBUG "Not implemented yet\n");
599         /* L1-I BTB RAM */
600         else if (ramindex == L1_I_BTB_RAM)
601                 printk(KERN_DEBUG "Not implemented yet\n");
602         /* L1-I GHB RAM */
603         else if (ramindex == L1_I_GHB_RAM)
604                 printk(KERN_DEBUG "Not implemented yet\n");
605         /* L1-I TLB RAM */
606         else if (ramindex == L1_I_TLB_RAM) {
607                 printk(KERN_DEBUG "L1-I TLB RAM\n");
608                 for (entries = 0; entries < 32; entries++) {
609                         get_tlb_array((((u8) ramindex) << 24) + entries, &DL1Data0, &DL1Data1, &DL1Data2, NULL);
610                         printk(KERN_DEBUG "entries[%d], DL1Data0=%08x, DL1Data1=%08x DL1Data2=%08x\n", entries, DL1Data0, DL1Data1 & 0xffff, 0x0);
611                 }
612         }
613         /* L1-I indirect predictor RAM */
614         else if (ramindex == L1_I_indirect_predictor_RAM)
615                 printk(KERN_DEBUG "Not implemented yet\n");
616         /* L1-D tag RAM */
617         else if (ramindex == L1_D_tag_RAM)
618                 printk(KERN_DEBUG "Not implemented yet\n");
619         /* L1-D data RAM */
620         else if (ramindex == L1_D_data_RAM)
621                 printk(KERN_DEBUG "Not implemented yet\n");
622         /* L1-D load TLB array */
623         else if (ramindex == L1_D_load_TLB_array) {
624                 printk(KERN_DEBUG "L1-D load TLB array\n");
625                 for (entries = 0; entries < 32; entries++) {
626                         get_tlb_array((((u8) ramindex) << 24) + entries, &DL1Data0, &DL1Data1, &DL1Data2, &DL1Data3);
627                         printk(KERN_DEBUG "entries[%d], DL1Data0=%08x, DL1Data1=%08x, DL1Data2=%08x, DL1Data3=%08x\n", entries, DL1Data0, DL1Data1, DL1Data2, DL1Data3 & 0x3f);
628                 }
629         }
630         /* L1-D store TLB array */
631         else if (ramindex == L1_D_store_TLB_array) {
632                 printk(KERN_DEBUG "\nL1-D store TLB array\n");
633                 for (entries = 0; entries < 32; entries++) {
634                         get_tlb_array((((u8) ramindex) << 24) + entries, &DL1Data0, &DL1Data1, &DL1Data2, &DL1Data3);
635                         printk(KERN_DEBUG "entries[%d], DL1Data0=%08x, DL1Data1=%08x, DL1Data2=%08x, DL1Data3=%08x\n", entries, DL1Data0, DL1Data1, DL1Data2, DL1Data3 & 0x3f);
636                 }
637         }
638         /* L2 tag RAM */
639         else if (ramindex == L2_tag_RAM)
640                 printk(KERN_DEBUG "Not implemented yet\n");
641         /* L2 data RAM */
642         else if (ramindex == L2_data_RAM)
643                 printk(KERN_DEBUG "Not implemented yet\n");
644         /* L2 snoop tag RAM */
645         else if (ramindex == L2_snoop_tag_RAM)
646                 printk(KERN_DEBUG "Not implemented yet\n");
647         /* L2 data ECC RAM */
648         else if (ramindex == L2_data_ECC_RAM)
649                 printk(KERN_DEBUG "Not implemented yet\n");
650         /* L2 dirty RAM */
651         else if (ramindex == L2_dirty_RAM)
652                 printk(KERN_DEBUG "Not implemented yet\n");
653
654         /* L2 TLB array */
655         else if (ramindex == L2_TLB_RAM) {
656                 printk(KERN_DEBUG "\nL2 TLB array\n");
657                 for (ways = 0; ways < 4; ways++) {
658                         for (entries = 0; entries < 512; entries++) {
659                                 get_tlb_array((ramindex << 24) + (ways << 18) + entries, &DL1Data0, &DL1Data1, &DL1Data2, &DL1Data3);
660                                 printk(KERN_DEBUG "ways[%d]:entries[%d], DL1Data0=%08x, DL1Data1=%08x, DL1Data2=%08x, DL1Data3=%08x\n", ways, entries, DL1Data0, DL1Data1, DL1Data2, DL1Data3);
661                         }
662                 }
663         } else {
664         }
665
666         ret += snprintf(buf + ret, PAGE_SIZE - ret, "Succeeded...\n");
667
668         if (ret < PAGE_SIZE - 1)
669                 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
670         else {
671                 buf[PAGE_SIZE - 2] = '\n';
672                 buf[PAGE_SIZE - 1] = '\0';
673                 ret = PAGE_SIZE - 1;
674         }
675         return ret;
676 }
677
678 static ssize_t set_dtlb(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
679 {
680         struct kbase_device *kbdev;
681         kbdev = dev_get_drvdata(dev);
682
683         if (!kbdev)
684                 return -ENODEV;
685
686         if (sysfs_streq("L1_I_tag_RAM", buf)) {
687                 ramindex = L1_I_tag_RAM;
688         } else if (sysfs_streq("L1_I_data_RAM", buf)) {
689                 ramindex = L1_I_data_RAM;
690         } else if (sysfs_streq("L1_I_BTB_RAM", buf)) {
691                 ramindex = L1_I_BTB_RAM;
692         } else if (sysfs_streq("L1_I_GHB_RAM", buf)) {
693                 ramindex = L1_I_GHB_RAM;
694         } else if (sysfs_streq("L1_I_TLB_RAM", buf)) {
695                 ramindex = L1_I_TLB_RAM;
696         } else if (sysfs_streq("L1_I_indirect_predictor_RAM", buf)) {
697                 ramindex = L1_I_indirect_predictor_RAM;
698         } else if (sysfs_streq("L1_D_tag_RAM", buf)) {
699                 ramindex = L1_D_tag_RAM;
700         } else if (sysfs_streq("L1_D_data_RAM", buf)) {
701                 ramindex = L1_D_data_RAM;
702         } else if (sysfs_streq("L1_D_load_TLB_array", buf)) {
703                 ramindex = L1_D_load_TLB_array;
704         } else if (sysfs_streq("L1_D_store_TLB_array", buf)) {
705                 ramindex = L1_D_store_TLB_array;
706         } else if (sysfs_streq("L2_tag_RAM", buf)) {
707                 ramindex = L2_tag_RAM;
708         } else if (sysfs_streq("L2_data_RAM", buf)) {
709                 ramindex = L2_data_RAM;
710         } else if (sysfs_streq("L2_snoop_tag_RAM", buf)) {
711                 ramindex = L2_snoop_tag_RAM;
712         } else if (sysfs_streq("L2_data_ECC_RAM", buf)) {
713                 ramindex = L2_data_ECC_RAM;
714         } else if (sysfs_streq("L2_dirty_RAM", buf)) {
715                 ramindex = L2_dirty_RAM;
716         } else if (sysfs_streq("L2_TLB_RAM", buf)) {
717                 ramindex = L2_TLB_RAM;
718         } else {
719                 printk(KERN_DEBUG "Invalid value....\n\n");
720                 printk(KERN_DEBUG "Available options are one of below\n");
721                 printk(KERN_DEBUG "L1_I_tag_RAM, L1_I_data_RAM, L1_I_BTB_RAM\n");
722                 printk(KERN_DEBUG "L1_I_GHB_RAM, L1_I_TLB_RAM, L1_I_indirect_predictor_RAM\n");
723                 printk(KERN_DEBUG "L1_D_tag_RAM, L1_D_data_RAM, L1_D_load_TLB_array, L1_D_store_TLB_array\n");
724                 printk(KERN_DEBUG "L2_tag_RAM, L2_data_RAM, L2_snoop_tag_RAM, L2_data_ECC_RAM\n");
725                 printk(KERN_DEBUG "L2_dirty_RAM, L2_TLB_RAM\n");
726         }
727
728         return count;
729 }
730
731 static ssize_t show_dvfs(struct device *dev, struct device_attribute *attr, char *buf)
732 {
733         struct kbase_device *kbdev;
734         struct rk_context *platform;
735         ssize_t ret = 0;
736         unsigned int clkrate;
737
738         kbdev = dev_get_drvdata(dev);
739
740         if (!kbdev)
741                 return -ENODEV;
742         
743         platform = (struct rk_context *)kbdev->platform_context;
744         if (!platform)
745                 return -ENODEV;
746
747         /* 获取当前 gpu_dvfs_node 的 clk_freq, Hz 为单位. */
748         clkrate = dvfs_clk_get_rate(platform->mali_clk_node);
749
750 #ifdef CONFIG_MALI_MIDGARD_DVFS
751         /* 若 mali_dvfs 是 开启的, 则... */
752         if (kbase_platform_dvfs_get_enable_status())
753         {
754                 ret += snprintf(buf + ret,
755                                 PAGE_SIZE - ret,
756                                 "mali_dvfs is ON \ngpu_utilisation : %d \ncurrent_gpu_clk_freq : %u MHz",
757                                 kbase_platform_dvfs_get_utilisation(),
758                                 clkrate / 1000000);
759         }
760         /* 否则, ... */
761         else
762         {
763                 ret += snprintf(buf + ret,
764                                 PAGE_SIZE - ret,
765                                 "mali_dvfs is OFF \ncurrent_gpu_clk_freq : %u MHz",
766                                 clkrate / 1000000);
767         }
768 #else
769         ret += snprintf(buf + ret, PAGE_SIZE - ret, "mali_dvfs is DISABLED");
770 #endif
771
772         if (ret < PAGE_SIZE - 1)
773                 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
774         else {
775                 buf[PAGE_SIZE - 2] = '\n';
776                 buf[PAGE_SIZE - 1] = '\0';
777                 ret = PAGE_SIZE - 1;
778         }
779
780         return ret;
781 }
782
783 static ssize_t set_dvfs(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
784 {
785         struct kbase_device *kbdev = dev_get_drvdata(dev);
786 #ifdef CONFIG_MALI_MIDGARD_DVFS
787         struct rk_context *platform;
788 #endif
789
790         if (!kbdev)
791                 return -ENODEV;
792
793 #ifdef CONFIG_MALI_MIDGARD_DVFS
794         platform = (struct rk_context *)kbdev->platform_context;
795         if (sysfs_streq("off", buf)) {
796                 /*kbase_platform_dvfs_enable(false, MALI_DVFS_BL_CONFIG_FREQ);*/
797                 D("to disable mali_dvfs, and set current_dvfs_level to the highest one.");
798                 kbase_platform_dvfs_enable(false, p_mali_dvfs_infotbl[MALI_DVFS_STEP-1].clock); 
799                 platform->dvfs_enabled = false;
800         } else if (sysfs_streq("on", buf)) {
801                 /*kbase_platform_dvfs_enable(true, MALI_DVFS_START_FREQ);*/
802                 D("to disable mali_dvfs, and set current_dvfs_level to the lowest one.");
803                 kbase_platform_dvfs_enable(true, p_mali_dvfs_infotbl[0].clock);
804                 platform->dvfs_enabled = true;
805         } else {
806                 printk(KERN_DEBUG "invalid val -only [on, off] is accepted\n");
807         }
808 #else
809         printk(KERN_DEBUG "mali  DVFS is disabled\n");
810 #endif
811         return count;
812 }
813
814 static ssize_t show_upper_lock_dvfs(struct device *dev, struct device_attribute *attr, char *buf)
815 {
816         struct kbase_device *kbdev;
817         ssize_t ret = 0;
818         int i;
819 #ifdef CONFIG_MALI_MIDGARD_DVFS
820         int gpu_clk_freq = 0;
821 #endif
822
823         kbdev = dev_get_drvdata(dev);
824
825         if (!kbdev)
826         {
827                 E("err.");
828                 return -ENODEV;
829         }
830
831 #ifdef CONFIG_MALI_MIDGARD_DVFS
832         gpu_clk_freq = mali_get_dvfs_upper_locked_freq();
833         if (gpu_clk_freq > 0)
834         {
835                 ret += snprintf(buf + ret, PAGE_SIZE - ret, "upper_lock_freq : %d KHz", gpu_clk_freq);
836         }
837         else
838         {
839                 ret += snprintf(buf + ret, PAGE_SIZE - ret, "upper_lock_freq is NOT set");
840         }
841         /*ret += snprintf(buf + ret, PAGE_SIZE - ret, "\nPossible settings : 400, 350,266, 160, 100, If you want to unlock : 600 or off");*/
842
843         ret += snprintf(buf + ret, PAGE_SIZE - ret, "\npossible upper_lock_freqs : ");
844         for ( i = 0; i < MALI_DVFS_STEP; i++ )
845         {
846                 if ( i < (MALI_DVFS_STEP - 1) )
847                 {
848                         ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d, ", p_mali_dvfs_infotbl[i].clock);
849                 }
850                 else
851                 {
852                         ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d ", p_mali_dvfs_infotbl[i].clock);
853                 }
854         }
855         ret += snprintf(buf + ret, PAGE_SIZE - ret, "(KHz)");
856         
857         if ( gpu_clk_freq > 0 )
858         {
859                 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\nif you want to unset upper_lock_freq, to echo 'off' to this file.");
860         }
861 #else
862         ret += snprintf(buf + ret, PAGE_SIZE - ret, "mali DVFS is disabled. You can not set");
863 #endif
864
865         if (ret < PAGE_SIZE - 1)
866                 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
867         else {
868                 buf[PAGE_SIZE - 2] = '\n';
869                 buf[PAGE_SIZE - 1] = '\0';
870                 ret = PAGE_SIZE - 1;
871         }
872
873         return ret;
874 }
875
876 static ssize_t set_upper_lock_dvfs(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
877 {
878         struct kbase_device *kbdev = NULL;
879         int i;
880         unsigned int freq = 0;              // 可能由 caller 传入的, 待设置的 gpu_freq_upper_limit.
881         int ret = 0;
882
883         kbdev = dev_get_drvdata(dev);
884
885         if ( NULL == kbdev)
886         {
887                 E("'kbdev' is NULL.");
888                 return -ENODEV;
889         }
890
891 #ifdef CONFIG_MALI_MIDGARD_DVFS
892         if (sysfs_streq("off", buf)) 
893         {
894                 mali_dvfs_freq_unlock();
895         } 
896         else 
897         {
898                 freq = simple_strtoul(buf, NULL, 10);
899                 D_DEC(freq);
900
901                 D("to search the level that matches target_freq; num_of_mali_dvfs_levels : %d.", MALI_DVFS_STEP);
902                 for(i=0;i<MALI_DVFS_STEP;i++)
903                 {
904                         D("p_mali_dvfs_infotbl[%d].clock : %d", i, p_mali_dvfs_infotbl[i].clock);
905                         if (p_mali_dvfs_infotbl[i].clock == freq) 
906                         {
907                                 D("target_freq is acceptable in level '%d', to set '%d' as index of dvfs_level_upper_limit.", i, i);
908                                 ret = mali_dvfs_freq_lock(i);
909                                 if ( 0 != ret )
910                                 {
911                                         E("fail to set dvfs_level_upper_limit, ret : %d.", ret);
912                                         return -EINVAL;
913                                 }
914                                 break;
915                         }
916                 }
917                 /* 若 "没有" 找到和 target_freq match 的 level, 则... */
918                 if ( MALI_DVFS_STEP == i )
919                 {
920                         // dev_err(dev, "set_clock: invalid value\n");
921                         E("invalid target_freq : %d", freq);
922                         return -ENOENT;
923                 }
924         }
925         
926 #else                           /* CONFIG_MALI_MIDGARD_DVFS */
927         printk(KERN_DEBUG "mali DVFS is disabled. You can not set\n");
928 #endif
929
930         return count;
931 }
932
933 static ssize_t show_under_lock_dvfs(struct device *dev, struct device_attribute *attr, char *buf)
934 {
935         struct kbase_device *kbdev;
936         ssize_t ret = 0;
937         int i;
938 #ifdef CONFIG_MALI_MIDGARD_DVFS
939         int gpu_clk_freq = 0;
940 #endif
941
942         kbdev = dev_get_drvdata(dev);
943
944         if (!kbdev)
945                 return -ENODEV;
946
947 #ifdef CONFIG_MALI_MIDGARD_DVFS
948         gpu_clk_freq = mali_get_dvfs_under_locked_freq();
949         if (gpu_clk_freq > 0)
950         {
951                 ret += snprintf(buf + ret, PAGE_SIZE - ret, "under_lock_freq : %d KHz",gpu_clk_freq);
952         }
953         else
954         {
955                 ret += snprintf(buf + ret, PAGE_SIZE - ret, "under_lock_freq is NOT set.");
956         }
957         /*ret += snprintf(buf + ret, PAGE_SIZE - ret, "\nPossible settings : 600, 400, 350,266, 160, If you want to unlock : 100 or off");*/
958         ret += snprintf(buf + ret, PAGE_SIZE - ret, "\npossible under_lock_freqs : ");
959         for ( i = 0; i < MALI_DVFS_STEP; i++ )
960         {
961                 if ( i < (MALI_DVFS_STEP - 1) )
962                 {
963                         ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d, ", p_mali_dvfs_infotbl[i].clock);
964                 }
965                 else
966                 {
967                         ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d ", p_mali_dvfs_infotbl[i].clock);
968                 }
969         }
970         ret += snprintf(buf + ret, PAGE_SIZE - ret, "(KHz)");
971
972         if ( gpu_clk_freq > 0 )
973         {
974                 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\nif you want to unset under_lock_freq, to echo 'off' to this file.");
975         }
976 #else
977         ret += snprintf(buf + ret, PAGE_SIZE - ret, "mali DVFS is disabled. You can not set");
978 #endif
979
980         if (ret < PAGE_SIZE - 1)
981                 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
982         else {
983                 buf[PAGE_SIZE - 2] = '\n';
984                 buf[PAGE_SIZE - 1] = '\0';
985                 ret = PAGE_SIZE - 1;
986         }
987
988         return ret;
989 }
990
991 static ssize_t set_under_lock_dvfs(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
992 {
993         int i;
994         unsigned int freq = 0;
995         struct kbase_device *kbdev = NULL;
996         int ret = 0;
997
998         kbdev = dev_get_drvdata(dev);
999         if ( NULL == kbdev)
1000         {
1001                 E("err.")
1002                 return -ENODEV;
1003         }
1004
1005 #ifdef CONFIG_MALI_MIDGARD_DVFS
1006         if (sysfs_streq("off", buf)) 
1007         {
1008                 mali_dvfs_freq_under_unlock();
1009         } 
1010         else 
1011         {
1012                 freq = simple_strtoul(buf, NULL, 10);
1013                 D_DEC(freq);
1014
1015                 for(i=0;i<MALI_DVFS_STEP;i++)
1016                 {
1017                         if (p_mali_dvfs_infotbl[i].clock == freq) 
1018                         {
1019                                 D("to set '%d' as the index of dvfs_level_lower_limit", i);
1020                                 ret = mali_dvfs_freq_under_lock(i);
1021                                 if ( 0 != ret )
1022                                 {
1023                                         E("fail to set dvfs_level_lower_limit, ret : %d.", ret);
1024                                         return -EINVAL;
1025                                 }
1026                                 break;
1027                         }
1028                 }
1029                 /* 若 "没有" 找到和 target_freq match 的 level, 则... */
1030                 if( i == MALI_DVFS_STEP )
1031                 {
1032                         dev_err(dev, "set_clock: invalid value\n");
1033                         return -ENOENT;
1034                 }
1035         }
1036
1037 #else                           /* CONFIG_MALI_MIDGARD_DVFS */
1038         printk(KERN_DEBUG "mali DVFS is disabled. You can not set\n");
1039 #endif
1040         return count;
1041 }
1042
1043 /** The sysfs file @c clock, fbdev.
1044  *
1045  * This is used for obtaining information about the mali t6xx operating clock & framebuffer address,
1046  */
1047 static DEVICE_ATTR(clock, S_IRUGO | S_IWUSR, show_clock, set_clock);
1048 static DEVICE_ATTR(fbdev, S_IRUGO, show_fbdev, NULL);
1049 static DEVICE_ATTR(dtlb, S_IRUGO | S_IWUSR, show_dtlb, set_dtlb);
1050 static DEVICE_ATTR(dvfs, S_IRUGO | S_IWUSR, show_dvfs, set_dvfs);
1051 static DEVICE_ATTR(dvfs_upper_lock, S_IRUGO | S_IWUSR, show_upper_lock_dvfs, set_upper_lock_dvfs);
1052 static DEVICE_ATTR(dvfs_under_lock, S_IRUGO | S_IWUSR, show_under_lock_dvfs, set_under_lock_dvfs);
1053 static DEVICE_ATTR(time_in_state, S_IRUGO | S_IWUSR, show_time_in_state, set_time_in_state);
1054 /*---------------------------------------------------------------------------*/
1055
1056 int kbase_platform_create_sysfs_file(struct device *dev)
1057 {
1058         if (device_create_file(dev, &dev_attr_clock)) {
1059                 dev_err(dev, "Couldn't create sysfs file [clock]\n");
1060                 goto out;
1061         }
1062
1063         if (device_create_file(dev, &dev_attr_fbdev)) {
1064                 dev_err(dev, "Couldn't create sysfs file [fbdev]\n");
1065                 goto out;
1066         }
1067
1068         /*  rk_ext : device will crash after "cat /sys/devices/ffa30000.gpu/dtlb".
1069         if (device_create_file(dev, &dev_attr_dtlb)) {
1070                 dev_err(dev, "Couldn't create sysfs file [dtlb]\n");
1071                 goto out;
1072         }
1073         */
1074
1075         if (device_create_file(dev, &dev_attr_dvfs)) {
1076                 dev_err(dev, "Couldn't create sysfs file [dvfs]\n");
1077                 goto out;
1078         }
1079
1080         if (device_create_file(dev, &dev_attr_dvfs_upper_lock)) {
1081                 dev_err(dev, "Couldn't create sysfs file [dvfs_upper_lock]\n");
1082                 goto out;
1083         }
1084
1085         if (device_create_file(dev, &dev_attr_dvfs_under_lock)) {
1086                 dev_err(dev, "Couldn't create sysfs file [dvfs_under_lock]\n");
1087                 goto out;
1088         }
1089
1090         if (device_create_file(dev, &dev_attr_time_in_state)) {
1091                 dev_err(dev, "Couldn't create sysfs file [time_in_state]\n");
1092                 goto out;
1093         }
1094         return 0;
1095
1096  out:
1097         return -ENOENT;
1098 }
1099
1100 void kbase_platform_remove_sysfs_file(struct device *dev)
1101 {
1102         device_remove_file(dev, &dev_attr_clock);
1103         device_remove_file(dev, &dev_attr_fbdev);
1104         device_remove_file(dev, &dev_attr_dtlb);
1105         device_remove_file(dev, &dev_attr_dvfs);
1106         device_remove_file(dev, &dev_attr_dvfs_upper_lock);
1107         device_remove_file(dev, &dev_attr_dvfs_under_lock);
1108         device_remove_file(dev, &dev_attr_time_in_state);
1109 }
1110 #endif                          /* CONFIG_MALI_MIDGARD_DEBUG_SYS */
1111
1112 mali_error kbase_platform_init(struct kbase_device *kbdev)
1113 {
1114         struct rk_context *platform;
1115         int ret;
1116
1117         platform = kmalloc(sizeof(struct rk_context), GFP_KERNEL);
1118
1119         if (NULL == platform)
1120                 return MALI_ERROR_OUT_OF_MEMORY;
1121
1122         /* .KP : 将 'rk_context' 关联到 mali_device. */
1123         kbdev->platform_context = (void *)platform;
1124
1125         platform->cmu_pmu_status = 0;
1126 #ifdef CONFIG_MALI_MIDGARD_DVFS
1127         platform->utilisation = 0;
1128         platform->time_busy = 0;
1129         platform->time_idle = 0;
1130         platform->time_tick = 0;
1131         platform->dvfs_enabled = true;
1132 #endif
1133
1134         rk_gpu = kobject_create_and_add("rk_gpu", NULL);
1135         if (!rk_gpu)
1136                 return MALI_ERROR_FUNCTION_FAILED;
1137
1138         ret = sysfs_create_file(rk_gpu, &dev_attr_error_count.attr);
1139         if(ret)
1140                 return MALI_ERROR_FUNCTION_FAILED;
1141
1142         spin_lock_init(&platform->cmu_pmu_lock);
1143
1144         if (kbase_platform_power_clock_init(kbdev))
1145                 goto clock_init_fail;
1146
1147 #ifdef CONFIG_MALI_MIDGARD_DVFS
1148         kbase_platform_dvfs_init(kbdev);
1149 #endif                          /* CONFIG_MALI_MIDGARD_DVFS */
1150
1151         /* Enable power */
1152         kbase_platform_cmu_pmu_control(kbdev, 1);
1153         return MALI_ERROR_NONE;
1154
1155  clock_init_fail:
1156         kfree(platform);
1157
1158         return MALI_ERROR_FUNCTION_FAILED;
1159 }
1160
1161 void kbase_platform_term(struct kbase_device *kbdev)
1162 {
1163         struct rk_context *platform;
1164
1165         platform = (struct rk_context *)kbdev->platform_context;
1166
1167 #ifdef CONFIG_MALI_MIDGARD_DVFS
1168         kbase_platform_dvfs_term();
1169 #endif                          /* CONFIG_MALI_MIDGARD_DVFS */
1170
1171         /* Disable power */
1172         kbase_platform_cmu_pmu_control(kbdev, 0);
1173         kfree(kbdev->platform_context);
1174         kbdev->platform_context = 0;
1175         return;
1176 }