gxbb bringup
authorJiyu Yang <jiyu.yang@amlogic.com>
Tue, 26 May 2015 13:14:18 +0000 (21:14 +0800)
committerJiyu Yang <jiyu.yang@amlogic.com>
Tue, 26 May 2015 13:51:07 +0000 (21:51 +0800)
1. gxbb bringup.
2. left clock tree divider cannot work.

Change-Id: Ie4d3727fa64f60a78b4a0a94ba83b86c441b149b
Signed-off-by: Jiyu Yang <jiyu.yang@amlogic.com>
14 files changed:
mali/Kbuild
mali/Makefile
mali/clean.sh [new file with mode: 0755]
mali/linux/mali_kernel_linux.c
mali/platform/mali_scaling.h [changed mode: 0755->0644]
mali/platform/meson_bu/mali_clock.c [new file with mode: 0644]
mali/platform/meson_bu/mali_clock.h [new file with mode: 0644]
mali/platform/meson_bu/mali_platform.h [new file with mode: 0644]
mali/platform/meson_bu/mali_scaling.h [new symlink]
mali/platform/meson_bu/meson_main2.c [new file with mode: 0644]
mali/platform/meson_bu/meson_main2.h [new file with mode: 0644]
mali/platform/meson_bu/mpgpu.c [new file with mode: 0644]
mali/platform/meson_bu/platform_gx.c [new file with mode: 0644]
mali/platform/meson_bu/scaling.c [new file with mode: 0644]

index acd8b725c00ea6dd12d01b4a516ecfefb2e56a58..1837b6f3274921580eaff38926e0263164b6ca52 100755 (executable)
 
 # This file is called by the Linux build system.
 ############## Kasin Added, for platform. ################
-TARGET_PLATFORM:=meson_m450
-ifeq ($(CONFIG_ARCH_MESON1),y)
-TARGET_PLATFORM:= meson_m400
-endif
-ifeq ($(CONFIG_ARCH_MESON3),y)
-TARGET_PLATFORM:= meson_m400
-endif
-ifeq ($(CONFIG_ARCH_MESON6),y)
-TARGET_PLATFORM:= meson_m400
-endif
-ifeq ($(CONFIG_ARCH_MESON6TV),y)
-TARGET_PLATFORM:= meson_m400
-endif
 
 ifndef CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH
     ccflags-y += -DCONFIG_MALI_DMA_BUF_MAP_ON_ATTACH=y
 endif
-ifeq ($(CONFIG_ARCH_MESON),y)
+#ifeq ($(CONFIG_ARCH_MESON),y)
+CONFIG_MALI400_DEBUG=y
+ccflags-y += -DCONFIG_MALI450=y
+ccflags-y += -DCONFIG_MALI_DT=y
 ccflags-y += -DMESON_CPU_TYPE=0x80
 ccflags-y += -DMESON_CPU_TYPE_MESON6=0x60
 ccflags-y += -DMESON_CPU_TYPE_MESON6TVD=0x75
 ccflags-y += -DMESON_CPU_TYPE_MESON8=0x80
-endif
+ccflags-y += -DMESON_CPU_TYPE_MESON8B=0x8B
+#endif
 
 ##################### end Kasin Added. ###################
 
@@ -67,13 +58,7 @@ ifeq ($(CONFIG_MALI400_DEBUG),y)
 else
        BUILD ?= release
        #ldflags-y += --strip-debug
-endif
-##################### end Kasin Added. ###################
 
-############## Kasin Added, useless now. ################
-ifeq ($(USING_UMP),1)
-       UMP_SYMVERS_FILE = ../ump/Module.symvers
-       KBUILD_EXTRA_SYMBOLS = $(srctree)/$(src)/$(UMP_SYMVERS_FILE)
 endif
 ##################### end Kasin Added. ###################
 
@@ -184,11 +169,22 @@ mali-y += \
        __malidrv_build_info.o
 
 ############## Kasin Added, for platform. ################
+ifeq (true,false)
 mali-y += \
        platform/meson_main.o \
        platform/mali_pm_device.o \
        platform/mali_clock.o \
-       platform/mpgpu.o \
+       platform/mpgpu.o
+else
+mali-y += \
+       platform/mali_pm_device.o \
+       platform/meson_bu/meson_main2.o \
+       platform/meson_bu/mali_clock.o \
+       platform/meson_bu/scaling.o \
+       platform/meson_bu/mpgpu.o \
+       platform/meson_bu/platform_gx.o
+endif
+
 
 ifeq ($(TARGET_PLATFORM),meson_m400)
 MALI_PLATFORM_FILES:= \
index 94c0a31cb82262ba87c95916ace51867ff3a0e61..a0bef307dbfbc61a1c3ce65fc1f4fa96f1aaeba9 100755 (executable)
@@ -139,6 +139,7 @@ export EXTRA_DEFINES += -DCONFIG_MALI_SHARED_INTERRUPTS
 endif
 
 ifeq ($(USING_DVFS),1)
+       xxxyyyy
 export CONFIG_MALI_DVFS=y
 export EXTRA_DEFINES += -DCONFIG_MALI_DVFS
 endif
diff --git a/mali/clean.sh b/mali/clean.sh
new file mode 100755 (executable)
index 0000000..130fd73
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+# rm *.o, *.cmd, *~
+find . -name "*.o" -o -name "*.cmd" -o -name "*~" | xargs rm -rf
+rm     Module.symvers
+rm     mali.ko
+rm     mali.mod.c
+rm     modules.order
index f25d24cbf4444a07e1bd6586b7ec591dae340101..a0dcc367fbda969f4a1c70ed27232d73c01642b7 100755 (executable)
@@ -369,7 +369,7 @@ int mali_module_init(void)
        int err = 0;
 
        MALI_DEBUG_PRINT(2, ("Inserting Mali v%d device driver. \n", _MALI_API_VERSION));
-       MALI_DEBUG_PRINT(2, ("Compiled: %s, time: %s.\n", __DATE__, __TIME__));
+       //MALI_DEBUG_PRINT(2, ("Compiled: %s, time: %s.\n", __DATE__, __TIME__));
        MALI_DEBUG_PRINT(2, ("Driver revision: %s\n", SVN_REV_STRING));
 
 #if MALI_ENABLE_CPU_CYCLES
old mode 100755 (executable)
new mode 100644 (file)
index 4ca5da5..3076d30
@@ -16,6 +16,8 @@
 #ifndef __ARM_CORE_SCALING_H__
 #define __ARM_CORE_SCALING_H__
 
+#include <linux/types.h>
+
 enum mali_scale_mode_t {
        MALI_PP_SCALING = 0,
        MALI_PP_FS_SCALING,
@@ -25,11 +27,13 @@ enum mali_scale_mode_t {
 };
 
 typedef struct mali_dvfs_threshold_table {
-       unsigned int freq_index;
-       unsigned int voltage;
-       unsigned int keep_count;
-       unsigned int downthreshold;
-       unsigned int upthreshold;
+       uint32_t    freq_index;
+       uint32_t    voltage;
+       uint32_t    keep_count;
+       uint32_t    downthreshold;
+       uint32_t    upthreshold;
+    uint32_t    clk_freq;
+    const char  *clk_parent;
 } mali_dvfs_threshold_table;
 
 /**
@@ -73,6 +77,8 @@ typedef struct mali_plat_info_t {
 
        /* for boost up gpu by user. */
        void (*plat_preheat)(void);
+
+    struct platform_device *pdev;
 } mali_plat_info_t;
 mali_plat_info_t* get_mali_plat_data(void);
 
