1 /* drivers/gpu/t6xx/kbase/src/platform/rk/mali_kbase_platform.c
3 * Rockchip SoC Mali-T764 platform-dependent codes
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.
11 * @file mali_kbase_platform.c
13 * 对 mali_kbase_platform.h 声明的 pm, clk 等接口的具体实现.
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>
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>
34 #include <linux/uaccess.h>
35 #include <linux/interrupt.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>
44 #include <mali_kbase_gator.h>
46 #include <linux/rockchip/dvfs.h>
48 // #define ENABLE_DEBUG_LOG
49 #include "custom_log.h"
51 /* ############################################################################################# */
53 #define MALI_T7XX_DEFAULT_CLOCK 100000
57 * clk_of_gpu_dvfs_node 的状态.
61 static int mali_clk_status = 0;
64 * gpu_power_domain 的状态.
68 static int mali_pd_status = 0;
70 // u32 kbase_group_error = 0;
71 static struct kobject *rk_gpu;
73 int mali_dvfs_clk_set(struct dvfs_node *node, unsigned long rate)
78 printk("clk_get_dvfs_node error \r\n");
81 /* .KP : 调用 dvfs_module 设置 gpu_clk. */
82 ret = dvfs_clk_set_rate(node,rate * MALI_KHZ);
85 printk("dvfs_clk_set_rate error \r\n");
91 * 初始化和 gpu_pm 和 gpu_clk.
93 static int kbase_platform_power_clock_init(struct kbase_device *kbdev)
95 /*struct device *dev = kbdev->dev;*/
96 struct rk_context *platform;
98 platform = (struct rk_context *)kbdev->platform_context;
102 /* enable mali t760 powerdomain*/
103 platform->mali_pd = clk_get(NULL,"pd_gpu");
104 if(IS_ERR_OR_NULL(platform->mali_pd))
106 platform->mali_pd = NULL;
107 printk(KERN_ERR "%s, %s(): failed to get [platform->mali_pd]\n", __FILE__, __func__);
112 clk_prepare_enable(platform->mali_pd);
113 printk("mali pd enabled\n");
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))
121 platform->mali_clk_node = NULL;
122 printk(KERN_ERR "%s, %s(): failed to get [platform->mali_clk_node]\n", __FILE__, __func__);
127 dvfs_clk_prepare_enable(platform->mali_clk_node);
128 printk("clk enabled\n");
130 mali_dvfs_clk_set(platform->mali_clk_node, MALI_T7XX_DEFAULT_CLOCK);
136 if(platform->mali_pd)
137 clk_put(platform->mali_pd);
143 int kbase_platform_clock_off(struct kbase_device *kbdev)
145 struct rk_context *platform;
149 platform = (struct rk_context *)kbdev->platform_context;
153 if (mali_clk_status == 0)
156 if((platform->mali_clk_node))
157 dvfs_clk_disable_unprepare(platform->mali_clk_node);
164 int kbase_platform_clock_on(struct kbase_device *kbdev)
166 struct rk_context *platform;
170 platform = (struct rk_context *)kbdev->platform_context;
174 if (mali_clk_status == 1)
177 if(platform->mali_clk_node)
178 dvfs_clk_prepare_enable(platform->mali_clk_node);
185 int kbase_platform_is_power_on(void)
187 return mali_pd_status;
190 /*turn on power domain*/
191 int kbase_platform_power_on(struct kbase_device *kbdev)
193 struct rk_context *platform;
197 platform = (struct rk_context *)kbdev->platform_context;
201 if (mali_pd_status == 1)
204 if(platform->mali_pd)
205 clk_prepare_enable(platform->mali_pd);
208 KBASE_TIMELINE_GPU_POWER(kbdev, 1);
213 /*turn off power domain*/
214 int kbase_platform_power_off(struct kbase_device *kbdev)
216 struct rk_context *platform;
220 platform = (struct rk_context *)kbdev->platform_context;
224 if (mali_pd_status== 0)
227 if(platform->mali_pd)
228 clk_disable_unprepare(platform->mali_pd);
231 KBASE_TIMELINE_GPU_POWER(kbdev, 0);
237 int kbase_platform_cmu_pmu_control(struct kbase_device *kbdev, int control)
240 struct rk_context *platform;
244 platform = (struct rk_context *)kbdev->platform_context;
248 spin_lock_irqsave(&platform->cmu_pmu_lock, flags);
254 if (platform->cmu_pmu_status == 0)
256 spin_unlock_irqrestore(&platform->cmu_pmu_lock, flags);
260 /* 关闭 gpu_power_domain. */
261 if (kbase_platform_power_off(kbdev))
263 panic("failed to turn off mali power domain\n");
265 /* 关闭 gpu_dvfs_node 的 clock. */
266 if (kbase_platform_clock_off(kbdev))
268 panic("failed to turn off mali clock\n");
271 platform->cmu_pmu_status = 0;
272 printk("turn off mali power \n");
276 if (platform->cmu_pmu_status == 1)
278 spin_unlock_irqrestore(&platform->cmu_pmu_lock, flags);
282 /* 开启 gpu_power_domain. */
283 if (kbase_platform_power_on(kbdev))
285 panic("failed to turn on mali power domain\n");
287 /* 使能 gpu_dvfs_node 的 clock. */
288 if (kbase_platform_clock_on(kbdev))
290 panic("failed to turn on mali clock\n");
293 platform->cmu_pmu_status = 1;
294 printk(KERN_ERR "turn on mali power\n");
297 spin_unlock_irqrestore(&platform->cmu_pmu_lock, flags);
302 /*---------------------------------------------------------------------------*/
304 static ssize_t error_count_show(struct device *dev,struct device_attribute *attr, char *buf)
306 struct kbase_device *kbdev = dev_get_drvdata(dev);
312 E("fail to get kbase_device instance.");
316 D_DEC(kbdev->kbase_group_error);
317 ret = scnprintf(buf, PAGE_SIZE, "%u\n", kbdev->kbase_group_error);
320 static DEVICE_ATTR(error_count, S_IRUGO, error_count_show, NULL);
323 /*---------------------------------------------------------------------------*/
324 /* < 对在 sysfs_dir_of_mali_device 下的 rk_ext_file_nodes 的具体实现, >*/
325 // .DP : impl_of_rk_ext_file_nodes.
328 * .doc : 对 sysfs_dir_of_mali_device 下 rk_ext_file_nodes 提供的接口的定义
330 * sysfs_dir_of_mali_device 通常是 sys/devices/ffa30000.gpu
332 * 其下有如下的 rk_ext_file_nodes :
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 先 :
346 * .R : 目前不确定该提供接口的用意.
349 * cat 该节点, 将返回当前 mali_dvfs 的状态, 包括 mali_dvfs 是否开启, gpu 使用率, 当前 gpu_clk 频率.
350 * 若当前 mali_dvfs 被开启, 可能返回如下信息 :
352 * gpu_utilisation : 100
353 * current_gpu_clk_freq : 480 MHz
354 * 若当前 mali_dvfs 被关闭, 可能返回 :
356 * current_gpu_clk_freq : 99 MHz
357 * 若一段时间没有 job 下发到 gpu, common_parts 也会自动关闭 mali_dvfs.
359 * 将字串 off 写入该节点, 将关闭 mali_dvfs,
360 * 且会将 gpu_clk_freq 固定到可能的最高的频率 或者 gpu_clk_freq_of_upper_limit(若有指定).
361 * 之后, 若将字串 on 写入该节点, 将重新开启 mali_dvfs.
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.
369 * 对该节点写入上面 possible upper_lock_freqs 中的某个 频率, 可以将该频率设置为 gpu_clk_freq_of_upper_limit, 比如.
370 * echo 417000 > dvfs_upper_lock
371 * 若要清除之前设置的 dvfs_level_upper_limit, 写入 off 即可.
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 即可.
383 * cat 该节点, 返回 mali_dvfs 停留在不同 level 中的时间统计, 譬如
384 * ------------------------------------------------------------------------------
385 * index_of_level gpu_clk_freq (KHz) time_in_this_level (s)
386 * ------------------------------------------------------------------------------
392 * ------------------------------------------------------------------------------
393 * 若通过 dvfs 节点, 开启/关闭 mali_dvfs, 则本节点输出的信息可能不准确.
395 * 若要复位上述时间统计, 可以向该节点写入任意字串, 比如 :
396 * echo dummy > time_in_state
399 #ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS
400 static ssize_t show_clock(struct device *dev, struct device_attribute *attr, char *buf)
402 struct kbase_device *kbdev;
403 struct rk_context *platform;
405 unsigned int clkrate = 0; // 从 dvfs_module 获取的 gpu_clk_freq, Hz 为单位.
407 kbdev = dev_get_drvdata(dev);
412 platform = (struct rk_context *)kbdev->platform_context;
416 if (!platform->mali_clk_node)
418 printk("mali_clk_node not init\n");
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);
425 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\npossible_freqs : ");
426 for ( i = 0; i < MALI_DVFS_STEP; i++ )
428 if ( i < (MALI_DVFS_STEP - 1) )
430 ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d, ", p_mali_dvfs_infotbl[i].clock);
434 ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d ", p_mali_dvfs_infotbl[i].clock);
437 ret += snprintf(buf + ret, PAGE_SIZE - ret, "(KHz)");
439 if (ret < PAGE_SIZE - 1)
441 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
444 buf[PAGE_SIZE - 2] = '\n';
445 buf[PAGE_SIZE - 1] = '\0';
452 static ssize_t set_clock(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
454 struct kbase_device *kbdev;
455 struct rk_context *platform;
456 unsigned int tmp = 0, freq = 0;
457 kbdev = dev_get_drvdata(dev);
462 platform = (struct rk_context *)kbdev->platform_context;
466 if (!platform->mali_clk_node)
469 if (sysfs_streq("500", buf)) {
471 } else if (sysfs_streq("400", buf)) {
473 } else if (sysfs_streq("350", buf)) {
475 } else if (sysfs_streq("266", buf)) {
477 } else if (sysfs_streq("160", buf)) {
479 } else if (sysfs_streq("100", buf)) {
482 dev_err(dev, "set_clock: invalid value\n");
486 freq = simple_strtoul(buf, NULL, 10);
487 D("freq : %u.", freq);
489 kbase_platform_dvfs_set_level(kbdev, kbase_platform_dvfs_get_level(freq));
493 static ssize_t show_fbdev(struct device *dev, struct device_attribute *attr, char *buf)
495 struct kbase_device *kbdev;
499 kbdev = dev_get_drvdata(dev);
504 for (i = 0; i < num_registered_fb; i++)
506 ret += snprintf(buf + ret,
508 "fb[%d] xres=%d, yres=%d, addr=0x%lx\n",
510 registered_fb[i]->var.xres,
511 registered_fb[i]->var.yres,
512 registered_fb[i]->fix.smem_start);
515 if (ret < PAGE_SIZE - 1)
516 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
518 buf[PAGE_SIZE - 2] = '\n';
519 buf[PAGE_SIZE - 1] = '\0';
528 L1_I_data_RAM = 0x01,
532 L1_I_indirect_predictor_RAM = 0x05,
534 L1_D_data_RAM = 0x09,
535 L1_D_load_TLB_array = 0x0A,
536 L1_D_store_TLB_array = 0x0B,
539 L2_snoop_tag_RAM = 0x12,
540 L2_data_ECC_RAM = 0x13,
545 static inline void asm_ramindex_mrc(u32 *DL1Data0, u32 *DL1Data1, u32 *DL1Data2, u32 *DL1Data3)
550 asm volatile ("mrc p15, 0, %0, c15, c1, 0" : "=r" (val));
554 asm volatile ("mrc p15, 0, %0, c15, c1, 1" : "=r" (val));
558 asm volatile ("mrc p15, 0, %0, c15, c1, 2" : "=r" (val));
562 asm volatile ("mrc p15, 0, %0, c15, c1, 3" : "=r" (val));
567 static inline void asm_ramindex_mcr(u32 val)
569 asm volatile ("mcr p15, 0, %0, c15, c4, 0" : : "r" (val));
570 asm volatile ("dsb");
571 asm volatile ("isb");
574 static void get_tlb_array(u32 val, u32 *DL1Data0, u32 *DL1Data1, u32 *DL1Data2, u32 *DL1Data3)
576 asm_ramindex_mcr(val);
577 asm_ramindex_mrc(DL1Data0, DL1Data1, DL1Data2, DL1Data3);
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)
583 struct kbase_device *kbdev;
586 u32 DL1Data0 = 0, DL1Data1 = 0, DL1Data2 = 0, DL1Data3 = 0;
588 kbdev = dev_get_drvdata(dev);
594 if (ramindex == L1_I_tag_RAM)
595 printk(KERN_DEBUG "Not implemented yet\n");
597 else if (ramindex == L1_I_data_RAM)
598 printk(KERN_DEBUG "Not implemented yet\n");
600 else if (ramindex == L1_I_BTB_RAM)
601 printk(KERN_DEBUG "Not implemented yet\n");
603 else if (ramindex == L1_I_GHB_RAM)
604 printk(KERN_DEBUG "Not implemented yet\n");
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);
613 /* L1-I indirect predictor RAM */
614 else if (ramindex == L1_I_indirect_predictor_RAM)
615 printk(KERN_DEBUG "Not implemented yet\n");
617 else if (ramindex == L1_D_tag_RAM)
618 printk(KERN_DEBUG "Not implemented yet\n");
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);
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);
639 else if (ramindex == L2_tag_RAM)
640 printk(KERN_DEBUG "Not implemented yet\n");
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");
651 else if (ramindex == L2_dirty_RAM)
652 printk(KERN_DEBUG "Not implemented yet\n");
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);
666 ret += snprintf(buf + ret, PAGE_SIZE - ret, "Succeeded...\n");
668 if (ret < PAGE_SIZE - 1)
669 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
671 buf[PAGE_SIZE - 2] = '\n';
672 buf[PAGE_SIZE - 1] = '\0';
678 static ssize_t set_dtlb(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
680 struct kbase_device *kbdev;
681 kbdev = dev_get_drvdata(dev);
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;
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");
731 static ssize_t show_dvfs(struct device *dev, struct device_attribute *attr, char *buf)
733 struct kbase_device *kbdev;
734 struct rk_context *platform;
736 unsigned int clkrate;
738 kbdev = dev_get_drvdata(dev);
743 platform = (struct rk_context *)kbdev->platform_context;
747 /* 获取当前 gpu_dvfs_node 的 clk_freq, Hz 为单位. */
748 clkrate = dvfs_clk_get_rate(platform->mali_clk_node);
750 #ifdef CONFIG_MALI_MIDGARD_DVFS
751 /* 若 mali_dvfs 是 开启的, 则... */
752 if (kbase_platform_dvfs_get_enable_status())
754 ret += snprintf(buf + ret,
756 "mali_dvfs is ON \ngpu_utilisation : %d \ncurrent_gpu_clk_freq : %u MHz",
757 kbase_platform_dvfs_get_utilisation(),
763 ret += snprintf(buf + ret,
765 "mali_dvfs is OFF \ncurrent_gpu_clk_freq : %u MHz",
769 ret += snprintf(buf + ret, PAGE_SIZE - ret, "mali_dvfs is DISABLED");
772 if (ret < PAGE_SIZE - 1)
773 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
775 buf[PAGE_SIZE - 2] = '\n';
776 buf[PAGE_SIZE - 1] = '\0';
783 static ssize_t set_dvfs(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
785 struct kbase_device *kbdev = dev_get_drvdata(dev);
786 #ifdef CONFIG_MALI_MIDGARD_DVFS
787 struct rk_context *platform;
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;
806 printk(KERN_DEBUG "invalid val -only [on, off] is accepted\n");
809 printk(KERN_DEBUG "mali DVFS is disabled\n");
814 static ssize_t show_upper_lock_dvfs(struct device *dev, struct device_attribute *attr, char *buf)
816 struct kbase_device *kbdev;
819 #ifdef CONFIG_MALI_MIDGARD_DVFS
820 int gpu_clk_freq = 0;
823 kbdev = dev_get_drvdata(dev);
831 #ifdef CONFIG_MALI_MIDGARD_DVFS
832 gpu_clk_freq = mali_get_dvfs_upper_locked_freq();
833 if (gpu_clk_freq > 0)
835 ret += snprintf(buf + ret, PAGE_SIZE - ret, "upper_lock_freq : %d KHz", gpu_clk_freq);
839 ret += snprintf(buf + ret, PAGE_SIZE - ret, "upper_lock_freq is NOT set");
841 /*ret += snprintf(buf + ret, PAGE_SIZE - ret, "\nPossible settings : 400, 350,266, 160, 100, If you want to unlock : 600 or off");*/
843 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\npossible upper_lock_freqs : ");
844 for ( i = 0; i < MALI_DVFS_STEP; i++ )
846 if ( i < (MALI_DVFS_STEP - 1) )
848 ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d, ", p_mali_dvfs_infotbl[i].clock);
852 ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d ", p_mali_dvfs_infotbl[i].clock);
855 ret += snprintf(buf + ret, PAGE_SIZE - ret, "(KHz)");
857 if ( gpu_clk_freq > 0 )
859 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\nif you want to unset upper_lock_freq, to echo 'off' to this file.");
862 ret += snprintf(buf + ret, PAGE_SIZE - ret, "mali DVFS is disabled. You can not set");
865 if (ret < PAGE_SIZE - 1)
866 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
868 buf[PAGE_SIZE - 2] = '\n';
869 buf[PAGE_SIZE - 1] = '\0';
876 static ssize_t set_upper_lock_dvfs(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
878 struct kbase_device *kbdev = NULL;
880 unsigned int freq = 0; // 可能由 caller 传入的, 待设置的 gpu_freq_upper_limit.
883 kbdev = dev_get_drvdata(dev);
887 E("'kbdev' is NULL.");
891 #ifdef CONFIG_MALI_MIDGARD_DVFS
892 if (sysfs_streq("off", buf))
894 mali_dvfs_freq_unlock();
898 freq = simple_strtoul(buf, NULL, 10);
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++)
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)
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);
911 E("fail to set dvfs_level_upper_limit, ret : %d.", ret);
917 /* 若 "没有" 找到和 target_freq match 的 level, 则... */
918 if ( MALI_DVFS_STEP == i )
920 // dev_err(dev, "set_clock: invalid value\n");
921 E("invalid target_freq : %d", freq);
926 #else /* CONFIG_MALI_MIDGARD_DVFS */
927 printk(KERN_DEBUG "mali DVFS is disabled. You can not set\n");
933 static ssize_t show_under_lock_dvfs(struct device *dev, struct device_attribute *attr, char *buf)
935 struct kbase_device *kbdev;
938 #ifdef CONFIG_MALI_MIDGARD_DVFS
939 int gpu_clk_freq = 0;
942 kbdev = dev_get_drvdata(dev);
947 #ifdef CONFIG_MALI_MIDGARD_DVFS
948 gpu_clk_freq = mali_get_dvfs_under_locked_freq();
949 if (gpu_clk_freq > 0)
951 ret += snprintf(buf + ret, PAGE_SIZE - ret, "under_lock_freq : %d KHz",gpu_clk_freq);
955 ret += snprintf(buf + ret, PAGE_SIZE - ret, "under_lock_freq is NOT set.");
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++ )
961 if ( i < (MALI_DVFS_STEP - 1) )
963 ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d, ", p_mali_dvfs_infotbl[i].clock);
967 ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d ", p_mali_dvfs_infotbl[i].clock);
970 ret += snprintf(buf + ret, PAGE_SIZE - ret, "(KHz)");
972 if ( gpu_clk_freq > 0 )
974 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\nif you want to unset under_lock_freq, to echo 'off' to this file.");
977 ret += snprintf(buf + ret, PAGE_SIZE - ret, "mali DVFS is disabled. You can not set");
980 if (ret < PAGE_SIZE - 1)
981 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
983 buf[PAGE_SIZE - 2] = '\n';
984 buf[PAGE_SIZE - 1] = '\0';
991 static ssize_t set_under_lock_dvfs(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
994 unsigned int freq = 0;
995 struct kbase_device *kbdev = NULL;
998 kbdev = dev_get_drvdata(dev);
1005 #ifdef CONFIG_MALI_MIDGARD_DVFS
1006 if (sysfs_streq("off", buf))
1008 mali_dvfs_freq_under_unlock();
1012 freq = simple_strtoul(buf, NULL, 10);
1015 for(i=0;i<MALI_DVFS_STEP;i++)
1017 if (p_mali_dvfs_infotbl[i].clock == freq)
1019 D("to set '%d' as the index of dvfs_level_lower_limit", i);
1020 ret = mali_dvfs_freq_under_lock(i);
1023 E("fail to set dvfs_level_lower_limit, ret : %d.", ret);
1029 /* 若 "没有" 找到和 target_freq match 的 level, 则... */
1030 if( i == MALI_DVFS_STEP )
1032 dev_err(dev, "set_clock: invalid value\n");
1037 #else /* CONFIG_MALI_MIDGARD_DVFS */
1038 printk(KERN_DEBUG "mali DVFS is disabled. You can not set\n");
1043 /** The sysfs file @c clock, fbdev.
1045 * This is used for obtaining information about the mali t6xx operating clock & framebuffer address,
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 /*---------------------------------------------------------------------------*/
1056 int kbase_platform_create_sysfs_file(struct device *dev)
1058 if (device_create_file(dev, &dev_attr_clock)) {
1059 dev_err(dev, "Couldn't create sysfs file [clock]\n");
1063 if (device_create_file(dev, &dev_attr_fbdev)) {
1064 dev_err(dev, "Couldn't create sysfs file [fbdev]\n");
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");
1075 if (device_create_file(dev, &dev_attr_dvfs)) {
1076 dev_err(dev, "Couldn't create sysfs file [dvfs]\n");
1080 if (device_create_file(dev, &dev_attr_dvfs_upper_lock)) {
1081 dev_err(dev, "Couldn't create sysfs file [dvfs_upper_lock]\n");
1085 if (device_create_file(dev, &dev_attr_dvfs_under_lock)) {
1086 dev_err(dev, "Couldn't create sysfs file [dvfs_under_lock]\n");
1090 if (device_create_file(dev, &dev_attr_time_in_state)) {
1091 dev_err(dev, "Couldn't create sysfs file [time_in_state]\n");
1100 void kbase_platform_remove_sysfs_file(struct device *dev)
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);
1110 #endif /* CONFIG_MALI_MIDGARD_DEBUG_SYS */
1112 mali_error kbase_platform_init(struct kbase_device *kbdev)
1114 struct rk_context *platform;
1117 platform = kmalloc(sizeof(struct rk_context), GFP_KERNEL);
1119 if (NULL == platform)
1120 return MALI_ERROR_OUT_OF_MEMORY;
1122 /* .KP : 将 'rk_context' 关联到 mali_device. */
1123 kbdev->platform_context = (void *)platform;
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;
1134 rk_gpu = kobject_create_and_add("rk_gpu", NULL);
1136 return MALI_ERROR_FUNCTION_FAILED;
1138 ret = sysfs_create_file(rk_gpu, &dev_attr_error_count.attr);
1140 return MALI_ERROR_FUNCTION_FAILED;
1142 spin_lock_init(&platform->cmu_pmu_lock);
1144 if (kbase_platform_power_clock_init(kbdev))
1145 goto clock_init_fail;
1147 #ifdef CONFIG_MALI_MIDGARD_DVFS
1148 kbase_platform_dvfs_init(kbdev);
1149 #endif /* CONFIG_MALI_MIDGARD_DVFS */
1152 kbase_platform_cmu_pmu_control(kbdev, 1);
1153 return MALI_ERROR_NONE;
1158 return MALI_ERROR_FUNCTION_FAILED;
1161 void kbase_platform_term(struct kbase_device *kbdev)
1163 struct rk_context *platform;
1165 platform = (struct rk_context *)kbdev->platform_context;
1167 #ifdef CONFIG_MALI_MIDGARD_DVFS
1168 kbase_platform_dvfs_term();
1169 #endif /* CONFIG_MALI_MIDGARD_DVFS */
1172 kbase_platform_cmu_pmu_control(kbdev, 0);
1173 kfree(kbdev->platform_context);
1174 kbdev->platform_context = 0;