From 5dccdd3aded6c4634916a1f1130f8e281958a8e2 Mon Sep 17 00:00:00 2001 From: Jiyu Yang Date: Tue, 26 May 2015 21:14:18 +0800 Subject: [PATCH] gxbb bringup 1. gxbb bringup. 2. left clock tree divider cannot work. Change-Id: Ie4d3727fa64f60a78b4a0a94ba83b86c441b149b Signed-off-by: Jiyu Yang --- mali/Kbuild | 40 +-- mali/Makefile | 1 + mali/clean.sh | 7 + mali/linux/mali_kernel_linux.c | 2 +- mali/platform/mali_scaling.h | 16 +- mali/platform/meson_bu/mali_clock.c | 212 ++++++++++++ mali/platform/meson_bu/mali_clock.h | 29 ++ mali/platform/meson_bu/mali_platform.h | 15 + mali/platform/meson_bu/mali_scaling.h | 1 + mali/platform/meson_bu/meson_main2.c | 122 +++++++ mali/platform/meson_bu/meson_main2.h | 37 ++ mali/platform/meson_bu/mpgpu.c | 357 +++++++++++++++++++ mali/platform/meson_bu/platform_gx.c | 444 ++++++++++++++++++++++++ mali/platform/meson_bu/scaling.c | 460 +++++++++++++++++++++++++ 14 files changed, 1715 insertions(+), 28 deletions(-) create mode 100755 mali/clean.sh mode change 100755 => 100644 mali/platform/mali_scaling.h create mode 100644 mali/platform/meson_bu/mali_clock.c create mode 100644 mali/platform/meson_bu/mali_clock.h create mode 100644 mali/platform/meson_bu/mali_platform.h create mode 120000 mali/platform/meson_bu/mali_scaling.h create mode 100644 mali/platform/meson_bu/meson_main2.c create mode 100644 mali/platform/meson_bu/meson_main2.h create mode 100644 mali/platform/meson_bu/mpgpu.c create mode 100644 mali/platform/meson_bu/platform_gx.c create mode 100644 mali/platform/meson_bu/scaling.c diff --git a/mali/Kbuild b/mali/Kbuild index acd8b72..1837b6f 100755 --- a/mali/Kbuild +++ b/mali/Kbuild @@ -10,29 +10,20 @@ # 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:= \ diff --git a/mali/Makefile b/mali/Makefile index 94c0a31..a0bef30 100755 --- a/mali/Makefile +++ b/mali/Makefile @@ -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 index 0000000..130fd73 --- /dev/null +++ b/mali/clean.sh @@ -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 diff --git a/mali/linux/mali_kernel_linux.c b/mali/linux/mali_kernel_linux.c index f25d24c..a0dcc36 100755 --- a/mali/linux/mali_kernel_linux.c +++ b/mali/linux/mali_kernel_linux.c @@ -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 diff --git a/mali/platform/mali_scaling.h b/mali/platform/mali_scaling.h old mode 100755 new mode 100644 index 4ca5da5..3076d30 --- a/mali/platform/mali_scaling.h +++ b/mali/platform/mali_scaling.h @@ -16,6 +16,8 @@ #ifndef __ARM_CORE_SCALING_H__ #define __ARM_CORE_SCALING_H__ +#include + 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 index 0000000..bbbded6 --- /dev/null +++ b/mali/platform/meson_bu/mali_clock.c @@ -0,0 +1,212 @@ +#include +#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; iclk_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\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 index 0000000..c9129ad --- /dev/null +++ b/mali/platform/meson_bu/mali_clock.h @@ -0,0 +1,29 @@ +#ifndef __MALI_CLOCK_H__ +#define __MALI_CLOCK_H__ +#include +#include +#include +#include +#include + +#include +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 29)) +#include +#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 index 0000000..41185d0 --- /dev/null +++ b/mali/platform/meson_bu/mali_platform.h @@ -0,0 +1,15 @@ +/* + * mali_platform.h + * + * Created on: Nov 8, 2013 + * Author: amlogic + */ + +#include +#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 index 0000000..dc8c0f4 --- /dev/null +++ b/mali/platform/meson_bu/mali_scaling.h @@ -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 index 0000000..6bcbf49 --- /dev/null +++ b/mali/platform/meson_bu/meson_main2.c @@ -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 +#include +#include +#ifdef CONFIG_PM_RUNTIME +#include +#endif +#include +#include +#include "mali_kernel_common.h" +#include +#include + +#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 diff --git a/mali/platform/meson_bu/meson_main2.h b/mali/platform/meson_bu/meson_main2.h new file mode 100644 index 0000000..a67441f --- /dev/null +++ b/mali/platform/meson_bu/meson_main2.h @@ -0,0 +1,37 @@ +/* + * mali_platform.h + * + * Created on: Nov 8, 2013 + * Author: amlogic + */ + +#ifndef MESON_MAIN_H_ +#define MESON_MAIN_H_ +#include +#include +#include +#ifdef CONFIG_PM_RUNTIME +#include +#endif +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 29)) +#include +#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 index 0000000..cadb61f --- /dev/null +++ b/mali/platform/meson_bu/mpgpu.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 29)) +#include +#include +#include +#endif + +#include +#include +#include +#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 index 0000000..77da53d --- /dev/null +++ b/mali/platform/meson_bu/platform_gx.c @@ -0,0 +1,444 @@ +/* + * platform.c + * + * clock source setting and resource config + * + * Created on: Dec 4, 2013 + * Author: amlogic + */ + +#include +#include +#include +#include +#include /* kernel module definitions */ +#include /* request_mem_region */ +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 29)) +#include +#include +#include +#endif +#include +#include +#ifdef CONFIG_GPU_THERMAL +#include +#include +#endif +#include +#include +#include + +#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_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 index 0000000..411d0d4 --- /dev/null +++ b/mali/platform/meson_bu/scaling.c @@ -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 +#include +#include +#include +#include +#include + +#include + +#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 +} -- 2.20.1