1. gxbb bringup.
2. left clock tree divider cannot work.
Change-Id: Ie4d3727fa64f60a78b4a0a94ba83b86c441b149b
Signed-off-by: Jiyu Yang <jiyu.yang@amlogic.com>
# 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. ###################
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. ###################
__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:= \
endif
ifeq ($(USING_DVFS),1)
+ xxxyyyy
export CONFIG_MALI_DVFS=y
export EXTRA_DEFINES += -DCONFIG_MALI_DVFS
endif
--- /dev/null
+#!/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
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
#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,
};
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;
/**
/* 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);
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+../mali_scaling.h
\ No newline at end of file
--- /dev/null
+/*
+ * 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, ¶m_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
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*******************************************************************
+ *
+ * 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
+}
+
--- /dev/null
+/*
+ * 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
+}
--- /dev/null
+/*
+ * 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
+}