diff --git a/mali/platform/meson_bu/mali_clock.c b/mali/platform/meson_bu/mali_clock.c
new file mode 100644 (file)
index 0000000..bbbded6
--- /dev/null
@@ -0,0 +1,212 @@
+#include <linux/platform_device.h>
+#include "mali_scaling.h"
+#include "mali_clock.h"
+#if 1
+#ifndef CLK_DVFS_TBL_SIZE
+#define CLK_DVFS_TBL_SIZE 5
+#endif
+//static DEFINE_SPINLOCK(lock);
+static mali_plat_info_t* pmali_plat = NULL;
+//static u32 mali_extr_backup = 0;
+//static u32 mali_extr_sample_backup = 0;
+
+int mali_clock_init_clk_tree(struct platform_device* pdev)
+{
+       struct clk *clk_mali_0_parent;
+       struct clk *clk_mali_0;
+       struct clk *clk_mali;
+
+       clk_mali = clk_get(&pdev->dev, "clk_mali");
+       clk_mali_0 = clk_get(&pdev->dev, "clk_mali_0");
+       clk_mali_0_parent = clk_get(&pdev->dev, "fclk_div4");
+
+       clk_set_parent(clk_mali_0, clk_mali_0_parent);
+
+       clk_prepare_enable(clk_mali_0_parent);
+       //ret = clk_set_rate(clk_mali, 425000000);
+
+       clk_prepare_enable(clk_mali_0);
+
+       clk_set_parent(clk_mali, clk_mali_0);
+
+       clk_prepare_enable(clk_mali);
+
+       printk(" clk_mali_0_parent =%p, clk_mali_0=%p, clk_mali=%p\n ",
+                       clk_mali_0_parent, clk_mali_0, clk_mali);
+
+       printk("pdev->drvdata=%p\n",
+                       dev_get_drvdata(&pdev->dev));
+
+       return 0;
+}
+
+int mali_clock_init(mali_plat_info_t *pdev)
+{
+       *pdev = *pdev;
+       return 0;
+}
+
+int mali_clock_critical(critical_t critical, size_t param)
+{
+       int ret = 0;
+       //unsigned long flags;
+
+       //spin_lock_irqsave(&lock, flags);
+       ret = critical(param);
+       //spin_unlock_irqrestore(&lock, flags);
+       return ret;
+}
+
+static int critical_clock_set(size_t param)
+{
+       int ret = 0;
+       unsigned int idx = param;
+       struct platform_device *pdev = pmali_plat->pdev;
+       mali_dvfs_threshold_table *dvfs_tbl = &pmali_plat->dvfs_table[idx];
+
+       struct clk *clk_mali_0_parent;
+       struct clk *clk_mali_0;
+       struct clk *clk_mali_1;
+       struct clk *clk_mali;
+
+       clk_mali = clk_get(&pdev->dev, "clk_mali");
+       clk_mali_1 = clk_get(&pdev->dev, "clk_mali_1");
+       clk_set_parent(clk_mali, clk_mali_1);
+
+       clk_mali_0 = clk_get(&pdev->dev, "clk_mali_0");
+       clk_mali_0_parent = clk_get(&pdev->dev,
+                       dvfs_tbl->clk_parent);
+
+       clk_set_parent(clk_mali_0, clk_mali_0_parent);
+       clk_prepare_enable(clk_mali_0_parent);
+       ret = clk_set_rate(clk_mali, dvfs_tbl->clk_freq);
+
+       clk_prepare_enable(clk_mali_0);
+
+       clk_set_parent(clk_mali, clk_mali_0);
+
+       clk_prepare_enable(clk_mali);
+
+       return 0;
+}
+
+int mali_clock_set(unsigned int clock)
+{
+       return mali_clock_critical(critical_clock_set, (size_t)clock);
+}
+
+void disable_clock(void)
+{
+       //unsigned long flags;
+
+       //spin_lock_irqsave(&lock, flags);
+       printk("disable clock\n");
+       //spin_unlock_irqrestore(&lock, flags);
+}
+
+void enable_clock(void)
+{
+       u32 ret = 0;
+       //unsigned long flags;
+
+       //spin_lock_irqsave(&lock, flags);
+       printk("enable clock, ret=%d\n", ret);
+       //spin_unlock_irqrestore(&lock, flags);
+}
+
+u32 get_mali_freq(u32 idx)
+{
+       if (!mali_pm_statue) {
+               return pmali_plat->clk_sample[idx];
+       } else {
+               return 0;
+       }
+}
+
+void set_str_src(u32 data)
+{
+       printk("%s, %s, %d\n", __FILE__, __func__, __LINE__);
+}
+
+int mali_dt_info(struct platform_device *pdev, struct mali_plat_info_t *mpdata)
+{
+       struct device_node *gpu_dn = pdev->dev.of_node;
+       struct device_node *gpu_clk_dn;
+       phandle dvfs_tbl_hdl;
+       phandle dvfs_clk_hdl[CLK_DVFS_TBL_SIZE];
+       mali_dvfs_threshold_table *dvfs_tbl = mpdata->dvfs_table;
+       uint32_t *clk_sample = mpdata->clk_sample;
+
+       int i = 0;
+       int ret = 0;
+       if (!gpu_dn) {
+               printk("gpu device node not right\n");
+       }
+
+       ret = of_property_read_u32(gpu_dn,"num_of_pp",
+                       &mpdata->cfg_pp);
+       mpdata->scale_info.maxpp = mpdata->cfg_pp;
+       printk("configure pp is %d\n", mpdata->cfg_pp);
+
+       ret = of_property_read_u32(gpu_dn,"dvfs_tbl",
+                       &dvfs_tbl_hdl);
+       gpu_dn = of_find_node_by_phandle(dvfs_tbl_hdl);
+       if (!gpu_dn) {
+               printk("failed to find gpu dvfs table\n");
+       }
+
+       ret = of_property_read_u32(gpu_dn,"sc_mpp",
+                       &mpdata->sc_mpp);
+       printk("sc_mpp=%d\n", mpdata->sc_mpp);
+
+       ret = of_property_read_u32_array(gpu_dn,"tbl",
+                       &dvfs_clk_hdl[0], CLK_DVFS_TBL_SIZE);
+
+       for (i = 0; i<CLK_DVFS_TBL_SIZE; i++) {
+               gpu_clk_dn = of_find_node_by_phandle(dvfs_clk_hdl[i]);
+               ret = of_property_read_u32(gpu_clk_dn,"clk_freq", &dvfs_tbl->clk_freq);
+               if (ret) {
+                       printk("read clk_freq failed\n");
+               }
+               ret = of_property_read_string(gpu_clk_dn,"clk_parent",
+                               &dvfs_tbl->clk_parent);
+               if (ret) {
+                       printk("read clk_parent failed\n");
+               }
+               ret = of_property_read_u32(gpu_clk_dn,"voltage", &dvfs_tbl->voltage);
+               if (ret) {
+                       printk("read voltage failed\n");
+               }
+               ret = of_property_read_u32(gpu_clk_dn,"keep_count", &dvfs_tbl->keep_count);
+               if (ret) {
+                       printk("read keep_count failed\n");
+               }
+               //downthreshold and upthreshold shall be u32
+               ret = of_property_read_u32_array(gpu_clk_dn,"threshold",
+                               &dvfs_tbl->downthreshold, 2);
+               if (ret) {
+                       printk("read threshold failed\n");
+               }
+               dvfs_tbl->freq_index = i;
+               *clk_sample = dvfs_tbl->clk_freq / 1000000;
+               dvfs_tbl ++;
+               clk_sample ++;
+       }
+
+       dvfs_tbl = mpdata->dvfs_table;
+       clk_sample = mpdata->clk_sample;
+       for (i = 0; i<CLK_DVFS_TBL_SIZE; i++) {
+               printk("===============%d=================\n", i);
+               printk("clk_freq=%d\nclk_parent=%s\nvoltage=%d\nkeep_count=%d\nthreshod=<%d %d>\n, clk_sample=%d\n",
+                               dvfs_tbl->clk_freq, dvfs_tbl->clk_parent,
+                               dvfs_tbl->voltage,  dvfs_tbl->keep_count,
+                               dvfs_tbl->downthreshold, dvfs_tbl->upthreshold, *clk_sample);
+               dvfs_tbl ++;
+               clk_sample ++;
+       }
+
+       pmali_plat = mpdata;
+       mpdata->pdev = pdev;
+       return 0;
+}
+#endif
diff --git a/mali/platform/meson_bu/mali_clock.h b/mali/platform/meson_bu/mali_clock.h
new file mode 100644 (file)
index 0000000..c9129ad
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef __MALI_CLOCK_H__
+#define __MALI_CLOCK_H__
+#include <linux/version.h>
+#include <linux/pm.h>
+#include <linux/io.h>
+#include <linux/types.h>
+#include <linux/of.h>
+
+#include <asm/io.h>
+#include <linux/clk.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 29))
+#include <linux/amlogic/iomap.h>
+#endif
+
+//extern int mali_clock_init(struct platform_device *dev);
+int mali_clock_init_clk_tree(struct platform_device *pdev);
+
+typedef int (*critical_t)(size_t param);
+int mali_clock_critical(critical_t critical, size_t param);
+
+int mali_clock_init(mali_plat_info_t*);
+int mali_clock_set(unsigned int index);
+void disable_clock(void);
+void enable_clock(void);
+u32 get_mali_freq(u32 idx);
+void set_str_src(u32 data);
+int mali_dt_info(struct platform_device *pdev,
+        struct mali_plat_info_t *mpdata);
+#endif
diff --git a/mali/platform/meson_bu/mali_platform.h b/mali/platform/meson_bu/mali_platform.h
new file mode 100644 (file)
index 0000000..41185d0
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * mali_platform.h
+ *
+ *  Created on: Nov 8, 2013
+ *      Author: amlogic
+ */
+
+#include <linux/kernel.h>
+#ifndef MALI_PLATFORM_H_
+#define MALI_PLATFORM_H_
+
+extern u32 mali_gp_reset_fail;
+extern u32 mali_core_timeout;
+
+#endif /* MALI_PLATFORM_H_ */
diff --git a/mali/platform/meson_bu/mali_scaling.h b/mali/platform/meson_bu/mali_scaling.h
new file mode 120000 (symlink)
index 0000000..dc8c0f4
--- /dev/null
@@ -0,0 +1 @@
+../mali_scaling.h
\ No newline at end of file
diff --git a/mali/platform/meson_bu/meson_main2.c b/mali/platform/meson_bu/meson_main2.c
new file mode 100644 (file)
index 0000000..6bcbf49
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2010, 2012-2014 Amlogic Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ */
+
+/**
+ * @file mali_platform.c
+ * Platform specific Mali driver functions for:
+ * meson8m2 and the newer chip
+ */
+#include <linux/platform_device.h>
+#include <linux/version.h>
+#include <linux/pm.h>
+#ifdef CONFIG_PM_RUNTIME
+#include <linux/pm_runtime.h>
+#endif
+#include <asm/io.h>
+#include <linux/mali/mali_utgard.h>
+#include "mali_kernel_common.h"
+#include <linux/dma-mapping.h>
+#include <linux/moduleparam.h>
+
+#include "mali_executor.h"
+#include "mali_scaling.h"
+#include "mali_clock.h"
+#include "meson_main2.h"
+
+#define CLK_DVFS_TBL_SIZE 5
+
+#if 0
+static int mali_core_scaling_enable = 0;
+#endif
+
+int mali_pm_statue = 0;
+extern void mali_gpu_utilization_callback(struct mali_gpu_utilization_data *data);
+
+u32 mali_gp_reset_fail = 0;
+u32 mali_core_timeout  = 0;
+
+static struct mali_gpu_device_data mali_gpu_data = {
+
+#if defined(CONFIG_ARCH_REALVIEW)
+       .dedicated_mem_start = 0x80000000, /* Physical start address (use 0xD0000000 for old indirect setup) */
+       .dedicated_mem_size = 0x10000000, /* 256MB */
+#endif
+#if defined(CONFIG_ARM64)
+       .fb_start = 0x5f000000,
+       .fb_size = 0x91000000,
+#else
+       .fb_start = 0xe0000000,
+       .fb_size = 0x01000000,
+#endif
+       .control_interval = 200, /* 1000ms */
+       .utilization_callback = mali_gpu_utilization_callback,
+       .get_clock_info = NULL,
+       .get_freq = NULL,
+       .set_freq = NULL,
+};
+
+int mali_platform_device_init(struct platform_device *device)
+{
+       int err = -1;
+
+       err = mali_meson_init_start(device);
+       if (0 != err) printk("mali init failed\n");
+
+       err = platform_device_add_data(device, &mali_gpu_data, sizeof(mali_gpu_data));
+
+       if (0 == err) {
+#ifdef CONFIG_PM_RUNTIME
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
+               pm_runtime_set_autosuspend_delay(&(device->dev), 1000);
+               pm_runtime_use_autosuspend(&(device->dev));
+#endif
+               pm_runtime_enable(&(device->dev));
+#endif
+               mali_meson_init_finish(device);
+       }
+
+       mali_gp_reset_fail = 0;
+       mali_core_timeout  = 0;
+
+       return err;
+}
+
+int mali_platform_device_deinit(struct platform_device *device)
+{
+       MALI_IGNORE(device);
+
+       printk("%s, %d\n", __FILE__, __LINE__);
+       MALI_DEBUG_PRINT(4, ("mali_platform_device_deinit() called\n"));
+
+       mali_core_scaling_term();
+
+       mali_meson_uninit(device);
+
+       return 0;
+}
+
+#if 0
+static int param_set_core_scaling(const char *val, const struct kernel_param *kp)
+{
+       int ret = param_set_int(val, kp);
+       printk("%s, %d\n", __FILE__, __LINE__);
+
+       if (1 == mali_core_scaling_enable) {
+               mali_core_scaling_sync(mali_executor_get_num_cores_enabled());
+       }
+       return ret;
+}
+
+static struct kernel_param_ops param_ops_core_scaling = {
+       .set = param_set_core_scaling,
+       .get = param_get_int,
+};
+
+module_param_cb(mali_core_scaling_enable, &param_ops_core_scaling, &mali_core_scaling_enable, 0644);
+MODULE_PARM_DESC(mali_core_scaling_enable, "1 means to enable core scaling policy, 0 means to disable core scaling policy");
+#endif
diff --git a/mali/platform/meson_bu/meson_main2.h b/mali/platform/meson_bu/meson_main2.h
new file mode 100644 (file)
index 0000000..a67441f
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * mali_platform.h
+ *
+ *  Created on: Nov 8, 2013
+ *      Author: amlogic
+ */
+
+#ifndef MESON_MAIN_H_
+#define MESON_MAIN_H_
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#ifdef CONFIG_PM_RUNTIME
+#include <linux/pm_runtime.h>
+#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 29))
+#include <mach/cpu.h>
+#endif
+
+#include "mali_scaling.h"
+#include "mali_clock.h"
+
+extern struct device_type mali_pm_device;
+extern int mali_pm_statue;
+
+u32 set_max_mali_freq(u32 idx);
+u32 get_max_mali_freq(void);
+
+int mali_meson_init_start(struct platform_device* ptr_plt_dev);
+int mali_meson_init_finish(struct platform_device* ptr_plt_dev);
+int mali_meson_uninit(struct platform_device* ptr_plt_dev);
+int mali_light_suspend(struct device *device);
+int mali_light_resume(struct device *device);
+int mali_deep_suspend(struct device *device);
+int mali_deep_resume(struct device *device);
+
+#endif /* MESON_MAIN_H_ */
diff --git a/mali/platform/meson_bu/mpgpu.c b/mali/platform/meson_bu/mpgpu.c
new file mode 100644 (file)
index 0000000..cadb61f
--- /dev/null
@@ -0,0 +1,357 @@
+/*******************************************************************
+ *
+ *  Copyright C 2013 by Amlogic, Inc. All Rights Reserved.
+ *
+ *  Description:
+ *
+ *  Author: Amlogic Software
+ *  Created: 2010/4/1   19:46
+ *
+ *******************************************************************/
+/* Standard Linux headers */
+#include <linux/platform_device.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 29))
+#include <mach/io.h>
+#include <plat/io.h>
+#include <asm/io.h>
+#endif
+
+#include <linux/mali/mali_utgard.h>
+#include <common/mali_kernel_common.h>
+#include <common/mali_pmu.h>
+#include "meson_main.h"
+
+#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8
+static ssize_t domain_stat_read(struct class *class,
+               struct class_attribute *attr, char *buf)
+{
+#if 0
+       unsigned int val;
+
+       val = readl((u32 *)(IO_AOBUS_BASE + 0xf0)) & 0xff;
+       return sprintf(buf, "%x\n", val>>4);
+#else
+       return 0;
+#endif
+}
+
+#define PREHEAT_CMD "preheat"
+#define PLL2_CMD "mpl2"  /* mpl2 [11] or [0xxxxxxx] */
+#define SCMPP_CMD "scmpp"  /* scmpp [number of pp your want in most of time]. */
+#define BSTGPU_CMD "bstgpu"  /* bstgpu [0-256] */
+#define BSTPP_CMD "bstpp"  /* bstpp [0-256] */
+#define LIMIT_CMD "lmt"  /* lmt [0 or 1] */
+#define MAX_TOKEN 20
+#define FULL_UTILIZATION 256
+
+static ssize_t mpgpu_write(struct class *class,
+               struct class_attribute *attr, const char *buf, size_t count)
+{
+       char *pstart, *cprt = NULL;
+       u32 val = 0;
+       mali_plat_info_t* pmali_plat = get_mali_plat_data();
+
+       cprt = skip_spaces(buf);
+       pstart = strsep(&cprt," ");
+       if (strlen(pstart) < 1)
+               goto quit;
+
+       if (!strncmp(pstart, PREHEAT_CMD, MAX_TOKEN)) {
+               if (pmali_plat->plat_preheat) {
+                       pmali_plat->plat_preheat();
+               }
+       } else if (!strncmp(pstart, PLL2_CMD, MAX_TOKEN)) {
+               int base = 10;
+               if ((strlen(cprt) > 2) && (cprt[0] == '0') &&
+                               (cprt[1] == 'x' || cprt[1] == 'X'))
+                       base = 16;
+               if (kstrtouint(cprt, base, &val) <0)
+                       goto quit;
+               if (val < 11)
+                       pmali_plat->cfg_clock = pmali_plat->cfg_clock_bkup;
+               else
+                       pmali_plat->cfg_clock = pmali_plat->turbo_clock;
+               pmali_plat->scale_info.maxclk = pmali_plat->cfg_clock;
+               set_str_src(val);
+       } else if (!strncmp(pstart, SCMPP_CMD, MAX_TOKEN)) {
+               if ((kstrtouint(cprt, 10, &val) <0) || pmali_plat == NULL)
+                       goto quit;
+               if ((val > 0) && (val < pmali_plat->cfg_pp)) {
+                       pmali_plat->sc_mpp = val;
+               }
+       } else if (!strncmp(pstart, BSTGPU_CMD, MAX_TOKEN)) {
+               if ((kstrtouint(cprt, 10, &val) <0) || pmali_plat == NULL)
+                       goto quit;
+               if ((val > 0) && (val < FULL_UTILIZATION)) {
+                       pmali_plat->bst_gpu = val;
+               }
+       } else if (!strncmp(pstart, BSTPP_CMD, MAX_TOKEN)) {
+               if ((kstrtouint(cprt, 10, &val) <0) || pmali_plat == NULL)
+                       goto quit;
+               if ((val > 0) && (val < FULL_UTILIZATION)) {
+                       pmali_plat->bst_pp = val;
+               }
+       } else if (!strncmp(pstart, LIMIT_CMD, MAX_TOKEN)) {
+               if ((kstrtouint(cprt, 10, &val) <0) || pmali_plat == NULL)
+                       goto quit;
+
+               if (val < 2) {
+                       pmali_plat->limit_on = val;
+                       if (val == 0) {
+                               pmali_plat->scale_info.maxclk = pmali_plat->cfg_clock;
+                               pmali_plat->scale_info.maxpp = pmali_plat->cfg_pp;
+                               revise_mali_rt();
+                       }
+               }
+       }
+quit:
+       return count;
+}
+
+static ssize_t scale_mode_read(struct class *class,
+               struct class_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", get_mali_schel_mode());
+}
+
+static ssize_t scale_mode_write(struct class *class,
+               struct class_attribute *attr, const char *buf, size_t count)
+{
+       int ret;
+       unsigned int val;
+
+       ret = kstrtouint(buf, 10, &val);
+       if (0 != ret)
+       {
+               return -EINVAL;
+       }
+
+       set_mali_schel_mode(val);
+
+       return count;
+}
+
+static ssize_t max_pp_read(struct class *class,
+               struct class_attribute *attr, char *buf)
+{
+       mali_plat_info_t* pmali_plat = get_mali_plat_data();
+       return sprintf(buf, "%d\n", pmali_plat->scale_info.maxpp);
+}
+
+static ssize_t max_pp_write(struct class *class,
+               struct class_attribute *attr, const char *buf, size_t count)
+{
+       int ret;
+       unsigned int val;
+       mali_plat_info_t* pmali_plat;
+       mali_scale_info_t* pinfo;
+
+       pmali_plat = get_mali_plat_data();
+       pinfo = &pmali_plat->scale_info;
+
+       ret = kstrtouint(buf, 10, &val);
+       if ((0 != ret) || (val > pmali_plat->cfg_pp) || (val < pinfo->minpp))
+               return -EINVAL;
+
+       pinfo->maxpp = val;
+       revise_mali_rt();
+
+       return count;
+}
+
+static ssize_t min_pp_read(struct class *class,
+               struct class_attribute *attr, char *buf)
+{
+       mali_plat_info_t* pmali_plat = get_mali_plat_data();
+       return sprintf(buf, "%d\n", pmali_plat->scale_info.minpp);
+}
+
+static ssize_t min_pp_write(struct class *class,
+               struct class_attribute *attr, const char *buf, size_t count)
+{
+       int ret;
+       unsigned int val;
+       mali_plat_info_t* pmali_plat;
+       mali_scale_info_t* pinfo;
+
+       pmali_plat = get_mali_plat_data();
+       pinfo = &pmali_plat->scale_info;
+
+       ret = kstrtouint(buf, 10, &val);
+       if ((0 != ret) || (val > pinfo->maxpp) || (val < 1))
+               return -EINVAL;
+
+       pinfo->minpp = val;
+       revise_mali_rt();
+
+       return count;
+}
+
+static ssize_t max_freq_read(struct class *class,
+               struct class_attribute *attr, char *buf)
+{
+       mali_plat_info_t* pmali_plat = get_mali_plat_data();
+       return sprintf(buf, "%d\n", pmali_plat->scale_info.maxclk);
+}
+
+static ssize_t max_freq_write(struct class *class,
+               struct class_attribute *attr, const char *buf, size_t count)
+{
+       int ret;
+       unsigned int val;
+       mali_plat_info_t* pmali_plat;
+       mali_scale_info_t* pinfo;
+
+       pmali_plat = get_mali_plat_data();
+       pinfo = &pmali_plat->scale_info;
+
+       ret = kstrtouint(buf, 10, &val);
+       if ((0 != ret) || (val > pmali_plat->cfg_clock) || (val < pinfo->minclk))
+               return -EINVAL;
+
+       pinfo->maxclk = val;
+       revise_mali_rt();
+
+       return count;
+}
+
+static ssize_t min_freq_read(struct class *class,
+               struct class_attribute *attr, char *buf)
+{
+       mali_plat_info_t* pmali_plat = get_mali_plat_data();
+       return sprintf(buf, "%d\n", pmali_plat->scale_info.minclk);
+}
+
+static ssize_t min_freq_write(struct class *class,
+               struct class_attribute *attr, const char *buf, size_t count)
+{
+       int ret;
+       unsigned int val;
+       mali_plat_info_t* pmali_plat;
+       mali_scale_info_t* pinfo;
+
+       pmali_plat = get_mali_plat_data();
+       pinfo = &pmali_plat->scale_info;
+
+       ret = kstrtouint(buf, 10, &val);
+       if ((0 != ret) || (val > pinfo->maxclk))
+               return -EINVAL;
+
+       pinfo->minclk = val;
+       revise_mali_rt();
+
+       return count;
+}
+
+static ssize_t freq_read(struct class *class,
+               struct class_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", get_current_frequency());
+}
+
+static ssize_t freq_write(struct class *class,
+               struct class_attribute *attr, const char *buf, size_t count)
+{
+       int ret;
+       unsigned int val;
+       u32 clk, pp;
+       get_mali_rt_clkpp(&clk, &pp);
+
+       ret = kstrtouint(buf, 10, &val);
+       if (0 != ret)
+               return -EINVAL;
+
+       set_mali_rt_clkpp(val, pp, 1);
+
+       return count;
+}
+
+static ssize_t current_pp_read(struct class *class,
+               struct class_attribute *attr, char *buf)
+{
+       u32 clk, pp;
+       get_mali_rt_clkpp(&clk, &pp);
+       return sprintf(buf, "%d\n", pp);
+}
+
+static ssize_t current_pp_write(struct class *class,
+               struct class_attribute *attr, const char *buf, size_t count)
+{
+       int ret;
+       unsigned int val;
+       u32 clk, pp;
+
+       get_mali_rt_clkpp(&clk, &pp);
+       ret = kstrtouint(buf, 10, &val);
+       if (0 != ret)
+       {
+               return -EINVAL;
+       }
+
+       ret = kstrtouint(buf, 10, &val);
+       if (0 != ret)
+               return -EINVAL;
+
+       set_mali_rt_clkpp(clk, val, 1);
+
+       return count;
+}
+
+static struct class_attribute mali_class_attrs[] = {
+       __ATTR(domain_stat,     0644, domain_stat_read, NULL),
+       __ATTR(mpgpucmd,        0644, NULL,             mpgpu_write),
+       __ATTR(scale_mode,      0644, scale_mode_read,  scale_mode_write),
+       __ATTR(min_freq,        0644, min_freq_read,    min_freq_write),
+       __ATTR(max_freq,        0644, max_freq_read,    max_freq_write),
+       __ATTR(min_pp,          0644, min_pp_read,      min_pp_write),
+       __ATTR(max_pp,          0644, max_pp_read,      max_pp_write),
+       __ATTR(cur_freq,        0644, freq_read,        freq_write),
+       __ATTR(cur_pp,          0644, current_pp_read,  current_pp_write),
+};
+
+static struct class mpgpu_class = {
+       .name = "mpgpu",
+};
+#endif
+
+int mpgpu_class_init(void)
+{
+#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8
+       int ret = 0;
+       int i;
+       int attr_num =  ARRAY_SIZE(mali_class_attrs);
+
+       ret = class_register(&mpgpu_class);
+       if (ret) {
+               printk(KERN_ERR "%s: class_register failed\n", __func__);
+               return ret;
+       }
+       for (i = 0; i< attr_num; i++) {
+               ret = class_create_file(&mpgpu_class, &mali_class_attrs[i]);
+               if (ret) {
+                       printk(KERN_ERR "%d ST: class item failed to register\n", i);
+               }
+       }
+       return ret;
+#else
+       return 0;
+#endif
+}
+
+void  mpgpu_class_exit(void)
+{
+#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8
+       class_unregister(&mpgpu_class);
+#endif
+}
+
diff --git a/mali/platform/meson_bu/platform_gx.c b/mali/platform/meson_bu/platform_gx.c
new file mode 100644 (file)
index 0000000..77da53d
--- /dev/null
@@ -0,0 +1,444 @@
+/*
+ * platform.c
+ *
+ * clock source setting and resource config
+ *
+ *  Created on: Dec 4, 2013
+ *      Author: amlogic
+ */
+
+#include <linux/platform_device.h>
+#include <linux/version.h>
+#include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/module.h>            /* kernel module definitions */
+#include <linux/ioport.h>            /* request_mem_region */
+#include <linux/slab.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 29))
+#include <mach/register.h>
+#include <mach/irqs.h>
+#include <mach/io.h>
+#endif
+#include <asm/io.h>
+#include <linux/mali/mali_utgard.h>
+#ifdef CONFIG_GPU_THERMAL
+#include <linux/gpu_cooling.h>
+#include <linux/gpucore_cooling.h>
+#endif
+#include <common/mali_kernel_common.h>
+#include <common/mali_osk_profiling.h>
+#include <common/mali_pmu.h>
+
+#include "mali_scaling.h"
+#include "mali_clock.h"
+#include "meson_main.h"
+
+/*
+ *    For Meson 8 M2.
+ *
+ */
+
+#define CFG_PP 6
+#define CFG_CLOCK 3
+#define CFG_MIN_PP 1
+#define CFG_MIN_CLOCK 0
+
+/* fclk is 2550Mhz. */
+#define FCLK_DEV3 (6 << 9)      /*  850   Mhz  */
+#define FCLK_DEV4 (5 << 9)      /*  637.5 Mhz  */
+#define FCLK_DEV5 (7 << 9)      /*  510   Mhz  */
+#define FCLK_DEV7 (4 << 9)      /*  364.3 Mhz  */
+
+
+static u32 mali_dvfs_clk[] = {
+    FCLK_DEV7 | 1,     /* 182.1 Mhz */
+    FCLK_DEV4 | 1,     /* 318.7 Mhz */
+    FCLK_DEV3 | 1,     /* 425 Mhz */
+    FCLK_DEV5 | 0,     /* 510 Mhz */
+    FCLK_DEV4 | 0,     /* 637.5 Mhz */
+};
+
+static u32 mali_dvfs_clk_sample[] = {
+    182,     /* 182.1 Mhz */
+    319,     /* 318.7 Mhz */
+    425,     /* 425 Mhz */
+    510,     /* 510 Mhz */
+    637,     /* 637.5 Mhz */
+};
+//////////////////////////////////////
+//for dvfs
+struct mali_gpu_clk_item  meson_gpu_clk[]  = {
+    {182,  1150},   /* 182.1 Mhz, 1150mV */
+    {319,  1150},   /* 318.7 Mhz */
+    {425,  1150},   /* 425 Mhz */
+    {510,  1150},   /* 510 Mhz */
+    {637,  1150},   /* 637.5 Mhz */
+};
+struct mali_gpu_clock meson_gpu_clk_info = {
+    .item = meson_gpu_clk,
+    .num_of_steps = ARRAY_SIZE(meson_gpu_clk),
+};
+static int cur_gpu_clk_index = 0;
+//////////////////////////////////////
+static mali_dvfs_threshold_table mali_dvfs_table[]={
+    { 0, 0, 3,  30,  80}, /* for 182.1  */
+    { 1, 1, 3,  40, 205}, /* for 318.7  */
+    { 2, 2, 3, 150, 215}, /* for 425.0  */
+    { 3, 3, 3, 170, 253}, /* for 510.0  */
+    { 4, 4, 3, 230, 255},  /* for 637.5  */
+    { 0, 0, 3,   0,   0}
+};
+
+static void mali_plat_preheat(void);
+static mali_plat_info_t mali_plat_data = {
+    .cfg_pp = CFG_PP,  /* number of pp. */
+    .cfg_min_pp = CFG_MIN_PP,
+    .turbo_clock = 4, /* reserved clock src. */
+    .def_clock = 2, /* gpu clock used most of time.*/
+    .cfg_clock = CFG_CLOCK, /* max gpu clock. */
+    .cfg_clock_bkup = CFG_CLOCK,
+    .cfg_min_clock = CFG_MIN_CLOCK,
+
+    .sc_mpp = 3, /* number of pp used most of time.*/
+    .bst_gpu = 210, /* threshold for boosting gpu. */
+    .bst_pp = 160, /* threshold for boosting PP. */
+
+    .clk = mali_dvfs_clk, /* clock source table. */
+    .clk_sample = mali_dvfs_clk_sample, /* freqency table for show. */
+    .clk_len = sizeof(mali_dvfs_clk) / sizeof(mali_dvfs_clk[0]),
+    .have_switch = 1,
+
+    .dvfs_table = mali_dvfs_table, /* DVFS table. */
+    .dvfs_table_size = sizeof(mali_dvfs_table) / sizeof(mali_dvfs_threshold_table),
+
+    .scale_info = {
+        CFG_MIN_PP, /* minpp */
+        CFG_PP, /* maxpp, should be same as cfg_pp */
+        CFG_MIN_CLOCK, /* minclk */
+        CFG_CLOCK, /* maxclk should be same as cfg_clock */
+    },
+
+    .limit_on = 1,
+    .plat_preheat = mali_plat_preheat,
+};
+
+static void mali_plat_preheat(void)
+{
+#ifndef CONFIG_MALI_DVFS
+    u32 pre_fs;
+    u32 clk, pp;
+
+    if (get_mali_schel_mode() != MALI_PP_FS_SCALING)
+        return;
+
+    get_mali_rt_clkpp(&clk, &pp);
+    pre_fs = mali_plat_data.def_clock + 1;
+    if (clk < pre_fs)
+        clk = pre_fs;
+    if (pp < mali_plat_data.sc_mpp)
+        pp = mali_plat_data.sc_mpp;
+    set_mali_rt_clkpp(clk, pp, 1);
+#endif
+}
+
+mali_plat_info_t* get_mali_plat_data(void) {
+    return &mali_plat_data;
+}
+
+int get_mali_freq_level(int freq)
+{
+    int i = 0, level = -1;
+    int mali_freq_num;
+
+    if (freq < 0)
+        return level;
+
+    mali_freq_num = mali_plat_data.dvfs_table_size - 1;
+    if (freq <= mali_plat_data.clk_sample[0])
+        level = mali_freq_num-1;
+    if (freq >= mali_plat_data.clk_sample[mali_freq_num - 1])
+        level = 0;
+    for (i=0; i<mali_freq_num - 1 ;i++) {
+        if (freq >= mali_plat_data.clk_sample[i] && freq <= mali_plat_data.clk_sample[i + 1]) {
+            level = i;
+            level = mali_freq_num-level - 1;
+        }
+    }
+    return level;
+}
+
+unsigned int get_mali_max_level(void)
+{
+    return mali_plat_data.dvfs_table_size - 1;
+}
+
+#ifdef CONFIG_GPU_THERMAL
+static void set_limit_mali_freq(u32 idx)
+{
+    if (mali_plat_data.limit_on == 0)
+        return;
+    if (idx > mali_plat_data.turbo_clock || idx < mali_plat_data.scale_info.minclk)
+        return;
+    mali_plat_data.scale_info.maxclk= idx;
+    revise_mali_rt();
+}
+
+static u32 get_limit_mali_freq(void)
+{
+    return mali_plat_data.scale_info.maxclk;
+}
+#endif
+
+#ifdef CONFIG_GPU_THERMAL
+static u32 set_limit_pp_num(u32 num)
+{
+    u32 ret = -1;
+    if (mali_plat_data.limit_on == 0)
+        goto quit;
+    if (num > mali_plat_data.cfg_pp ||
+            num < mali_plat_data.scale_info.minpp)
+        goto quit;
+    mali_plat_data.scale_info.maxpp = num;
+    revise_mali_rt();
+    ret = 0;
+quit:
+    return ret;
+}
+#endif
+
+void mali_gpu_utilization_callback(struct mali_gpu_utilization_data *data);
+
+/* Function that platfrom report it's clock info which driver can set, needed when CONFIG_MALI_DVFS enabled */
+void meson_platform_get_clock_info(struct mali_gpu_clock **data) {
+    *data = &meson_gpu_clk_info;
+}
+
+/* Function that get the current clock info, needed when CONFIG_MALI_DVFS enabled */
+int meson_platform_get_freq(void) {
+    printk("get cur_gpu_clk_index =%d\n", cur_gpu_clk_index);
+    return  cur_gpu_clk_index;
+}
+
+/* Fuction that platform callback for freq setting, needed when CONFIG_MALI_DVFS enabled */
+int meson_platform_set_freq(int setting_clock_step) {
+
+    if (cur_gpu_clk_index == setting_clock_step) {
+        return 0;
+    }
+
+    mali_clock_set(setting_clock_step);
+
+    cur_gpu_clk_index = setting_clock_step;
+    printk("set cur_gpu_clk_index =%d\n", cur_gpu_clk_index);
+
+    return 0;
+}
+
+int mali_meson_init_start(struct platform_device* ptr_plt_dev)
+{
+    dev_set_drvdata(&ptr_plt_dev->dev, &mali_plat_data);
+    mali_dt_info(ptr_plt_dev, &mali_plat_data);
+    mali_clock_init_clk_tree(ptr_plt_dev);
+    return 0;
+}
+
+int mali_meson_init_finish(struct platform_device* ptr_plt_dev)
+{
+#ifndef CONFIG_MALI_DVFS
+    if (mali_core_scaling_init(&mali_plat_data) < 0)
+        return -1;
+#else
+    printk("disable meson own dvfs\n");
+#endif
+    return 0;
+}
+
+int mali_meson_uninit(struct platform_device* ptr_plt_dev)
+{
+    return 0;
+}
+
+static int mali_cri_light_suspend(size_t param)
+{
+    int ret;
+    struct device *device;
+    struct mali_pmu_core *pmu;
+
+    ret = 0;
+    mali_pm_statue = 1;
+    device = (struct device *)param;
+    pmu = mali_pmu_get_global_pmu_core();
+
+    if (NULL != device->driver &&
+            NULL != device->driver->pm &&
+            NULL != device->driver->pm->runtime_suspend)
+    {
+        /* Need to notify Mali driver about this event */
+        ret = device->driver->pm->runtime_suspend(device);
+    }
+    mali_pmu_power_down_all(pmu);
+    return ret;
+}
+
+static int mali_cri_light_resume(size_t param)
+{
+    int ret;
+    struct device *device;
+    struct mali_pmu_core *pmu;
+
+    ret = 0;
+    device = (struct device *)param;
+    pmu = mali_pmu_get_global_pmu_core();
+
+    mali_pmu_power_up_all(pmu);
+    if (NULL != device->driver &&
+            NULL != device->driver->pm &&
+            NULL != device->driver->pm->runtime_resume)
+    {
+        /* Need to notify Mali driver about this event */
+        ret = device->driver->pm->runtime_resume(device);
+    }
+    mali_pm_statue = 0;
+    return ret;
+}
+
+static int mali_cri_deep_suspend(size_t param)
+{
+    int ret;
+    struct device *device;
+    struct mali_pmu_core *pmu;
+
+    ret = 0;
+    device = (struct device *)param;
+    pmu = mali_pmu_get_global_pmu_core();
+
+    if (NULL != device->driver &&
+            NULL != device->driver->pm &&
+            NULL != device->driver->pm->suspend)
+    {
+        /* Need to notify Mali driver about this event */
+        ret = device->driver->pm->suspend(device);
+    }
+    mali_pmu_power_down_all(pmu);
+    return ret;
+}
+
+static int mali_cri_deep_resume(size_t param)
+{
+    int ret;
+    struct device *device;
+    struct mali_pmu_core *pmu;
+
+    ret = 0;
+    device = (struct device *)param;
+    pmu = mali_pmu_get_global_pmu_core();
+
+    mali_pmu_power_up_all(pmu);
+    if (NULL != device->driver &&
+            NULL != device->driver->pm &&
+            NULL != device->driver->pm->resume)
+    {
+        /* Need to notify Mali driver about this event */
+        ret = device->driver->pm->resume(device);
+    }
+    return ret;
+
+}
+
+int mali_light_suspend(struct device *device)
+{
+    int ret = 0;
+#ifdef CONFIG_MALI400_PROFILING
+    _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE |
+            MALI_PROFILING_EVENT_CHANNEL_GPU |
+            MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE,
+            0, 0, 0, 0, 0);
+#endif
+
+    /* clock scaling. Kasin..*/
+    ret = mali_clock_critical(mali_cri_light_suspend, (size_t)device);
+    disable_clock();
+    return ret;
+}
+
+int mali_light_resume(struct device *device)
+{
+    int ret = 0;
+    enable_clock();
+    ret = mali_clock_critical(mali_cri_light_resume, (size_t)device);
+#ifdef CONFIG_MALI400_PROFILING
+    _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE |
+            MALI_PROFILING_EVENT_CHANNEL_GPU |
+            MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE,
+            get_current_frequency(), 0, 0, 0, 0);
+#endif
+    return ret;
+}
+
+int mali_deep_suspend(struct device *device)
+{
+    int ret = 0;
+
+    mali_pm_statue = 1;
+    enable_clock();
+#ifndef CONFIG_MALI_DVFS
+    flush_scaling_job();
+#endif
+
+    /* clock scaling off. Kasin... */
+    ret = mali_clock_critical(mali_cri_deep_suspend, (size_t)device);
+    disable_clock();
+    return ret;
+}
+
+int mali_deep_resume(struct device *device)
+{
+    int ret = 0;
+
+    /* clock scaling up. Kasin.. */
+    enable_clock();
+    ret = mali_clock_critical(mali_cri_deep_resume, (size_t)device);
+    mali_pm_statue = 0;
+    return ret;
+
+}
+
+void mali_post_init(void)
+{
+#ifdef CONFIG_GPU_THERMAL
+    int err;
+    struct gpufreq_cooling_device *gcdev = NULL;
+    struct gpucore_cooling_device *gccdev = NULL;
+
+    gcdev = gpufreq_cooling_alloc();
+    register_gpu_freq_info(get_current_frequency);
+    if (IS_ERR(gcdev))
+        printk("malloc gpu cooling buffer error!!\n");
+    else if (!gcdev)
+        printk("system does not enable thermal driver\n");
+    else {
+        gcdev->get_gpu_freq_level = get_mali_freq_level;
+        gcdev->get_gpu_max_level = get_mali_max_level;
+        gcdev->set_gpu_freq_idx = set_limit_mali_freq;
+        gcdev->get_gpu_current_max_level = get_limit_mali_freq;
+        err = gpufreq_cooling_register(gcdev);
+        if (err < 0)
+            printk("register GPU  cooling error\n");
+        printk("gpu cooling register okay with err=%d\n",err);
+    }
+
+    gccdev = gpucore_cooling_alloc();
+    if (IS_ERR(gccdev))
+        printk("malloc gpu core cooling buffer error!!\n");
+    else if (!gccdev)
+        printk("system does not enable thermal driver\n");
+    else {
+        gccdev->max_gpu_core_num=mali_plat_data.cfg_pp;
+        gccdev->set_max_pp_num=set_limit_pp_num;
+        err = (int)gpucore_cooling_register(gccdev);
+        if (err < 0)
+            printk("register GPU  cooling error\n");
+        printk("gpu core cooling register okay with err=%d\n",err);
+    }
+#endif
+}
diff --git a/mali/platform/meson_bu/scaling.c b/mali/platform/meson_bu/scaling.c
new file mode 100644 (file)
index 0000000..411d0d4
--- /dev/null
@@ -0,0 +1,460 @@
+/*
+ * Copyright (C) 2013 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/**
+ * @file arm_core_scaling.c
+ * Example core scaling policy.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/mali/mali_utgard.h>
+#include <mali_kernel_common.h>
+#include <mali_osk_profiling.h>
+
+#include <meson_main.h>
+
+#define LOG_MALI_SCALING 1
+
+
+static int currentStep;
+#ifndef CONFIG_MALI_DVFS
+static int num_cores_enabled;
+static int lastStep;
+static struct work_struct wq_work;
+static mali_plat_info_t* pmali_plat = NULL;
+#endif
+static int  scaling_mode = MALI_PP_FS_SCALING;
+//static int  scaling_mode = MALI_SCALING_DISABLE;
+//static int  scaling_mode = MALI_PP_SCALING;
+
+
+static unsigned scaling_dbg_level = 0;
+module_param(scaling_dbg_level, uint, 0644);
+MODULE_PARM_DESC(scaling_dbg_level , "scaling debug level");
+
+#define scalingdbg(level, fmt, arg...)                            \
+       do {                                                                                       \
+               if (scaling_dbg_level >= (level))                          \
+               printk(fmt , ## arg);                                              \
+       } while (0)
+
+#ifndef CONFIG_MALI_DVFS
+static void do_scaling(struct work_struct *work)
+{
+       mali_dvfs_threshold_table * pdvfs = pmali_plat->dvfs_table;
+       int err = mali_perf_set_num_pp_cores(num_cores_enabled);
+       scalingdbg(1, "set pp cores to %d\n", num_cores_enabled);
+       MALI_DEBUG_ASSERT(0 == err);
+       MALI_IGNORE(err);
+       if (pdvfs[currentStep].freq_index != pdvfs[lastStep].freq_index) {
+               mali_dev_pause();
+               mali_clock_set(pdvfs[currentStep].freq_index);
+               mali_dev_resume();
+               lastStep = currentStep;
+       }
+#ifdef CONFIG_MALI400_PROFILING
+       _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE |
+                       MALI_PROFILING_EVENT_CHANNEL_GPU |
+                       MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE,
+                       get_current_frequency(),
+                       0,      0,      0,      0);
+#endif
+}
+#endif
+
+u32 revise_set_clk(u32 val, u32 flush)
+{
+       u32 ret = 0;
+#ifndef CONFIG_MALI_DVFS
+       mali_scale_info_t* pinfo;
+
+       pinfo = &pmali_plat->scale_info;
+
+       if (val < pinfo->minclk)
+               val = pinfo->minclk;
+       else if (val >  pinfo->maxclk)
+               val =  pinfo->maxclk;
+
+       if (val != currentStep) {
+               currentStep = val;
+               if (flush)
+                       schedule_work(&wq_work);
+               else
+                       ret = 1;
+       }
+#endif
+       return ret;
+}
+
+void get_mali_rt_clkpp(u32* clk, u32* pp)
+{
+#ifndef CONFIG_MALI_DVFS
+       *clk = currentStep;
+       *pp = num_cores_enabled;
+#endif
+}
+
+u32 set_mali_rt_clkpp(u32 clk, u32 pp, u32 flush)
+{
+       u32 ret = 0;
+#ifndef CONFIG_MALI_DVFS
+       mali_scale_info_t* pinfo;
+       u32 flush_work = 0;
+
+       pinfo = &pmali_plat->scale_info;
+       if (clk < pinfo->minclk)
+               clk = pinfo->minclk;
+       else if (clk >  pinfo->maxclk)
+               clk =  pinfo->maxclk;
+
+       if (clk != currentStep) {
+               currentStep = clk;
+               if (flush)
+                       flush_work++;
+               else
+                       ret = 1;
+       }
+       if (pp < pinfo->minpp)
+               pp = pinfo->minpp;
+       else if (pp > pinfo->maxpp)
+               pp = pinfo->maxpp;
+
+       if (pp != num_cores_enabled) {
+               num_cores_enabled = pp;
+               if (flush)
+                       flush_work++;
+               else
+                       ret = 1;
+       }
+
+       if (flush_work)
+               schedule_work(&wq_work);
+#endif
+       return ret;
+}
+
+void revise_mali_rt(void)
+{
+#ifndef CONFIG_MALI_DVFS
+       set_mali_rt_clkpp(currentStep, num_cores_enabled, 1);
+#endif
+}
+
+void flush_scaling_job(void)
+{
+#ifndef CONFIG_MALI_DVFS
+       cancel_work_sync(&wq_work);
+#endif
+}
+
+#ifndef CONFIG_MALI_DVFS
+static u32 enable_one_core(void)
+{
+       scalingdbg(2, "meson:    one more pp, curent has %d pp cores\n",  num_cores_enabled + 1);
+       return set_mali_rt_clkpp(currentStep, num_cores_enabled + 1, 0);
+}
+
+static u32 disable_one_core(void)
+{
+       scalingdbg(2, "meson: disable one pp, current has %d pp cores\n",  num_cores_enabled - 1);
+       return set_mali_rt_clkpp(currentStep, num_cores_enabled - 1, 0);
+}
+
+static u32 enable_max_num_cores(void)
+{
+       return set_mali_rt_clkpp(currentStep, pmali_plat->scale_info.maxpp, 0);
+}
+
+static u32 enable_pp_cores(u32 val)
+{
+       scalingdbg(2, "meson: enable %d pp cores\n", val);
+       return set_mali_rt_clkpp(currentStep, val, 0);
+}
+#endif
+
+int mali_core_scaling_init(mali_plat_info_t *mali_plat)
+{
+#ifndef CONFIG_MALI_DVFS
+       if (mali_plat == NULL) {
+               scalingdbg(2, " Mali platform data is NULL!!!\n");
+               return -1;
+       }
+
+       pmali_plat = mali_plat;
+       num_cores_enabled = pmali_plat->sc_mpp;
+
+       currentStep = pmali_plat->def_clock;
+       lastStep = currentStep;
+       INIT_WORK(&wq_work, do_scaling);
+#endif
+       return 0;
+       /* NOTE: Mali is not fully initialized at this point. */
+}
+
+void mali_core_scaling_term(void)
+{
+#ifndef CONFIG_MALI_DVFS
+       flush_scheduled_work();
+#endif
+}
+
+#ifndef CONFIG_MALI_DVFS
+static u32 mali_threshold [] = {
+       102, /* 40% */
+       128, /* 50% */
+       230, /* 90% */
+};
+#endif
+
+void mali_pp_scaling_update(struct mali_gpu_utilization_data *data)
+{
+#ifndef CONFIG_MALI_DVFS
+       int ret = 0;
+
+       if (mali_threshold[2] < data->utilization_pp)
+               ret = enable_max_num_cores();
+       else if (mali_threshold[1]< data->utilization_pp)
+               ret = enable_one_core();
+       else if (0 < data->utilization_pp)
+               ret = disable_one_core();
+       if (ret == 1)
+               schedule_work(&wq_work);
+#endif
+}
+
+#if LOG_MALI_SCALING
+void trace_utilization(struct mali_gpu_utilization_data *data, u32 current_idx, u32 next,
+               u32 current_pp, u32 next_pp)
+{
+       char direction;
+       if (next > current_idx)
+               direction = '>';
+       else if ((current_idx > pmali_plat->scale_info.minpp) && (next < current_idx))
+               direction = '<';
+       else
+               direction = '~';
+
+       scalingdbg(2, "[SCALING]%c (%3d-->%3d)@%3d{%3d - %3d}. pp:(%d-->%d)\n",
+                       direction,
+                       get_mali_freq(current_idx),
+                       get_mali_freq(next),
+                       data->utilization_gpu,
+                       pmali_plat->dvfs_table[current_idx].downthreshold,
+                       pmali_plat->dvfs_table[current_idx].upthreshold,
+                       current_pp, next_pp);
+}
+#endif
+
+#ifndef CONFIG_MALI_DVFS
+static int mali_stay_count = 0;
+static void mali_decide_next_status(struct mali_gpu_utilization_data *data, int* next_fs_idx,
+               int* pp_change_flag)
+{
+       u32 utilization, mali_up_limit, decided_fs_idx;
+       u32 ld_left, ld_right;
+       u32 ld_up, ld_down;
+       u32 change_mode;
+
+       *pp_change_flag = 0;
+       change_mode = 0;
+       utilization = data->utilization_gpu;
+
+       //printk("line(%d), scaling_mode=%d\n",__LINE__,  scaling_mode);
+       mali_up_limit = (scaling_mode ==  MALI_TURBO_MODE) ?
+               pmali_plat->turbo_clock : pmali_plat->scale_info.maxclk;
+       decided_fs_idx = currentStep;
+
+       ld_up = pmali_plat->dvfs_table[currentStep].upthreshold;
+       ld_down = pmali_plat->dvfs_table[currentStep].downthreshold;
+
+       scalingdbg(2, "utilization=%d,  ld_up=%d\n ", utilization,  ld_up);
+       if (utilization >= ld_up) { /* go up */
+
+               scalingdbg(2, "currentStep=%d,  mali_up_limit=%d\n ", currentStep, mali_up_limit);
+               if (currentStep < mali_up_limit) {
+                       change_mode = 1;
+                       if ((currentStep < pmali_plat->def_clock) && (utilization > pmali_plat->bst_gpu))
+                               decided_fs_idx = pmali_plat->def_clock;
+                       else
+                               decided_fs_idx++;
+               }
+               if ((data->utilization_pp >= ld_up) &&
+                               (num_cores_enabled < pmali_plat->scale_info.maxpp)) {
+                       if ((num_cores_enabled < pmali_plat->sc_mpp) && (data->utilization_pp >= pmali_plat->bst_pp)) {
+                               *pp_change_flag = 1;
+                               change_mode = 1;
+                       } else if (change_mode == 0) {
+                               *pp_change_flag = 2;
+                               change_mode = 1;
+                       }
+               }
+#if LOG_MALI_SCALING
+               scalingdbg(2, "[nexting..] [LD:%d]-> FS[CRNT:%d LMT:%d NEXT:%d] PP[NUM:%d LMT:%d MD:%d][F:%d]\n",
+                               data->utilization_pp, currentStep, mali_up_limit, decided_fs_idx,
+                               num_cores_enabled, pmali_plat->scale_info.maxpp, *pp_change_flag, change_mode);
+#endif
+       } else if (utilization <= ld_down) { /* go down */
+               if (mali_stay_count > 0) {
+                       *next_fs_idx = decided_fs_idx;
+                       mali_stay_count--;
+                       return;
+               }
+
+               if (num_cores_enabled > pmali_plat->sc_mpp) {
+                       change_mode = 1;
+                       if (data->utilization_pp <= ld_down) {
+                               ld_left = data->utilization_pp * num_cores_enabled;
+                               ld_right = (pmali_plat->dvfs_table[currentStep].upthreshold) *
+                                       (num_cores_enabled - 1);
+                               if (ld_left < ld_right) {
+                                       change_mode = 2;
+                               }
+                       }
+               } else if (currentStep > pmali_plat->scale_info.minclk) {
+                       change_mode = 1;
+               } else if (num_cores_enabled > 1) { /* decrease PPS */
+                       if (data->utilization_pp <= ld_down) {
+                               ld_left = data->utilization_pp * num_cores_enabled;
+                               ld_right = (pmali_plat->dvfs_table[currentStep].upthreshold) *
+                                       (num_cores_enabled - 1);
+                               scalingdbg(2, "ld_left=%d, ld_right=%d\n", ld_left, ld_right);
+                               if (ld_left < ld_right) {
+                                       change_mode = 2;
+                               }
+                       }
+               }
+
+               if (change_mode == 1) {
+                       decided_fs_idx--;
+               } else if (change_mode == 2) { /* decrease PPS */
+                       *pp_change_flag = -1;
+               }
+       }
+       if (change_mode)
+               mali_stay_count = pmali_plat->dvfs_table[decided_fs_idx].keep_count;
+       *next_fs_idx = decided_fs_idx;
+}
+#endif
+
+void mali_pp_fs_scaling_update(struct mali_gpu_utilization_data *data)
+{
+#ifndef CONFIG_MALI_DVFS
+       int ret = 0;
+       int pp_change_flag = 0;
+       u32 next_idx = 0;
+
+#if LOG_MALI_SCALING
+       u32 last_pp = num_cores_enabled;
+#endif
+       mali_decide_next_status(data, &next_idx, &pp_change_flag);
+
+       if (pp_change_flag == 1)
+               ret = enable_pp_cores(pmali_plat->sc_mpp);
+       else if (pp_change_flag == 2)
+               ret = enable_one_core();
+       else if (pp_change_flag == -1) {
+               ret = disable_one_core();
+       }
+
+#if LOG_MALI_SCALING
+       if (pp_change_flag || (next_idx != currentStep))
+               trace_utilization(data, currentStep, next_idx, last_pp, num_cores_enabled);
+#endif
+
+       if (next_idx != currentStep) {
+               ret = 1;
+               currentStep = next_idx;
+       }
+
+       if (ret == 1)
+               schedule_work(&wq_work);
+#ifdef CONFIG_MALI400_PROFILING
+       else
+               _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE |
+                               MALI_PROFILING_EVENT_CHANNEL_GPU |
+                               MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE,
+                               get_current_frequency(),
+                               0,      0,      0,      0);
+#endif
+#endif
+}
+
+u32 get_mali_schel_mode(void)
+{
+       return scaling_mode;
+}
+
+void set_mali_schel_mode(u32 mode)
+{
+#ifndef CONFIG_MALI_DVFS
+       MALI_DEBUG_ASSERT(mode < MALI_SCALING_MODE_MAX);
+       if (mode >= MALI_SCALING_MODE_MAX)
+               return;
+       scaling_mode = mode;
+       //printk("line(%d), scaling_mode=%d\n",__LINE__,  scaling_mode);
+
+       /* set default performance range. */
+       pmali_plat->scale_info.minclk = pmali_plat->cfg_min_clock;
+       pmali_plat->scale_info.maxclk = pmali_plat->cfg_clock;
+       pmali_plat->scale_info.minpp = pmali_plat->cfg_min_pp;
+       pmali_plat->scale_info.maxpp = pmali_plat->cfg_pp;
+
+       /* set current status and tune max freq */
+       if (scaling_mode == MALI_PP_FS_SCALING) {
+               pmali_plat->scale_info.maxclk = pmali_plat->cfg_clock;
+               enable_pp_cores(pmali_plat->sc_mpp);
+       } else if (scaling_mode == MALI_SCALING_DISABLE) {
+               pmali_plat->scale_info.maxclk = pmali_plat->cfg_clock;
+               enable_max_num_cores();
+       } else if (scaling_mode == MALI_TURBO_MODE) {
+               pmali_plat->scale_info.maxclk = pmali_plat->turbo_clock;
+               enable_max_num_cores();
+       }
+       currentStep = pmali_plat->scale_info.maxclk;
+       schedule_work(&wq_work);
+#endif
+}
+
+u32 get_current_frequency(void)
+{
+       return get_mali_freq(currentStep);
+}
+
+void mali_gpu_utilization_callback(struct mali_gpu_utilization_data *data)
+{
+#ifndef CONFIG_MALI_DVFS
+       if (mali_pm_statue)
+               return;
+
+       //printk("line(%d), scaling_mode=%d\n",__LINE__,  scaling_mode);
+       switch (scaling_mode) {
+               case MALI_PP_FS_SCALING:
+                       mali_pp_fs_scaling_update(data);
+                       break;
+               case MALI_PP_SCALING:
+                       mali_pp_scaling_update(data);
+                       break;
+               default:
+                       break;
+       }
+#endif
+}
+
+void mali_dev_restore(void)
+{
+#ifndef CONFIG_MALI_DVFS
+       mali_dvfs_threshold_table * pdvfs = pmali_plat->dvfs_table;
+
+       //mali_perf_set_num_pp_cores(num_cores_enabled);
+       mali_clock_set(pdvfs[currentStep].freq_index);
+#endif
+}