6db4831e98
Android 14
3589 lines
102 KiB
C
3589 lines
102 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (c) 2019 MediaTek Inc.
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/init.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/miscdevice.h>
|
|
#include <linux/platform_device.h>
|
|
#ifdef CONFIG_HAS_EARLYSUSPEND
|
|
#include <linux/earlysuspend.h>
|
|
#endif
|
|
#include <linux/spinlock.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/hrtimer.h>
|
|
#include <linux/ktime.h>
|
|
#include <linux/jiffies.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/input.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/sched/rt.h>
|
|
#include <linux/sched/task.h>
|
|
#include <linux/kthread.h>
|
|
#include <uapi/linux/sched/types.h>
|
|
#ifdef CONFIG_OF
|
|
#include <linux/of.h>
|
|
#include <linux/of_address.h>
|
|
#endif
|
|
|
|
#include <linux/uaccess.h>
|
|
|
|
#include "mtk_gpufreq.h"
|
|
/*
|
|
* #include "mtk_static_power.h"
|
|
*/
|
|
#include "mt-plat/upmu_common.h"
|
|
#include "mt-plat/sync_write.h"
|
|
#include "mach/mtk_pmic_wrap.h"
|
|
|
|
#include "mtk_fhreg.h"
|
|
#include "mtk_freqhopping_drv.h"
|
|
|
|
static void __iomem *g_apmixed_base;
|
|
|
|
/* Change name of REG_MFGPLL_CON0 to REG_GPUPLL_CON0 in MT6739 */
|
|
#define GPUPLL_CON0 (REG_MFGPLL_CON0)
|
|
#define GPUPLL_CON1 (REG_MFGPLL_CON1)
|
|
|
|
/* Use VOLT_SET_READY for regulator operation debug*/
|
|
#define VOLT_SET_READY
|
|
|
|
/* support vcorefs_request_dvfs_opp, operation voltage by the API */
|
|
#define VCORE_DVFS_OPP_SUPPORT
|
|
|
|
/* TODO: check this! */
|
|
/* #include "mach/mt_static_power.h" */
|
|
#include "mach/mtk_thermal.h"
|
|
#include "mach/upmu_sw.h"
|
|
#include "mach/upmu_hw.h"
|
|
#include "mach/mtk_pbm.h"
|
|
|
|
#include <linux/regulator/consumer.h>
|
|
#include <mtk_vcorefs_manager.h>
|
|
#include "mtk_devinfo.h"
|
|
|
|
/* #define BRING_UP */
|
|
|
|
#define DRIVER_NOT_READY -1
|
|
|
|
#ifndef MTK_UNREFERENCED_PARAMETER
|
|
#define MTK_UNREFERENCED_PARAMETER(param) ((void)(param))
|
|
#endif
|
|
|
|
//#define DRV_Reg32(addr) readl(addr)
|
|
#define DRV_Reg32(addr) INREG32(addr)
|
|
|
|
/*
|
|
* CONFIG
|
|
*/
|
|
/**************************************************
|
|
* Define low battery voltage support
|
|
***************************************************/
|
|
#define MT_GPUFREQ_LOW_BATT_VOLT_PROTECT
|
|
|
|
/**************************************************
|
|
* Define low battery volume support
|
|
***************************************************/
|
|
#define MT_GPUFREQ_LOW_BATT_VOLUME_PROTECT
|
|
|
|
/**************************************************
|
|
* Define oc support
|
|
***************************************************/
|
|
#define MT_GPUFREQ_OC_PROTECT
|
|
|
|
/**************************************************
|
|
* GPU DVFS input boost feature
|
|
***************************************************/
|
|
#define MT_GPUFREQ_INPUT_BOOST
|
|
|
|
/***************************
|
|
* Define for dynamic power table update
|
|
****************************/
|
|
#define MT_GPUFREQ_DYNAMIC_POWER_TABLE_UPDATE
|
|
|
|
#define STATIC_PWR_READY2USE
|
|
|
|
#ifdef STATIC_PWR_READY2USE
|
|
#include "mtk_common_static_power.h"
|
|
#endif
|
|
|
|
/***************************
|
|
* Define for random test
|
|
****************************/
|
|
/* #define MT_GPU_DVFS_RANDOM_TEST */
|
|
|
|
/***************************
|
|
* Define for SRAM debugging
|
|
****************************/
|
|
#ifdef CONFIG_MTK_RAM_CONSOLE
|
|
#define MT_GPUFREQ_AEE_RR_REC
|
|
#endif
|
|
|
|
/*
|
|
* Define how to setup VPROC by
|
|
* PMIC_WRAP
|
|
* PMIC
|
|
* external IC
|
|
*/
|
|
/* #define VPROC_SET_BY_PMIC_WRAP */
|
|
#define VPROC_SET_BY_PMIC
|
|
/* #define VPROC_SET_BY_EXTIC */
|
|
|
|
#ifdef VPROC_SET_BY_EXTIC
|
|
#include "fan53555.h"
|
|
#endif
|
|
/**************************************************
|
|
* Define register write function
|
|
***************************************************/
|
|
#define mt_gpufreq_reg_write(val, addr) mt_reg_sync_writel((val), ((void *)addr))
|
|
|
|
/***************************
|
|
* Operate Point Definition
|
|
****************************/
|
|
#define GPUOP(khz, volt, vsram, idx) \
|
|
{ \
|
|
.gpufreq_khz = khz, \
|
|
.gpufreq_volt = volt, \
|
|
.gpufreq_vsram = vsram, \
|
|
.gpufreq_idx = idx, \
|
|
}
|
|
|
|
/*************
|
|
* For MT6739
|
|
*************/
|
|
#define VPROC 1
|
|
#define VSRAM 2
|
|
|
|
/**************************
|
|
* GPU DVFS OPP table setting
|
|
***************************/
|
|
|
|
/* MT6739 Use VCORE DVFS and need on/off VCORE & frequency control only */
|
|
#define GPU_DVFS_FREQ0 (450000) /* KHz */
|
|
#define GPU_DVFS_FREQ1 (400000) /* KHz */
|
|
#define GPU_DVFS_FREQ2 (350000) /* KHz */
|
|
#define GPU_DVFS_FREQ3 (290000) /* KHz */
|
|
#define GPUFREQ_LAST_FREQ_LEVEL (GPU_DVFS_FREQ3)
|
|
|
|
#define GPU_DVFS_VOLT0 (115000) /* mV x 100 */
|
|
#define GPU_DVFS_VOLT1 (111875) /* mV x 100 */
|
|
#define GPU_DVFS_VOLT2 (108750) /* mV x 100 */
|
|
#define GPU_DVFS_VOLT3 (105000) /* mV x 100 */
|
|
|
|
#define GPU_DVFS_VSRAM0 (100000) /* mV x 100 */
|
|
#define GPU_DVFS_VSRAM1 (98750) /* mV x 100 */
|
|
|
|
#define GPU_DVFS_MAX_FREQ GPU_DVFS_FREQ0 /* KHz */
|
|
|
|
#define GPU_DVFS_PTPOD_DISABLE_VOLT GPU_DVFS_VOLT1
|
|
|
|
#define UNIVPLL_FREQ (416000) /* KHz */
|
|
|
|
/* MT6739TW Use VCORE DVFS and need on/off VCORE & frequency control only */
|
|
#define GPU_DVFS_FREQ0_6739TW (570000) /* KHz */
|
|
#define GPU_DVFS_FREQ1_6739TW (482500) /* KHz */
|
|
#define GPU_DVFS_FREQ2_6739TW (395000) /* KHz */
|
|
#define GPU_DVFS_FREQ3_6739TW (290000) /* KHz */
|
|
#define GPUFREQ_LAST_FREQ_LEVEL_6739TW (GPU_DVFS_FREQ3_6739TW)
|
|
|
|
#define GPU_DVFS_VOLT0_6739TW (115000) /* mV x 100 */
|
|
#define GPU_DVFS_VOLT1_6739TW (111875) /* mV x 100 */
|
|
#define GPU_DVFS_VOLT2_6739TW (108750) /* mV x 100 */
|
|
#define GPU_DVFS_VOLT3_6739TW (105000) /* mV x 100 */
|
|
|
|
#define GPU_DVFS_VSRAM0_6739TW (90000) /* mV x 100 */
|
|
#define GPU_DVFS_VSRAM1_6739TW (80000) /* mV x 100 */
|
|
|
|
#define GPU_DVFS_PTPOD_DISABLE_VOLT_MT6739TW GPU_DVFS_VOLT0_6739TW
|
|
|
|
/* MT6739WD(6731) Use VCORE DVFS and need on/off VCORE & frequency control only */
|
|
#define GPU_DVFS_FREQ0_6739WD (350000) /* KHz */
|
|
#define GPU_DVFS_FREQ1_6739WD (290000) /* KHz */
|
|
#define GPUFREQ_LAST_FREQ_LEVEL_6739WD (GPU_DVFS_FREQ1_6739WD)
|
|
|
|
#define GPU_DVFS_VOLT0_6739WD (108750) /* mV x 100 */
|
|
#define GPU_DVFS_VOLT1_6739WD (105000) /* mV x 100 */
|
|
|
|
#define GPU_DVFS_VSRAM0_6739WD (90000) /* mV x 100 */
|
|
#define GPU_DVFS_VSRAM1_6739WD (80000) /* mV x 100 */
|
|
|
|
#define GPU_DVFS_PTPOD_DISABLE_VOLT_MT6739WD GPU_DVFS_VOLT0_6739WD
|
|
|
|
/*****************************************
|
|
* PMIC settle time (us), should not be changed
|
|
******************************************/
|
|
#define PMIC_MAX_VSRAM GPU_DVFS_VSRAM0
|
|
#define PMIC_MIN_VCORE GPU_DVFS_VOLT1
|
|
#define PMIC_MAX_VCORE GPU_DVFS_VOLT0
|
|
|
|
#define PMIC_MIN_VCORE_6739TW GPU_DVFS_VOLT1_6739TW
|
|
#define PMIC_MAX_VCORE_6739TW GPU_DVFS_VOLT0_6739TW
|
|
|
|
#define PMIC_MIN_VCORE_6739WD GPU_DVFS_VOLT1_6739WD
|
|
#define PMIC_MAX_VCORE_6739WD GPU_DVFS_VOLT0_6739WD
|
|
|
|
/* mt6739 us * 100 BEGIN */
|
|
#define DELAY_FACTOR 625
|
|
#define HALF_DELAY_FACTOR 312
|
|
#define BUCK_INIT_US 750
|
|
#define VPROC_ENABLE_TIME_US 240 /* spec is 220, but more time means more safety */
|
|
#define VSRAM_GPU_ENABLE_TIME_US 120 /* spec is 110, but more time means more safety */
|
|
|
|
/* mt6739 END */
|
|
|
|
|
|
#define PMIC_CMD_DELAY_TIME 5
|
|
#define MIN_PMIC_SETTLE_TIME 25
|
|
#define PMIC_VOLT_UP_SETTLE_TIME(old_volt, new_volt) \
|
|
(((((new_volt) - (old_volt)) + 1250 - 1) / 1250) + PMIC_CMD_DELAY_TIME)
|
|
#define PMIC_VOLT_DOWN_SETTLE_TIME(old_volt, new_volt) \
|
|
(((((old_volt) - (new_volt)) * 2) / 625) + PMIC_CMD_DELAY_TIME)
|
|
#define PMIC_VOLT_ON_OFF_DELAY_US (200)
|
|
#define INVALID_SLEW_RATE (0)
|
|
|
|
/* efuse */
|
|
#define GPUFREQ_EFUSE_INDEX (8)
|
|
#define EFUSE_MFG_SPD_BOND_SHIFT (8)
|
|
#define EFUSE_MFG_SPD_BOND_MASK (0xF)
|
|
#define EFUSE_FAB_INFO_TURBO_MASK (0x300000)
|
|
/*
|
|
* LOG
|
|
*/
|
|
#define TAG "[Power/gpufreq] "
|
|
|
|
#define gpufreq_pr_err(fmt, args...) \
|
|
pr_err(TAG"[ERROR]"fmt, ##args)
|
|
#define gpufreq_pr_warn(fmt, args...) \
|
|
pr_warn(TAG"[WARNING]"fmt, ##args)
|
|
#define gpufreq_info(fmt, args...) \
|
|
pr_info(TAG""fmt, ##args)
|
|
#define gpufreq_dbg(fmt, args...) \
|
|
do { \
|
|
if (mt_gpufreq_debug) \
|
|
pr_debug(TAG""fmt, ##args); \
|
|
} while (0)
|
|
#define gpufreq_ver(fmt, args...) \
|
|
do { \
|
|
if (mt_gpufreq_debug) \
|
|
pr_debug(TAG""fmt, ##args); \
|
|
} while (0)
|
|
|
|
|
|
#ifdef CONFIG_HAS_EARLYSUSPEND
|
|
static struct early_suspend mt_gpufreq_early_suspend_handler = {
|
|
.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 200,
|
|
.suspend = NULL,
|
|
.resume = NULL,
|
|
};
|
|
#endif
|
|
|
|
static sampler_func g_pFreqSampler;
|
|
static sampler_func g_pVoltSampler;
|
|
|
|
static gpufreq_power_limit_notify g_pGpufreq_power_limit_notify;
|
|
#ifdef MT_GPUFREQ_INPUT_BOOST
|
|
static gpufreq_input_boost_notify g_pGpufreq_input_boost_notify;
|
|
#endif
|
|
static gpufreq_ptpod_update_notify g_pGpufreq_ptpod_update_notify;
|
|
|
|
/* Efuse Device ID */
|
|
enum chip_ip_table {
|
|
ID_MT6739 = 0,
|
|
ID_MT6739TW,
|
|
ID_MT6739WD,
|
|
};
|
|
|
|
static enum chip_ip_table device_id;
|
|
|
|
/***************************
|
|
* GPU DVFS OPP Table
|
|
****************************/
|
|
/* Full Yield */
|
|
static struct mt_gpufreq_table_info mt_gpufreq_opp_tbl_mt6739[] = {
|
|
GPUOP(GPU_DVFS_FREQ0, GPU_DVFS_VOLT0, GPU_DVFS_VSRAM0, 0),
|
|
GPUOP(GPU_DVFS_FREQ1, GPU_DVFS_VOLT1, GPU_DVFS_VSRAM1, 1),
|
|
GPUOP(GPU_DVFS_FREQ2, GPU_DVFS_VOLT2, GPU_DVFS_VSRAM1, 2),
|
|
GPUOP(GPU_DVFS_FREQ3, GPU_DVFS_VOLT3, GPU_DVFS_VSRAM1, 3),
|
|
};
|
|
|
|
static struct mt_gpufreq_table_info mt_gpufreq_opp_tbl_mt6739tw[] = {
|
|
GPUOP(GPU_DVFS_FREQ0_6739TW, GPU_DVFS_VOLT0_6739TW, GPU_DVFS_VSRAM0_6739TW, 0),
|
|
GPUOP(GPU_DVFS_FREQ1_6739TW, GPU_DVFS_VOLT1_6739TW, GPU_DVFS_VSRAM1_6739TW, 1),
|
|
GPUOP(GPU_DVFS_FREQ2_6739TW, GPU_DVFS_VOLT2_6739TW, GPU_DVFS_VSRAM1_6739TW, 2),
|
|
GPUOP(GPU_DVFS_FREQ3_6739TW, GPU_DVFS_VOLT3_6739TW, GPU_DVFS_VSRAM1_6739TW, 3),
|
|
};
|
|
|
|
static struct mt_gpufreq_table_info mt_gpufreq_opp_tbl_mt6739wd[] = {
|
|
GPUOP(GPU_DVFS_FREQ0_6739WD, GPU_DVFS_VOLT0_6739WD, GPU_DVFS_VSRAM0_6739WD, 0),
|
|
GPUOP(GPU_DVFS_FREQ1_6739WD, GPU_DVFS_VOLT1_6739WD, GPU_DVFS_VSRAM1_6739WD, 1),
|
|
};
|
|
|
|
/*
|
|
* AEE (SRAM debug)
|
|
*/
|
|
#ifdef MT_GPUFREQ_AEE_RR_REC
|
|
enum gpu_dvfs_state {
|
|
GPU_DVFS_IS_DOING_DVFS = 0,
|
|
GPU_DVFS_IS_VPROC_ENABLED,
|
|
};
|
|
|
|
static void _mt_gpufreq_aee_init(void)
|
|
{
|
|
aee_rr_rec_gpu_dvfs_vgpu(0xFF);
|
|
aee_rr_rec_gpu_dvfs_oppidx(0xFF);
|
|
aee_rr_rec_gpu_dvfs_status(0xFC);
|
|
}
|
|
#endif
|
|
|
|
/**************************
|
|
* enable GPU DVFS count
|
|
***************************/
|
|
static int g_gpufreq_dvfs_disable_count;
|
|
|
|
static unsigned int g_cur_gpu_freq = GPU_DVFS_FREQ0; /* initial value */
|
|
static unsigned int g_cur_gpu_volt = GPU_DVFS_VOLT0; /* initial value */
|
|
static unsigned int g_cur_gpu_idx = 0xFF;
|
|
static unsigned int g_cur_gpu_OPPidx = 0xFF;
|
|
#ifdef SFCHG
|
|
static unsigned int g_vproc_sfchg_rrate = 3; /* just a default value */
|
|
static unsigned int g_vproc_sfchg_frate = 3; /* just a default value */
|
|
static unsigned int g_vsram_sfchg_rrate = 3; /* just a default value */
|
|
static unsigned int g_vsram_sfchg_frate = 3; /* just a default value */
|
|
#endif
|
|
|
|
static unsigned int g_cur_freq_init_keep;
|
|
|
|
static bool mt_gpufreq_ready;
|
|
|
|
/* In default settiing, freq_table[0] is max frequency, freq_table[num-1] is min frequency,*/
|
|
static unsigned int g_gpufreq_max_id;
|
|
|
|
/* If not limited, it should be set to freq_table[0] (MAX frequency) */
|
|
static unsigned int g_limited_max_id;
|
|
static unsigned int g_limited_min_id;
|
|
|
|
static bool mt_gpufreq_debug;
|
|
static bool mt_gpufreq_pause;
|
|
static bool mt_gpufreq_keep_max_frequency_state;
|
|
static bool mt_gpufreq_keep_opp_frequency_state;
|
|
static unsigned int mt_gpufreq_keep_opp_frequency;
|
|
static unsigned int mt_gpufreq_keep_opp_index;
|
|
static bool mt_gpufreq_fixed_freq_volt_state;
|
|
static unsigned int mt_gpufreq_fixed_frequency;
|
|
static unsigned int mt_gpufreq_fixed_voltage;
|
|
|
|
static unsigned int mt_gpufreq_volt_enable;
|
|
|
|
static unsigned int mt_gpufreq_volt_enable_state;
|
|
#ifdef MT_GPUFREQ_INPUT_BOOST
|
|
static unsigned int mt_gpufreq_input_boost_state = 1;
|
|
#endif
|
|
static bool g_limited_thermal_ignore_state;
|
|
#ifdef MT_GPUFREQ_LOW_BATT_VOLT_PROTECT
|
|
static bool g_limited_low_batt_volt_ignore_state;
|
|
#endif
|
|
#ifdef MT_GPUFREQ_LOW_BATT_VOLUME_PROTECT
|
|
static bool g_limited_low_batt_volume_ignore_state;
|
|
#endif
|
|
#ifdef MT_GPUFREQ_OC_PROTECT
|
|
static bool g_limited_oc_ignore_state;
|
|
#endif
|
|
|
|
static bool mt_gpufreq_opp_max_frequency_state;
|
|
static unsigned int mt_gpufreq_opp_max_frequency;
|
|
static unsigned int mt_gpufreq_opp_max_index;
|
|
|
|
static unsigned int mt_gpufreq_dvfs_table_type;
|
|
static unsigned int mt_gpufreq_dvfs_table_cid;
|
|
|
|
/* static DEFINE_SPINLOCK(mt_gpufreq_lock); */
|
|
static DEFINE_MUTEX(mt_gpufreq_lock);
|
|
static DEFINE_MUTEX(mt_gpufreq_power_lock);
|
|
|
|
static unsigned int mt_gpufreqs_num;
|
|
static struct mt_gpufreq_table_info *mt_gpufreqs;
|
|
static struct mt_gpufreq_table_info *mt_gpufreqs_default;
|
|
static struct mt_gpufreq_power_table_info *mt_gpufreqs_power;
|
|
static struct mt_gpufreq_clk_t *mt_gpufreq_clk;
|
|
static struct mt_gpufreq_pmic_t *mt_gpufreq_pmic;
|
|
|
|
|
|
/* static struct mt_gpufreq_power_table_info *mt_gpufreqs_default_power; */
|
|
|
|
static bool mt_gpufreq_ptpod_disable;
|
|
static int mt_gpufreq_ptpod_disable_idx;
|
|
|
|
static void mt_gpufreq_clock_switch(unsigned int freq_new);
|
|
static void mt_gpufreq_volt_switch(unsigned int volt_old, unsigned int volt_new);
|
|
static void mt_gpufreq_set(unsigned int freq_old, unsigned int freq_new,
|
|
unsigned int volt_old, unsigned int volt_new);
|
|
static unsigned int _mt_gpufreq_get_cur_volt(void);
|
|
static unsigned int _mt_gpufreq_get_cur_freq(void);
|
|
static void _mt_gpufreq_kick_pbm(int enable);
|
|
|
|
|
|
#ifndef DISABLE_PBM_FEATURE
|
|
static bool g_limited_pbm_ignore_state;
|
|
static unsigned int mt_gpufreq_pbm_limited_gpu_power; /* PBM limit power */
|
|
static unsigned int mt_gpufreq_pbm_limited_index; /* Limited frequency index for PBM */
|
|
#define GPU_OFF_SETTLE_TIME_MS (100)
|
|
struct delayed_work notify_pbm_gpuoff_work;
|
|
#endif
|
|
|
|
/* SSPM reserved memory */
|
|
/* #ifdef MTK_SSPM */
|
|
phys_addr_t gpu_fdvfs_phy_addr, gpu_fdvfs_virt_addr;
|
|
uint32_t gpu_dvfs_mem_size;
|
|
|
|
/* #endif */
|
|
|
|
|
|
int __attribute__ ((weak))
|
|
get_immediate_gpu_wrap(void)
|
|
{
|
|
gpufreq_pr_err("get_immediate_gpu_wrap doesn't exist");
|
|
return 0;
|
|
}
|
|
|
|
/*************************************************************************************
|
|
* Get Post DIV value
|
|
*
|
|
* @breif
|
|
* VCO needs proper post div value to get corresponding dds value to adjust PLL value
|
|
* e.g: VCO range is 1.5GHz - 3.8GHz
|
|
* required frequency is 900MHz, so pos div could be 2(1.8/2), 4(3.6/4), 8(X), 16(X)
|
|
* It may have special requiremt by DE in different efuse value
|
|
* e.g: In MT6757, efuse value(3'b001) ,VCO range is 1.5GHz - 3.8GHz
|
|
* 375MHz - 900MHz, It can only use post div 4, no pos div 2
|
|
*
|
|
* @param[in] freq: required frequency
|
|
* @param[in] efuse: efuse value
|
|
* return corresponding post div by freq and efuse
|
|
**************************************************************************************/
|
|
static enum post_div_order_enum _get_post_div_order(unsigned int freq, unsigned int efuse)
|
|
{
|
|
/* [MT6757]VCO range: 1.5G - 3.8GHz by div 1/2/4/8/16
|
|
*
|
|
* PLL range: 125MHz - 3.8GHz
|
|
* Version(eFuse Value) Info POSTDIV FOUT
|
|
* Free Version(efuse 3'b000) No limit 1/2/4/8/16 125MHz - 3800MHz
|
|
*/
|
|
enum post_div_order_enum post_div_order = POST_DIV4;
|
|
|
|
post_div_order = POST_DIV4;
|
|
|
|
gpufreq_dbg("@%s: freq = %d efuse = %d post_div_order = %d\n", __func__, freq, efuse, post_div_order);
|
|
return post_div_order;
|
|
}
|
|
|
|
|
|
#ifdef MT_GPUFREQ_INPUT_BOOST
|
|
static struct task_struct *mt_gpufreq_up_task;
|
|
|
|
static int mt_gpufreq_input_boost_task(void *data)
|
|
{
|
|
while (1) {
|
|
gpufreq_dbg("@%s: begin\n", __func__);
|
|
|
|
if (g_pGpufreq_input_boost_notify != NULL) {
|
|
gpufreq_dbg("@%s: g_pGpufreq_input_boost_notify\n", __func__);
|
|
g_pGpufreq_input_boost_notify(g_gpufreq_max_id);
|
|
}
|
|
|
|
gpufreq_dbg("@%s: end\n", __func__);
|
|
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
|
schedule();
|
|
|
|
if (kthread_should_stop())
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*************************************************************************************
|
|
* Input boost
|
|
**************************************************************************************/
|
|
static void mt_gpufreq_input_event(struct input_handle *handle, unsigned int type,
|
|
unsigned int code, int value)
|
|
{
|
|
if (mt_gpufreq_ready == false) {
|
|
/*gpufreq_pr_warn("@%s: GPU DVFS not ready!\n", __func__);*/
|
|
return;
|
|
}
|
|
|
|
if ((type == EV_KEY) && (code == BTN_TOUCH) && (value == 1)
|
|
&& (mt_gpufreq_input_boost_state == 1)) {
|
|
gpufreq_dbg("@%s: accept.\n", __func__);
|
|
|
|
wake_up_process(mt_gpufreq_up_task);
|
|
}
|
|
}
|
|
|
|
static int mt_gpufreq_input_connect(struct input_handler *handler,
|
|
struct input_dev *dev, const struct input_device_id *id)
|
|
{
|
|
struct input_handle *handle;
|
|
int error;
|
|
|
|
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
|
|
if (!handle)
|
|
return -ENOMEM;
|
|
|
|
handle->dev = dev;
|
|
handle->handler = handler;
|
|
handle->name = "gpufreq_ib";
|
|
|
|
error = input_register_handle(handle);
|
|
if (error)
|
|
goto err2;
|
|
|
|
error = input_open_device(handle);
|
|
if (error)
|
|
goto err1;
|
|
|
|
return 0;
|
|
err1:
|
|
input_unregister_handle(handle);
|
|
err2:
|
|
kfree(handle);
|
|
return error;
|
|
}
|
|
|
|
static void mt_gpufreq_input_disconnect(struct input_handle *handle)
|
|
{
|
|
input_close_device(handle);
|
|
input_unregister_handle(handle);
|
|
kfree(handle);
|
|
}
|
|
|
|
static const struct input_device_id mt_gpufreq_ids[] = {
|
|
{.driver_info = 1},
|
|
{},
|
|
};
|
|
|
|
static struct input_handler mt_gpufreq_input_handler = {
|
|
.event = mt_gpufreq_input_event,
|
|
.connect = mt_gpufreq_input_connect,
|
|
.disconnect = mt_gpufreq_input_disconnect,
|
|
.name = "gpufreq_ib",
|
|
.id_table = mt_gpufreq_ids,
|
|
};
|
|
#endif /* mt_gpufreq_input_handler */
|
|
|
|
/*
|
|
* Power table calculation
|
|
*/
|
|
static void mt_gpufreq_power_calculation(unsigned int idx, unsigned int freq,
|
|
unsigned int volt, unsigned int temp)
|
|
{
|
|
#define GPU_ACT_REF_POWER 250 /* mW */
|
|
#define GPU_ACT_REF_FREQ 420000 /* KHz */
|
|
#define GPU_ACT_REF_VOLT 115000 /* mV x 100 */
|
|
#define GPU_ACT_REF_POWER_MT6739W 350 /* mW */
|
|
#define GPU_ACT_REF_FREQ_MT6739W 570000 /* KHz */
|
|
#define GPU_ACT_REF_VOLT_MT6739W 115000 /* mV x 100 */
|
|
|
|
unsigned int p_total = 0, p_dynamic = 0, ref_freq = 0, ref_volt = 0;
|
|
int p_leakage = 0;
|
|
|
|
if (mt_gpufreq_dvfs_table_type == ID_MT6739TW) {
|
|
p_dynamic = GPU_ACT_REF_POWER_MT6739W;
|
|
ref_freq = GPU_ACT_REF_FREQ_MT6739W;
|
|
ref_volt = GPU_ACT_REF_VOLT_MT6739W;
|
|
} else {
|
|
p_dynamic = GPU_ACT_REF_POWER;
|
|
ref_freq = GPU_ACT_REF_FREQ;
|
|
ref_volt = GPU_ACT_REF_VOLT;
|
|
}
|
|
|
|
p_dynamic = p_dynamic *
|
|
((freq * 100) / ref_freq) *
|
|
((volt * 100) / ref_volt) * ((volt * 100) / ref_volt) / (100 * 100 * 100);
|
|
|
|
#ifdef STATIC_PWR_READY2USE
|
|
p_leakage =
|
|
mt_spower_get_leakage(MTK_SPOWER_GPU, (volt / 100), temp);
|
|
if (!mt_gpufreq_volt_enable_state || p_leakage < 0)
|
|
p_leakage = 0;
|
|
#else
|
|
p_leakage = 71;
|
|
#endif
|
|
|
|
p_total = p_dynamic + p_leakage;
|
|
|
|
gpufreq_ver("%d: p_dynamic = %d, p_leakage = %d, p_total = %d, temp = %d\n",
|
|
idx, p_dynamic, p_leakage, p_total, temp);
|
|
|
|
mt_gpufreqs_power[idx].gpufreq_power = p_total;
|
|
}
|
|
|
|
/**************************************
|
|
* Random seed generated for test
|
|
***************************************/
|
|
#ifdef MT_GPU_DVFS_RANDOM_TEST
|
|
static int mt_gpufreq_idx_get(int num)
|
|
{
|
|
int random = 0, mult = 0, idx;
|
|
|
|
random = jiffies & 0xF;
|
|
|
|
while (1) {
|
|
if ((mult * num) >= random) {
|
|
idx = (mult * num) - random;
|
|
break;
|
|
}
|
|
mult++;
|
|
}
|
|
return idx;
|
|
}
|
|
#endif
|
|
|
|
|
|
/* Set frequency and voltage at driver probe function */
|
|
static void mt_gpufreq_set_initial(void)
|
|
{
|
|
unsigned int cur_volt = 0, cur_freq = 0;
|
|
/*int i = 0;*/
|
|
|
|
mutex_lock(&mt_gpufreq_lock);
|
|
|
|
#ifdef MT_GPUFREQ_AEE_RR_REC
|
|
aee_rr_rec_gpu_dvfs_status(aee_rr_curr_gpu_dvfs_status() | (1 << GPU_DVFS_IS_DOING_DVFS));
|
|
#endif
|
|
gpufreq_dbg("[Figo] Into mt_gpufreq_set_initial");
|
|
cur_volt = _mt_gpufreq_get_cur_volt();
|
|
cur_freq = _mt_gpufreq_get_cur_freq();
|
|
|
|
#if 0
|
|
for (i = 0; i < mt_gpufreqs_num; i++) {
|
|
if (cur_volt >= mt_gpufreqs[i].gpufreq_volt) {
|
|
mt_gpufreq_set(cur_freq, mt_gpufreqs[i].gpufreq_khz,
|
|
cur_volt, mt_gpufreqs[i].gpufreq_volt);
|
|
g_cur_gpu_OPPidx = i;
|
|
gpufreq_dbg("init_idx = %d\n", g_cur_gpu_OPPidx);
|
|
_mt_gpufreq_kick_pbm(1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Not found, set to LPM */
|
|
if (i == mt_gpufreqs_num) {
|
|
gpufreq_pr_err
|
|
("Set to LPM since GPU idx not found according to current Vcore = %d mV\n",
|
|
cur_volt / 100);
|
|
g_cur_gpu_OPPidx = mt_gpufreqs_num - 1;
|
|
mt_gpufreq_set(cur_freq, mt_gpufreqs[g_cur_gpu_OPPidx].gpufreq_khz,
|
|
cur_volt, mt_gpufreqs[g_cur_gpu_OPPidx].gpufreq_volt);
|
|
}
|
|
#endif
|
|
|
|
g_cur_gpu_OPPidx = 0;
|
|
mt_gpufreq_set(cur_freq, mt_gpufreqs[g_cur_gpu_OPPidx].gpufreq_khz,
|
|
cur_volt, mt_gpufreqs[g_cur_gpu_OPPidx].gpufreq_volt);
|
|
|
|
g_cur_gpu_freq = mt_gpufreqs[g_cur_gpu_OPPidx].gpufreq_khz;
|
|
g_cur_gpu_volt = mt_gpufreqs[g_cur_gpu_OPPidx].gpufreq_volt;
|
|
g_cur_gpu_idx = mt_gpufreqs[g_cur_gpu_OPPidx].gpufreq_idx;
|
|
|
|
#ifdef MT_GPUFREQ_AEE_RR_REC
|
|
aee_rr_rec_gpu_dvfs_oppidx(g_cur_gpu_OPPidx);
|
|
aee_rr_rec_gpu_dvfs_status(aee_rr_curr_gpu_dvfs_status() & ~(1 << GPU_DVFS_IS_DOING_DVFS));
|
|
#endif
|
|
|
|
mutex_unlock(&mt_gpufreq_lock);
|
|
}
|
|
|
|
|
|
#ifndef DISABLE_PBM_FEATURE
|
|
static void mt_gpufreq_notify_pbm_gpuoff(struct work_struct *work)
|
|
{
|
|
mutex_lock(&mt_gpufreq_lock);
|
|
if (!mt_gpufreq_volt_enable_state)
|
|
_mt_gpufreq_kick_pbm(0);
|
|
|
|
mutex_unlock(&mt_gpufreq_lock);
|
|
}
|
|
#endif
|
|
|
|
|
|
/* Set VPROC/VSRAM enable/disable when GPU clock be switched on/off */
|
|
unsigned int mt_gpufreq_voltage_enable_set(unsigned int enable)
|
|
{
|
|
int ret = 0;
|
|
|
|
mutex_lock(&mt_gpufreq_lock);
|
|
|
|
gpufreq_dbg("[Figo][+]@%s: enable = %d, mt_gpufreq_volt_enable_state = %d\n",
|
|
__func__, enable, mt_gpufreq_volt_enable_state);
|
|
|
|
|
|
#ifdef VPROC_SET_BY_PMIC
|
|
if (mt_gpufreq_ready == false) {
|
|
/*gpufreq_pr_warn("@%s: GPU DVFS not ready!\n", __func__);*/
|
|
ret = DRIVER_NOT_READY;
|
|
goto SET_EXIT;
|
|
}
|
|
|
|
{
|
|
#ifdef VCORE_DVFS_OPP_SUPPORT
|
|
if (enable == BUCK_ON) {
|
|
switch (g_cur_gpu_volt) {
|
|
case GPU_DVFS_VOLT0:
|
|
ret = vcorefs_request_dvfs_opp(KIR_GPU, OPP_0);
|
|
break;
|
|
case GPU_DVFS_VOLT1:
|
|
ret = vcorefs_request_dvfs_opp(KIR_GPU, OPP_1);
|
|
break;
|
|
case GPU_DVFS_VOLT2:
|
|
ret = vcorefs_request_dvfs_opp(KIR_GPU, OPP_2);
|
|
break;
|
|
case GPU_DVFS_VOLT3:
|
|
ret = vcorefs_request_dvfs_opp(KIR_GPU, OPP_3);
|
|
break;
|
|
default:
|
|
gpufreq_pr_warn("@%s: ummapped voltage! volt %d\n", __func__, g_cur_gpu_volt);
|
|
break;
|
|
}
|
|
} else {
|
|
ret = vcorefs_request_dvfs_opp(KIR_GPU, OPP_UNREQ);
|
|
}
|
|
if (ret)
|
|
gpufreq_pr_warn("@%s: vcorefs_request_dvfs_opp fail! volt %d\n", __func__, g_cur_gpu_volt);
|
|
#else
|
|
gpufreq_dbg("@%s: VCORE_DVFS_OPP_SUPPORT not defined!, need to implement it by PMIC\n",
|
|
__func__);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#ifndef DISABLE_PBM_FEATURE
|
|
if (enable == 1) {
|
|
if (delayed_work_pending(¬ify_pbm_gpuoff_work))
|
|
cancel_delayed_work(¬ify_pbm_gpuoff_work);
|
|
else
|
|
_mt_gpufreq_kick_pbm(1);
|
|
} else {
|
|
schedule_delayed_work(¬ify_pbm_gpuoff_work, msecs_to_jiffies(GPU_OFF_SETTLE_TIME_MS));
|
|
}
|
|
|
|
#endif
|
|
|
|
mt_gpufreq_volt_enable_state = enable;
|
|
SET_EXIT:
|
|
gpufreq_dbg("[Figo][-]@%s: enable = %d, mt_gpufreq_volt_enable_state = %d\n",
|
|
__func__, enable, mt_gpufreq_volt_enable_state);
|
|
mutex_unlock(&mt_gpufreq_lock);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(mt_gpufreq_voltage_enable_set);
|
|
|
|
|
|
/* Set VPROC enable/disable when GPU clock be switched on/off */
|
|
unsigned int mt_gpufreq_voltage_lpm_set(unsigned int enable_lpm)
|
|
{
|
|
int ret = 0;
|
|
|
|
mutex_lock(&mt_gpufreq_lock);
|
|
|
|
gpufreq_dbg("[Figo][+]@%s: enable_lpm = %d, mt_gpufreq_volt_enable_state = %d\n",
|
|
__func__, enable_lpm, mt_gpufreq_volt_enable_state);
|
|
|
|
if (mt_gpufreq_ready == false) {
|
|
gpufreq_pr_warn("@%s: GPU DVFS not ready!\n", __func__);
|
|
ret = DRIVER_NOT_READY;
|
|
goto SET_LPM_EXIT;
|
|
}
|
|
|
|
{
|
|
#ifdef VCORE_DVFS_OPP_SUPPORT
|
|
if (enable_lpm) {
|
|
if (!mt_gpufreq_ptpod_disable)
|
|
ret = vcorefs_request_dvfs_opp(KIR_GPU, OPP_UNREQ);
|
|
} else {
|
|
switch (g_cur_gpu_volt) {
|
|
case GPU_DVFS_VOLT0:
|
|
ret = vcorefs_request_dvfs_opp(KIR_GPU, OPP_0);
|
|
break;
|
|
case GPU_DVFS_VOLT1:
|
|
ret = vcorefs_request_dvfs_opp(KIR_GPU, OPP_1);
|
|
break;
|
|
case GPU_DVFS_VOLT2:
|
|
ret = vcorefs_request_dvfs_opp(KIR_GPU, OPP_2);
|
|
break;
|
|
case GPU_DVFS_VOLT3:
|
|
ret = vcorefs_request_dvfs_opp(KIR_GPU, OPP_3);
|
|
break;
|
|
default:
|
|
gpufreq_pr_warn("@%s: ummapped voltage! volt %d\n", __func__, g_cur_gpu_volt);
|
|
break;
|
|
}
|
|
}
|
|
if (ret)
|
|
gpufreq_pr_warn("@%s: vcorefs_request_dvfs_opp fail! volt %d\n", __func__, g_cur_gpu_volt);
|
|
#else
|
|
gpufreq_dbg("@%s: VCORE_DVFS_OPP_SUPPORT not defined!, need to implement it by PMIC\n",
|
|
__func__);
|
|
#endif
|
|
}
|
|
|
|
if (enable_lpm)
|
|
mt_gpufreq_volt_enable_state = 0;
|
|
else
|
|
mt_gpufreq_volt_enable_state = 1;
|
|
|
|
SET_LPM_EXIT:
|
|
gpufreq_dbg("[Figo][-]@%s: enable_lpm = %d, mt_gpufreq_volt_enable_state = %d\n",
|
|
__func__, enable_lpm, mt_gpufreq_volt_enable_state);
|
|
mutex_unlock(&mt_gpufreq_lock);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(mt_gpufreq_voltage_lpm_set);
|
|
|
|
/************************************************
|
|
* DVFS enable API for PTPOD
|
|
*************************************************/
|
|
|
|
void mt_gpufreq_enable_by_ptpod(void)
|
|
{
|
|
#ifdef VOLT_SET_READY
|
|
gpufreq_dbg("[Figo] Power off by mt_gpufreq_enable_by_ptpod\n");
|
|
mt_gpufreq_voltage_enable_set(0);
|
|
#endif
|
|
|
|
mt_gpufreq_ptpod_disable = false;
|
|
gpufreq_info("mt_gpufreq enabled by ptpod\n");
|
|
}
|
|
EXPORT_SYMBOL(mt_gpufreq_enable_by_ptpod);
|
|
|
|
/************************************************
|
|
* DVFS disable API for PTPOD
|
|
*************************************************/
|
|
void mt_gpufreq_disable_by_ptpod(void)
|
|
{
|
|
int i = 0, target_idx = 0;
|
|
|
|
if (mt_gpufreq_ready == false) {
|
|
/*gpufreq_pr_warn("@%s: GPU DVFS not ready!\n", __func__);*/
|
|
return;
|
|
}
|
|
|
|
mt_gpufreq_ptpod_disable = true;
|
|
mt_gpufreq_voltage_lpm_set(0);
|
|
gpufreq_info("mt_gpufreq disabled by ptpod\n");
|
|
|
|
for (i = 0; i < mt_gpufreqs_num; i++) {
|
|
target_idx = i;
|
|
if (mt_gpufreqs_default[i].gpufreq_volt <= GPU_DVFS_PTPOD_DISABLE_VOLT)
|
|
break;
|
|
}
|
|
|
|
mt_gpufreq_ptpod_disable_idx = target_idx;
|
|
|
|
#ifdef VOLT_SET_READY
|
|
gpufreq_dbg("[Figo] Power on by mt_gpufreq_disable_by_ptpod\n");
|
|
mt_gpufreq_voltage_enable_set(1);
|
|
#endif
|
|
mt_gpufreq_target(target_idx);
|
|
}
|
|
EXPORT_SYMBOL(mt_gpufreq_disable_by_ptpod);
|
|
|
|
/************************************************
|
|
* API to switch back default voltage setting for GPU PTPOD disabled
|
|
*************************************************/
|
|
void mt_gpufreq_restore_default_volt(void)
|
|
{
|
|
int i;
|
|
|
|
if (mt_gpufreq_ready == false) {
|
|
/*gpufreq_pr_warn("@%s: GPU DVFS not ready!\n", __func__);*/
|
|
return;
|
|
}
|
|
|
|
mutex_lock(&mt_gpufreq_lock);
|
|
|
|
for (i = 0; i < mt_gpufreqs_num; i++) {
|
|
mt_gpufreqs[i].gpufreq_volt = mt_gpufreqs_default[i].gpufreq_volt;
|
|
gpufreq_dbg("@%s: mt_gpufreqs[%d].gpufreq_volt = %x\n", __func__, i,
|
|
mt_gpufreqs[i].gpufreq_volt);
|
|
}
|
|
|
|
/* Use VCORE for power Control */
|
|
mt_gpufreq_volt_switch(g_cur_gpu_volt, mt_gpufreqs[g_cur_gpu_OPPidx].gpufreq_volt);
|
|
|
|
g_cur_gpu_volt = mt_gpufreqs[g_cur_gpu_OPPidx].gpufreq_volt;
|
|
|
|
mutex_unlock(&mt_gpufreq_lock);
|
|
}
|
|
EXPORT_SYMBOL(mt_gpufreq_restore_default_volt);
|
|
|
|
/* Set voltage because PTP-OD modified voltage table by PMIC wrapper */
|
|
unsigned int mt_gpufreq_update_volt(unsigned int pmic_volt[], unsigned int array_size)
|
|
{
|
|
int i; /* , idx; */
|
|
/* unsigned long flags; */
|
|
|
|
if (mt_gpufreq_ready == false) {
|
|
/*gpufreq_pr_warn("@%s: GPU DVFS not ready!\n", __func__);*/
|
|
return DRIVER_NOT_READY;
|
|
}
|
|
|
|
mutex_lock(&mt_gpufreq_lock);
|
|
|
|
for (i = 0; i < array_size; i++) {
|
|
mt_gpufreqs[i].gpufreq_volt = pmic_volt[i];
|
|
gpufreq_dbg("@%s: mt_gpufreqs[%d].gpufreq_volt = %d\n", __func__, i,
|
|
mt_gpufreqs[i].gpufreq_volt);
|
|
}
|
|
|
|
/* Use VCORE for power Control */
|
|
mt_gpufreq_volt_switch(g_cur_gpu_volt, mt_gpufreqs[g_cur_gpu_OPPidx].gpufreq_volt);
|
|
|
|
g_cur_gpu_volt = mt_gpufreqs[g_cur_gpu_OPPidx].gpufreq_volt;
|
|
if (g_pGpufreq_ptpod_update_notify != NULL)
|
|
g_pGpufreq_ptpod_update_notify();
|
|
mutex_unlock(&mt_gpufreq_lock);
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(mt_gpufreq_update_volt);
|
|
|
|
unsigned int mt_gpufreq_get_dvfs_table_num(void)
|
|
{
|
|
return mt_gpufreqs_num;
|
|
}
|
|
EXPORT_SYMBOL(mt_gpufreq_get_dvfs_table_num);
|
|
|
|
unsigned int mt_gpufreq_get_freq_by_idx(unsigned int idx)
|
|
{
|
|
if (mt_gpufreq_ready == false) {
|
|
/*gpufreq_pr_warn("@%s: GPU DVFS not ready!\n", __func__);*/
|
|
return DRIVER_NOT_READY;
|
|
}
|
|
|
|
if (idx < mt_gpufreqs_num) {
|
|
gpufreq_dbg("@%s: idx = %d, frequency= %d\n", __func__, idx,
|
|
mt_gpufreqs[idx].gpufreq_khz);
|
|
return mt_gpufreqs[idx].gpufreq_khz;
|
|
}
|
|
|
|
gpufreq_dbg("@%s: idx = %d, NOT found! return 0!\n", __func__, idx);
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(mt_gpufreq_get_freq_by_idx);
|
|
|
|
int mt_gpufreq_get_idx_by_target_freq(unsigned int target_freq)
|
|
{
|
|
int i = mt_gpufreqs_num - 1;
|
|
|
|
gpufreq_dbg("@%s: freq = %u\n", __func__, target_freq);
|
|
while (i >= 0) {
|
|
if (mt_gpufreqs[i--].gpufreq_khz >= target_freq)
|
|
goto TARGET_EXIT;
|
|
}
|
|
|
|
TARGET_EXIT:
|
|
gpufreq_pr_err("@%s: idx = %u\n", __func__, i+1);
|
|
return i+1;
|
|
}
|
|
|
|
unsigned int mt_gpufreq_get_volt_by_idx(unsigned int idx)
|
|
{
|
|
if (mt_gpufreq_ready == false) {
|
|
/*gpufreq_pr_warn("@%s: GPU DVFS not ready!\n", __func__);*/
|
|
return DRIVER_NOT_READY;
|
|
}
|
|
|
|
if (idx < mt_gpufreqs_num) {
|
|
gpufreq_dbg("@%s: idx = %d, voltage= %d\n", __func__, idx,
|
|
mt_gpufreqs[idx].gpufreq_volt);
|
|
return mt_gpufreqs[idx].gpufreq_volt;
|
|
}
|
|
|
|
gpufreq_dbg("@%s: idx = %d, NOT found! return 0!\n", __func__, idx);
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(mt_gpufreq_get_volt_by_idx);
|
|
|
|
#ifdef MT_GPUFREQ_DYNAMIC_POWER_TABLE_UPDATE
|
|
static void mt_update_gpufreqs_power_table(void)
|
|
{
|
|
int i = 0;
|
|
int temp = 0;
|
|
unsigned int freq = 0, volt = 0;
|
|
|
|
if (mt_gpufreq_ready == false) {
|
|
gpufreq_pr_warn("@%s: GPU DVFS not ready\n", __func__);
|
|
return;
|
|
}
|
|
|
|
#ifdef CONFIG_THERMAL
|
|
temp = get_immediate_gpu_wrap() / 1000;
|
|
#else
|
|
temp = 40;
|
|
#endif
|
|
|
|
gpufreq_dbg("@%s, temp = %d\n", __func__, temp);
|
|
|
|
mutex_lock(&mt_gpufreq_lock);
|
|
|
|
if ((temp >= -20) && (temp <= 125)) {
|
|
for (i = 0; i < mt_gpufreqs_num; i++) {
|
|
freq = mt_gpufreqs_power[i].gpufreq_khz;
|
|
volt = mt_gpufreqs_power[i].gpufreq_volt;
|
|
|
|
mt_gpufreq_power_calculation(i, freq, volt, temp);
|
|
|
|
gpufreq_ver("update mt_gpufreqs_power[%d].gpufreq_khz = %d\n", i,
|
|
mt_gpufreqs_power[i].gpufreq_khz);
|
|
gpufreq_ver("update mt_gpufreqs_power[%d].gpufreq_volt = %d\n", i,
|
|
mt_gpufreqs_power[i].gpufreq_volt);
|
|
gpufreq_ver("update mt_gpufreqs_power[%d].gpufreq_power = %d\n", i,
|
|
mt_gpufreqs_power[i].gpufreq_power);
|
|
}
|
|
} else
|
|
gpufreq_pr_err("@%s: temp < 0 or temp > 125, NOT update power table!\n", __func__);
|
|
|
|
mutex_unlock(&mt_gpufreq_lock);
|
|
}
|
|
#endif
|
|
|
|
static void mt_setup_gpufreqs_power_table(int num)
|
|
{
|
|
int i = 0, temp = 0;
|
|
|
|
mt_gpufreqs_power = kzalloc((num) * sizeof(struct mt_gpufreq_power_table_info), GFP_KERNEL);
|
|
if (mt_gpufreqs_power == NULL)
|
|
return;
|
|
#ifdef CONFIG_THERMAL
|
|
temp = get_immediate_gpu_wrap() / 1000;
|
|
#else
|
|
temp = 40;
|
|
#endif
|
|
|
|
gpufreq_dbg("@%s: temp = %d\n", __func__, temp);
|
|
|
|
if ((temp < -20) || (temp > 125)) {
|
|
gpufreq_dbg("@%s: temp < 0 or temp > 125!\n", __func__);
|
|
temp = 65;
|
|
}
|
|
|
|
for (i = 0; i < num; i++) {
|
|
/* fill-in freq and volt in power table */
|
|
mt_gpufreqs_power[i].gpufreq_khz = mt_gpufreqs[i].gpufreq_khz;
|
|
mt_gpufreqs_power[i].gpufreq_volt = mt_gpufreqs[i].gpufreq_volt;
|
|
|
|
mt_gpufreq_power_calculation(i,
|
|
mt_gpufreqs_power[i].gpufreq_khz,
|
|
mt_gpufreqs_power[i].gpufreq_volt,
|
|
temp);
|
|
|
|
gpufreq_info("mt_gpufreqs_power[%d].gpufreq_khz = %u\n", i,
|
|
mt_gpufreqs_power[i].gpufreq_khz);
|
|
gpufreq_info("mt_gpufreqs_power[%d].gpufreq_volt = %u\n", i,
|
|
mt_gpufreqs_power[i].gpufreq_volt);
|
|
gpufreq_info("mt_gpufreqs_power[%d].gpufreq_power = %u\n", i,
|
|
mt_gpufreqs_power[i].gpufreq_power);
|
|
}
|
|
|
|
#ifdef CONFIG_THERMAL
|
|
mtk_gpufreq_register(mt_gpufreqs_power, num);
|
|
#endif
|
|
}
|
|
|
|
/***********************************************
|
|
* register frequency table to gpufreq subsystem
|
|
************************************************/
|
|
static int mt_setup_gpufreqs_table(struct mt_gpufreq_table_info *freqs, int num)
|
|
{
|
|
int i = 0;
|
|
|
|
mt_gpufreqs = kzalloc((num) * sizeof(*freqs), GFP_KERNEL);
|
|
mt_gpufreqs_default = kzalloc((num) * sizeof(*freqs), GFP_KERNEL);
|
|
if (mt_gpufreqs == NULL)
|
|
return -ENOMEM;
|
|
|
|
for (i = 0; i < num; i++) {
|
|
mt_gpufreqs[i].gpufreq_khz = freqs[i].gpufreq_khz;
|
|
mt_gpufreqs[i].gpufreq_volt = freqs[i].gpufreq_volt;
|
|
mt_gpufreqs[i].gpufreq_vsram = freqs[i].gpufreq_vsram;
|
|
mt_gpufreqs[i].gpufreq_idx = freqs[i].gpufreq_idx;
|
|
|
|
mt_gpufreqs_default[i].gpufreq_khz = freqs[i].gpufreq_khz;
|
|
mt_gpufreqs_default[i].gpufreq_volt = freqs[i].gpufreq_volt;
|
|
mt_gpufreqs_default[i].gpufreq_vsram = freqs[i].gpufreq_vsram;
|
|
mt_gpufreqs_default[i].gpufreq_idx = freqs[i].gpufreq_idx;
|
|
|
|
gpufreq_dbg("freqs[%d].gpufreq_khz = %u\n", i, freqs[i].gpufreq_khz);
|
|
gpufreq_dbg("freqs[%d].gpufreq_volt = %u\n", i, freqs[i].gpufreq_volt);
|
|
gpufreq_dbg("freqs[%d].gpufreq_vsram = %u\n", i, freqs[i].gpufreq_vsram);
|
|
gpufreq_dbg("freqs[%d].gpufreq_idx = %u\n", i, freqs[i].gpufreq_idx);
|
|
}
|
|
|
|
mt_gpufreqs_num = num;
|
|
|
|
g_limited_max_id = 0;
|
|
g_limited_min_id = mt_gpufreqs_num - 1;
|
|
|
|
gpufreq_info("@%s: g_cur_gpu_freq = %d, g_cur_gpu_volt = %d\n", __func__, g_cur_gpu_freq,
|
|
g_cur_gpu_volt);
|
|
|
|
mt_setup_gpufreqs_power_table(num);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**************************************
|
|
* check if maximum frequency is needed
|
|
***************************************/
|
|
static int mt_gpufreq_keep_max_freq(unsigned int freq_old, unsigned int freq_new)
|
|
{
|
|
if (mt_gpufreq_keep_max_frequency_state == true)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************
|
|
* set GPU DVFS status
|
|
******************************/
|
|
int mt_gpufreq_state_set(int enabled)
|
|
{
|
|
if (enabled) {
|
|
if (!mt_gpufreq_pause) {
|
|
gpufreq_dbg("gpufreq already enabled\n");
|
|
return 0;
|
|
}
|
|
|
|
/*****************
|
|
* enable GPU DVFS
|
|
******************/
|
|
g_gpufreq_dvfs_disable_count--;
|
|
gpufreq_dbg("enable GPU DVFS: g_gpufreq_dvfs_disable_count = %d\n",
|
|
g_gpufreq_dvfs_disable_count);
|
|
|
|
/***********************************************
|
|
* enable DVFS if no any module still disable it
|
|
************************************************/
|
|
if (g_gpufreq_dvfs_disable_count <= 0)
|
|
mt_gpufreq_pause = false;
|
|
else
|
|
gpufreq_pr_warn("someone still disable gpufreq, cannot enable it\n");
|
|
} else {
|
|
/******************
|
|
* disable GPU DVFS
|
|
*******************/
|
|
g_gpufreq_dvfs_disable_count++;
|
|
gpufreq_dbg("disable GPU DVFS: g_gpufreq_dvfs_disable_count = %d\n",
|
|
g_gpufreq_dvfs_disable_count);
|
|
|
|
if (mt_gpufreq_pause) {
|
|
gpufreq_dbg("gpufreq already disabled\n");
|
|
return 0;
|
|
}
|
|
|
|
mt_gpufreq_pause = true;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(mt_gpufreq_state_set);
|
|
|
|
|
|
static unsigned int mt_gpufreq_dds_calc(unsigned int freq_khz, enum post_div_order_enum post_div_order)
|
|
{
|
|
unsigned int dds = 0;
|
|
|
|
gpufreq_dbg("@%s: request freq = %d, div_order = %d\n",
|
|
__func__, freq_khz, post_div_order);
|
|
/*
|
|
* Below freq range is Austin @ mt6739 only:
|
|
*
|
|
* dds formula is consistent with Elbrus
|
|
*
|
|
*/
|
|
if ((freq_khz >= GPUFREQ_LAST_FREQ_LEVEL) && (freq_khz <= GPU_DVFS_FREQ0_6739TW)) {
|
|
dds = (((freq_khz / TO_MHz_HEAD * (1 << post_div_order)) << DDS_SHIFT)
|
|
/ GPUPLL_FIN + ROUNDING_VALUE) / TO_MHz_TAIL;
|
|
} else {
|
|
gpufreq_pr_err("@%s: target freq_khz(%d) out of range!\n", __func__, freq_khz);
|
|
/* WARN_ON(); */
|
|
}
|
|
|
|
return dds;
|
|
}
|
|
|
|
|
|
static void mt_gpufreq_clock_switch_transient(unsigned int freq_new, enum post_div_order_enum post_div_order)
|
|
{
|
|
unsigned int cur_volt;
|
|
unsigned int cur_freq;
|
|
unsigned int dds;
|
|
|
|
/* GPUPLL_CON1: 31: MMPLL_SDM_PCW_CHG
|
|
* 26-24: GPUPLL_POSDIV
|
|
* 000: /1
|
|
* 001: /2
|
|
* 010: /4
|
|
* 011: /8
|
|
* 100: /18
|
|
* 21-0:MMPLL_SDM_PCW
|
|
*/
|
|
|
|
cur_volt = _mt_gpufreq_get_cur_volt();
|
|
cur_freq = _mt_gpufreq_get_cur_freq();
|
|
dds = mt_gpufreq_dds_calc(freq_new, post_div_order);
|
|
gpufreq_dbg("@%s: request GPU dds = 0x%x, cur_volt = %d, cur_freq = %d\n",
|
|
__func__, dds, cur_volt, cur_freq);
|
|
|
|
gpufreq_dbg("@%s: request GPUPLL_CON1 = 0x%x\n",
|
|
__func__, DRV_Reg32(GPUPLL_CON1));
|
|
|
|
/* Step2. Modify gpupll_ck */
|
|
#ifdef FHCTL_READY
|
|
mt_dfs_general_pll(FH_PLL3, dds);
|
|
#endif
|
|
|
|
}
|
|
|
|
/* static void _mt_gpufreq_set_cur_freq(unsigned int freq_new) */
|
|
static void mt_gpufreq_clock_switch(unsigned int freq_new)
|
|
{
|
|
unsigned int mfgpll;
|
|
|
|
if (mt_gpufreq_dvfs_table_cid == 0)
|
|
mt_gpufreq_clock_switch_transient(freq_new, _get_post_div_order(freq_new, mt_gpufreq_dvfs_table_cid));
|
|
else
|
|
gpufreq_dbg("@%s: efuse number type(%d)\n", __func__, mt_gpufreq_dvfs_table_cid);
|
|
|
|
mfgpll = DRV_Reg32(GPUPLL_CON1);
|
|
gpufreq_dbg("@%s: freq_new = %d, mfgpll = 0x%x\n", __func__, freq_new, mfgpll);
|
|
if (g_pFreqSampler != NULL)
|
|
g_pFreqSampler(freq_new);
|
|
}
|
|
|
|
#if 0
|
|
static int mt_gpufreq_get_idx_by_target_volt(unsigned int target_volt)
|
|
{
|
|
int i = mt_gpufreqs_num - 1;
|
|
|
|
while (i >= 0) {
|
|
if (mt_gpufreqs[i--].gpufreq_volt >= target_volt)
|
|
goto TARGET_EXIT;
|
|
}
|
|
|
|
TARGET_EXIT:
|
|
return i+1;
|
|
}
|
|
#endif
|
|
|
|
#ifndef VCORE_DVFS_OPP_SUPPORT
|
|
static unsigned int _calculate_vproc_sfchg_rate(bool isRising)
|
|
{
|
|
unsigned int sfchg_rate_reg;
|
|
unsigned int sfchg_rate_vproc;
|
|
|
|
/* [MT6739] RG_LDO_VSRAM_PROC_SFCHG_RRATE (rising rate) and RG_LDO_VSRAM_PROC_SFCHG_FRATE (falling rate)
|
|
* 4: 0.19us
|
|
* 8: 0.34us
|
|
* 11: 0.46us
|
|
* 17: 0.69us
|
|
* 23: 0.92us
|
|
* 25: 1us
|
|
*/
|
|
if (isRising) {
|
|
pmic_read_interface(MT6356_BUCK_VPROC_CFG0, &sfchg_rate_reg,
|
|
PMIC_RG_BUCK_VPROC_SFCHG_RRATE_MASK, PMIC_RG_BUCK_VPROC_SFCHG_RRATE_SHIFT);
|
|
} else {
|
|
pmic_read_interface(MT6356_BUCK_VPROC_CFG0, &sfchg_rate_reg,
|
|
PMIC_RG_BUCK_VPROC_SFCHG_FRATE_MASK, PMIC_RG_BUCK_VPROC_SFCHG_FRATE_SHIFT);
|
|
}
|
|
|
|
sfchg_rate_vproc = 1;
|
|
|
|
gpufreq_dbg("@%s: isRising(%d), sfchg_rate_vproc = %d, sfchg_rate_reg = %x\n",
|
|
__func__, isRising, sfchg_rate_vproc, sfchg_rate_reg);
|
|
|
|
return sfchg_rate_vproc;
|
|
}
|
|
static unsigned int _calculate_vsram_sfchg_rate(bool isRising)
|
|
{
|
|
unsigned int sfchg_rate_reg;
|
|
unsigned int sfchg_rate_vsram;
|
|
|
|
/* [MT6739] RG_LDO_VSRAM_GPU_SFCHG_RRATE and RG_LDO_VSRAM_GPU_SFCHG_FRATE
|
|
* 4: 0.19us
|
|
* 8: 0.34us
|
|
* 11: 0.46us
|
|
* 17: 0.69us
|
|
* 23: 0.92us
|
|
* 25: 1us
|
|
*/
|
|
|
|
if (isRising) {
|
|
pmic_read_interface(MT6356_LDO_VSRAM_GPU_CFG0, &sfchg_rate_reg,
|
|
PMIC_RG_LDO_VSRAM_GPU_SFCHG_RRATE_MASK, PMIC_RG_LDO_VSRAM_GPU_SFCHG_RRATE_SHIFT);
|
|
sfchg_rate_vsram = 1;
|
|
} else {
|
|
pmic_read_interface(MT6356_LDO_VSRAM_GPU_CFG0, &sfchg_rate_reg,
|
|
PMIC_RG_LDO_VSRAM_GPU_SFCHG_FRATE_MASK, PMIC_RG_LDO_VSRAM_GPU_SFCHG_FRATE_SHIFT);
|
|
sfchg_rate_vsram = 1;
|
|
}
|
|
|
|
gpufreq_dbg("@%s: isRising(%d), sfchg_rate_vsram = %d, sfchg_rate_reg = %x\n",
|
|
__func__, isRising, sfchg_rate_vsram, sfchg_rate_reg);
|
|
|
|
return sfchg_rate_vsram;
|
|
}
|
|
#endif
|
|
|
|
|
|
static void mt_gpufreq_volt_switch(unsigned int volt_old, unsigned int volt_new)
|
|
{
|
|
#ifdef VCORE_DVFS_OPP_SUPPORT
|
|
if (volt_new != volt_old) {
|
|
int ret = 0;
|
|
|
|
switch (volt_new) {
|
|
case GPU_DVFS_VOLT0:
|
|
ret = vcorefs_request_dvfs_opp(KIR_GPU, OPP_0);
|
|
break;
|
|
case GPU_DVFS_VOLT1:
|
|
ret = vcorefs_request_dvfs_opp(KIR_GPU, OPP_1);
|
|
break;
|
|
case GPU_DVFS_VOLT2:
|
|
ret = vcorefs_request_dvfs_opp(KIR_GPU, OPP_2);
|
|
break;
|
|
case GPU_DVFS_VOLT3:
|
|
ret = vcorefs_request_dvfs_opp(KIR_GPU, OPP_3);
|
|
break;
|
|
default:
|
|
gpufreq_pr_warn("@%s: ummapped voltage! volt %d\n", __func__, volt_new);
|
|
break;
|
|
}
|
|
if (ret)
|
|
gpufreq_pr_warn("@%s: vcorefs_request_dvfs_opp fail! volt %d\n", __func__, volt_new);
|
|
}
|
|
#else
|
|
gpufreq_dbg("@%s: VCORE_DVFS_OPP_SUPPORT not defined!, need to implement it by PMIC\n",
|
|
__func__);
|
|
#endif
|
|
}
|
|
|
|
static unsigned int _mt_gpufreq_get_cur_freq(void)
|
|
{
|
|
unsigned long mfgpll = 0;
|
|
unsigned int post_div_order = 0;
|
|
unsigned int freq_khz = 0;
|
|
unsigned long dds;
|
|
|
|
mfgpll = DRV_Reg32(GPUPLL_CON1);
|
|
post_div_order = (mfgpll & (0x7 << POST_DIV_SHIFT)) >> POST_DIV_SHIFT;
|
|
|
|
/*
|
|
* become dds
|
|
*/
|
|
dds = mfgpll & (0x3FFFFF);
|
|
|
|
freq_khz = (((dds * TO_MHz_TAIL + ROUNDING_VALUE)*GPUPLL_FIN) >> DDS_SHIFT)
|
|
/ (1 << post_div_order) * TO_MHz_HEAD;
|
|
|
|
if (freq_khz < DIV4_MIN_FREQ || freq_khz > DIV4_MAX_FREQ)
|
|
gpufreq_pr_err("Invalid out-of-bound freq %d KHz, mfgpll value = 0x%lx\n",
|
|
freq_khz, mfgpll);
|
|
else
|
|
gpufreq_dbg("mfgpll = 0x%lx, freq = %d KHz, div_order = %d\n",
|
|
mfgpll, freq_khz, post_div_order);
|
|
|
|
return freq_khz; /* KHz */
|
|
}
|
|
|
|
static unsigned int _mt_gpufreq_get_cur_volt(void)
|
|
{
|
|
unsigned int gpu_volt = 0;
|
|
{
|
|
gpu_volt = regulator_get_voltage(mt_gpufreq_pmic->reg_vcore) / 10;
|
|
gpufreq_dbg("gpu_dvfs_get_cur_volt:[PMIC] volt = %d\n", gpu_volt);
|
|
}
|
|
|
|
return gpu_volt;
|
|
}
|
|
|
|
static void _mt_gpufreq_kick_pbm(int enable)
|
|
{
|
|
#ifndef DISABLE_PBM_FEATURE
|
|
static unsigned int power;
|
|
static unsigned int cur_volt;
|
|
int i;
|
|
int tmp_idx = -1;
|
|
unsigned int found = 0;
|
|
unsigned int cur_freq = _mt_gpufreq_get_cur_freq();
|
|
|
|
cur_volt = _mt_gpufreq_get_cur_volt();
|
|
|
|
if (enable) {
|
|
for (i = 0; i < mt_gpufreqs_num; i++) {
|
|
if (mt_gpufreqs_power[i].gpufreq_khz == cur_freq) {
|
|
/* record idx since current voltage may not in DVFS table */
|
|
tmp_idx = i;
|
|
|
|
if (mt_gpufreqs_power[i].gpufreq_volt == cur_volt) {
|
|
power = mt_gpufreqs_power[i].gpufreq_power;
|
|
found = 1;
|
|
kicker_pbm_by_gpu(true, power, cur_volt / 100);
|
|
gpufreq_dbg
|
|
("@%s: request GPU power = %d, cur_volt = %d, cur_freq = %d\n",
|
|
__func__, power, cur_volt / 100, cur_freq);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
gpufreq_dbg("@%s: tmp_idx = %d\n", __func__, tmp_idx);
|
|
|
|
if (tmp_idx != -1 && tmp_idx < mt_gpufreqs_num) {
|
|
/* use freq to found corresponding power budget */
|
|
power = mt_gpufreqs_power[tmp_idx].gpufreq_power;
|
|
kicker_pbm_by_gpu(true, power, cur_volt / 100);
|
|
gpufreq_dbg
|
|
("@%s: request GPU power = %d, cur_volt = %d, cur_freq = %d\n",
|
|
__func__, power, cur_volt / 100, cur_freq);
|
|
} else {
|
|
gpufreq_pr_warn("@%s: Cannot found request power in power table!\n",
|
|
__func__);
|
|
gpufreq_pr_warn("cur_freq = %dKHz, cur_volt = %dmV\n", cur_freq,
|
|
cur_volt / 100);
|
|
}
|
|
}
|
|
} else {
|
|
kicker_pbm_by_gpu(false, 0, cur_volt / 100);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*****************************************
|
|
* frequency ramp up and ramp down handler
|
|
******************************************/
|
|
/***********************************************************
|
|
* [note]
|
|
* 1. frequency ramp up need to wait voltage settle
|
|
* 2. frequency ramp down do not need to wait voltage settle
|
|
************************************************************/
|
|
static void mt_gpufreq_set(unsigned int freq_old, unsigned int freq_new,
|
|
unsigned int volt_old, unsigned int volt_new)
|
|
{
|
|
|
|
gpufreq_dbg("[Figo][+]@%s: Freq: %d ---> %d, Volt: %d ---> %d\n",
|
|
__func__, freq_old, freq_new, volt_old, volt_new);
|
|
if (freq_new > freq_old) {
|
|
mt_gpufreq_volt_switch(volt_old, volt_new);
|
|
mt_gpufreq_clock_switch(freq_new);
|
|
} else {
|
|
mt_gpufreq_clock_switch(freq_new);
|
|
mt_gpufreq_volt_switch(volt_old, volt_new);
|
|
}
|
|
gpufreq_dbg("[Figo][-]@%s: Freq: %d ---> %d, Volt: %d ---> %d\n",
|
|
__func__, freq_old, freq_new, volt_old, volt_new);
|
|
gpufreq_dbg("[Figo][Status]@%s: freq:%d, volt:%d\n",
|
|
__func__, mt_get_ckgen_freq(7), _mt_gpufreq_get_cur_volt());
|
|
|
|
g_cur_gpu_freq = freq_new;
|
|
g_cur_gpu_volt = volt_new;
|
|
|
|
_mt_gpufreq_kick_pbm(1);
|
|
}
|
|
|
|
/**********************************
|
|
* gpufreq target callback function
|
|
***********************************/
|
|
/*************************************************
|
|
* [note]
|
|
* 1. handle frequency change request
|
|
* 2. call mt_gpufreq_set to set target frequency
|
|
**************************************************/
|
|
unsigned int mt_gpufreq_target(unsigned int idx)
|
|
{
|
|
/* unsigned long flags; */
|
|
unsigned int target_freq, target_volt, target_idx, target_OPPidx;
|
|
|
|
#ifdef MT_GPUFREQ_PERFORMANCE_TEST
|
|
return 0;
|
|
#endif
|
|
|
|
mutex_lock(&mt_gpufreq_lock);
|
|
|
|
if (mt_gpufreq_pause == true) {
|
|
gpufreq_pr_warn("GPU DVFS pause!\n");
|
|
mutex_unlock(&mt_gpufreq_lock);
|
|
return DRIVER_NOT_READY;
|
|
}
|
|
|
|
if (mt_gpufreq_ready == false) {
|
|
gpufreq_pr_warn("GPU DVFS not ready!\n");
|
|
mutex_unlock(&mt_gpufreq_lock);
|
|
return DRIVER_NOT_READY;
|
|
}
|
|
|
|
if (mt_gpufreq_volt_enable_state == 0) {
|
|
gpufreq_dbg("mt_gpufreq_volt_enable_state == 0! return\n");
|
|
mutex_unlock(&mt_gpufreq_lock);
|
|
return DRIVER_NOT_READY;
|
|
}
|
|
#ifdef MT_GPU_DVFS_RANDOM_TEST
|
|
idx = mt_gpufreq_idx_get(5);
|
|
gpufreq_dbg("@%s: random test index is %d !\n", __func__, idx);
|
|
#endif
|
|
|
|
if (idx > (mt_gpufreqs_num - 1)) {
|
|
mutex_unlock(&mt_gpufreq_lock);
|
|
gpufreq_pr_err("@%s: idx out of range! idx = %d\n", __func__, idx);
|
|
return -1;
|
|
}
|
|
|
|
/**********************************
|
|
* look up for the target GPU OPP
|
|
***********************************/
|
|
target_freq = mt_gpufreqs[idx].gpufreq_khz;
|
|
target_volt = mt_gpufreqs[idx].gpufreq_volt;
|
|
target_idx = mt_gpufreqs[idx].gpufreq_idx;
|
|
target_OPPidx = idx;
|
|
|
|
gpufreq_dbg("@%s: begin, receive freq: %d, OPPidx: %d\n", __func__, target_freq,
|
|
target_OPPidx);
|
|
|
|
/**********************************
|
|
* Check if need to keep max frequency
|
|
***********************************/
|
|
if (mt_gpufreq_keep_max_freq(g_cur_gpu_freq, target_freq)) {
|
|
target_freq = mt_gpufreqs[g_gpufreq_max_id].gpufreq_khz;
|
|
target_volt = mt_gpufreqs[g_gpufreq_max_id].gpufreq_volt;
|
|
target_idx = mt_gpufreqs[g_gpufreq_max_id].gpufreq_idx;
|
|
target_OPPidx = g_gpufreq_max_id;
|
|
gpufreq_dbg("Keep MAX frequency %d !\n", target_freq);
|
|
}
|
|
|
|
/************************************************
|
|
* If /proc command keep opp frequency.
|
|
*************************************************/
|
|
if (mt_gpufreq_keep_opp_frequency_state == true) {
|
|
target_freq = mt_gpufreqs[mt_gpufreq_keep_opp_index].gpufreq_khz;
|
|
target_volt = mt_gpufreqs[mt_gpufreq_keep_opp_index].gpufreq_volt;
|
|
target_idx = mt_gpufreqs[mt_gpufreq_keep_opp_index].gpufreq_idx;
|
|
target_OPPidx = mt_gpufreq_keep_opp_index;
|
|
gpufreq_dbg("Keep opp! opp frequency %d, opp voltage %d, opp idx %d\n", target_freq,
|
|
target_volt, target_OPPidx);
|
|
}
|
|
|
|
/************************************************
|
|
* If /proc command fix the frequency.
|
|
*************************************************/
|
|
if (mt_gpufreq_fixed_freq_volt_state == true) {
|
|
target_freq = mt_gpufreq_fixed_frequency;
|
|
target_volt = mt_gpufreq_fixed_voltage;
|
|
target_idx = 0;
|
|
target_OPPidx = 0;
|
|
gpufreq_dbg("Fixed! fixed frequency %d, fixed voltage %d\n", target_freq,
|
|
target_volt);
|
|
}
|
|
|
|
/************************************************
|
|
* If /proc command keep opp max frequency.
|
|
*************************************************/
|
|
if (mt_gpufreq_opp_max_frequency_state == true) {
|
|
if (target_freq > mt_gpufreq_opp_max_frequency) {
|
|
target_freq = mt_gpufreqs[mt_gpufreq_opp_max_index].gpufreq_khz;
|
|
target_volt = mt_gpufreqs[mt_gpufreq_opp_max_index].gpufreq_volt;
|
|
target_idx = mt_gpufreqs[mt_gpufreq_opp_max_index].gpufreq_idx;
|
|
target_OPPidx = mt_gpufreq_opp_max_index;
|
|
|
|
gpufreq_dbg
|
|
("opp max freq! opp max frequency %d, opp max voltage %d, opp max idx %d\n",
|
|
target_freq, target_volt, target_OPPidx);
|
|
}
|
|
}
|
|
|
|
/************************************************
|
|
* PBM limit
|
|
*************************************************/
|
|
#ifndef DISABLE_PBM_FEATURE
|
|
if (mt_gpufreq_pbm_limited_index != 0) {
|
|
if (target_freq > mt_gpufreqs[mt_gpufreq_pbm_limited_index].gpufreq_khz) {
|
|
/*********************************************
|
|
* target_freq > limited_freq, need to adjust
|
|
**********************************************/
|
|
target_freq = mt_gpufreqs[mt_gpufreq_pbm_limited_index].gpufreq_khz;
|
|
target_volt = mt_gpufreqs[mt_gpufreq_pbm_limited_index].gpufreq_volt;
|
|
target_OPPidx = mt_gpufreq_pbm_limited_index;
|
|
gpufreq_dbg("Limit! Thermal/Power limit gpu frequency %d\n",
|
|
mt_gpufreqs[mt_gpufreq_pbm_limited_index].gpufreq_khz);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/************************************************
|
|
* Thermal/Power limit
|
|
*************************************************/
|
|
if (g_limited_max_id != 0) {
|
|
if (target_freq > mt_gpufreqs[g_limited_max_id].gpufreq_khz) {
|
|
/*********************************************
|
|
* target_freq > limited_freq, need to adjust
|
|
**********************************************/
|
|
target_freq = mt_gpufreqs[g_limited_max_id].gpufreq_khz;
|
|
target_volt = mt_gpufreqs[g_limited_max_id].gpufreq_volt;
|
|
target_idx = mt_gpufreqs[g_limited_max_id].gpufreq_idx;
|
|
target_OPPidx = g_limited_max_id;
|
|
gpufreq_info("Limit! Thermal/Power limit gpu frequency %d\n",
|
|
mt_gpufreqs[g_limited_max_id].gpufreq_khz);
|
|
}
|
|
}
|
|
|
|
/************************************************
|
|
* DVFS keep at max freq when PTPOD initial
|
|
*************************************************/
|
|
if (mt_gpufreq_ptpod_disable == true) {
|
|
#if 1
|
|
target_freq = mt_gpufreqs[mt_gpufreq_ptpod_disable_idx].gpufreq_khz;
|
|
target_volt = GPU_DVFS_PTPOD_DISABLE_VOLT;
|
|
target_idx = mt_gpufreqs[mt_gpufreq_ptpod_disable_idx].gpufreq_idx;
|
|
target_OPPidx = mt_gpufreq_ptpod_disable_idx;
|
|
gpufreq_dbg("PTPOD disable dvfs, mt_gpufreq_ptpod_disable_idx = %d\n",
|
|
mt_gpufreq_ptpod_disable_idx);
|
|
#else
|
|
mutex_unlock(&mt_gpufreq_lock);
|
|
gpufreq_dbg("PTPOD disable dvfs, return\n");
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
/************************************************
|
|
* target frequency == current frequency, skip it
|
|
*************************************************/
|
|
if (g_cur_gpu_freq == target_freq && g_cur_gpu_volt == target_volt) {
|
|
mutex_unlock(&mt_gpufreq_lock);
|
|
gpufreq_dbg("GPU frequency from %d KHz to %d KHz (skipped) due to same frequency\n",
|
|
g_cur_gpu_freq, target_freq);
|
|
return 0;
|
|
}
|
|
|
|
gpufreq_dbg("GPU current frequency %d KHz, target frequency %d KHz\n", g_cur_gpu_freq,
|
|
target_freq);
|
|
|
|
#ifdef MT_GPUFREQ_AEE_RR_REC
|
|
aee_rr_rec_gpu_dvfs_status(aee_rr_curr_gpu_dvfs_status() | (1 << GPU_DVFS_IS_DOING_DVFS));
|
|
aee_rr_rec_gpu_dvfs_oppidx(target_OPPidx);
|
|
#endif
|
|
|
|
/******************************
|
|
* set to the target frequency
|
|
*******************************/
|
|
mt_gpufreq_set(g_cur_gpu_freq, target_freq, g_cur_gpu_volt, target_volt);
|
|
|
|
g_cur_gpu_idx = target_idx;
|
|
g_cur_gpu_OPPidx = target_OPPidx;
|
|
|
|
#ifdef MT_GPUFREQ_AEE_RR_REC
|
|
aee_rr_rec_gpu_dvfs_status(aee_rr_curr_gpu_dvfs_status() & ~(1 << GPU_DVFS_IS_DOING_DVFS));
|
|
#endif
|
|
|
|
mutex_unlock(&mt_gpufreq_lock);
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(mt_gpufreq_target);
|
|
|
|
|
|
/********************************************
|
|
* POWER LIMIT RELATED
|
|
********************************************/
|
|
enum {
|
|
IDX_THERMAL_LIMITED,
|
|
IDX_LOW_BATT_VOLT_LIMITED,
|
|
IDX_LOW_BATT_VOLUME_LIMITED,
|
|
IDX_OC_LIMITED,
|
|
|
|
NR_IDX_POWER_LIMITED,
|
|
};
|
|
|
|
/* NO need to throttle when OC */
|
|
#ifdef MT_GPUFREQ_OC_PROTECT
|
|
static unsigned int mt_gpufreq_oc_level;
|
|
|
|
#define MT_GPUFREQ_OC_LIMIT_FREQ_1 GPUFREQ_LAST_FREQ_LEVEL /* < 485 MHz */
|
|
#define MT_GPUFREQ_OC_LIMIT_FREQ_1_6739TW GPUFREQ_LAST_FREQ_LEVEL_6739TW /* 530 MHz */
|
|
static unsigned int mt_gpufreq_oc_limited_index_0; /* unlimit frequency, index = 0. */
|
|
static unsigned int mt_gpufreq_oc_limited_index_1;
|
|
static unsigned int mt_gpufreq_oc_limited_index; /* Limited frequency index for oc */
|
|
#endif
|
|
|
|
#ifdef MT_GPUFREQ_LOW_BATT_VOLUME_PROTECT
|
|
static unsigned int mt_gpufreq_low_battery_volume;
|
|
|
|
#define MT_GPUFREQ_LOW_BATT_VOLUME_LIMIT_FREQ_1 GPU_DVFS_FREQ0
|
|
static unsigned int mt_gpufreq_low_bat_volume_limited_index_0; /* unlimit frequency, index = 0. */
|
|
static unsigned int mt_gpufreq_low_bat_volume_limited_index_1;
|
|
static unsigned int mt_gpufreq_low_batt_volume_limited_index; /* Limited frequency index for low battery volume */
|
|
#endif
|
|
|
|
#ifdef MT_GPUFREQ_LOW_BATT_VOLT_PROTECT
|
|
static unsigned int mt_gpufreq_low_battery_level;
|
|
|
|
#define MT_GPUFREQ_LOW_BATT_VOLT_LIMIT_FREQ_1 GPU_DVFS_FREQ0 /* no need to throttle when LV1 */
|
|
#define MT_GPUFREQ_LOW_BATT_VOLT_LIMIT_FREQ_2 GPUFREQ_LAST_FREQ_LEVEL /* 485 MHz */
|
|
#define MT_GPUFREQ_LOW_BATT_VOLT_LIMIT_FREQ_2_6739TW GPUFREQ_LAST_FREQ_LEVEL_6739TW /* 530 MHz */
|
|
static unsigned int mt_gpufreq_low_bat_volt_limited_index_0; /* unlimit frequency, index = 0. */
|
|
static unsigned int mt_gpufreq_low_bat_volt_limited_index_1;
|
|
static unsigned int mt_gpufreq_low_bat_volt_limited_index_2;
|
|
static unsigned int mt_gpufreq_low_batt_volt_limited_index; /* Limited frequency index for low battery voltage */
|
|
#endif
|
|
|
|
static unsigned int mt_gpufreq_thermal_limited_gpu_power; /* thermal limit power */
|
|
static unsigned int mt_gpufreq_prev_thermal_limited_freq; /* thermal limited freq */
|
|
/* limit frequency index array */
|
|
static unsigned int mt_gpufreq_power_limited_index_array[NR_IDX_POWER_LIMITED] = { 0 };
|
|
bool mt_gpufreq_power_limited_ignore[NR_IDX_POWER_LIMITED] = { false };
|
|
|
|
int mt_gpufreq_get_cur_ceiling_idx(void)
|
|
{
|
|
int limited_id = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < NR_IDX_POWER_LIMITED; i++) {
|
|
limited_id = mt_gpufreq_power_limited_index_array[i];
|
|
|
|
if (limited_id > g_limited_max_id) {
|
|
if (mt_gpufreq_power_limited_ignore[i] == false)
|
|
g_limited_max_id = limited_id;
|
|
}
|
|
}
|
|
|
|
limited_id = g_limited_max_id;
|
|
#ifndef DISABLE_PBM_FEATURE
|
|
if (mt_gpufreq_pbm_limited_index > limited_id)
|
|
limited_id = mt_gpufreq_pbm_limited_index;
|
|
#endif
|
|
return limited_id;
|
|
}
|
|
|
|
/************************************************
|
|
* frequency adjust interface for thermal protect
|
|
*************************************************/
|
|
/******************************************************
|
|
* parameter: target power
|
|
*******************************************************/
|
|
static int mt_gpufreq_power_throttle_protect(void)
|
|
{
|
|
int ret = 0;
|
|
int i = 0;
|
|
unsigned int limited_index = 0;
|
|
|
|
/* Check lowest frequency in all limitation */
|
|
for (i = 0; i < NR_IDX_POWER_LIMITED; i++) {
|
|
if (mt_gpufreq_power_limited_index_array[i] != 0 && limited_index == 0)
|
|
limited_index = mt_gpufreq_power_limited_index_array[i];
|
|
else if (mt_gpufreq_power_limited_index_array[i] != 0 && limited_index != 0) {
|
|
if (mt_gpufreq_power_limited_index_array[i] > limited_index)
|
|
limited_index = mt_gpufreq_power_limited_index_array[i];
|
|
}
|
|
}
|
|
|
|
g_limited_max_id = limited_index;
|
|
|
|
if (g_pGpufreq_power_limit_notify != NULL)
|
|
g_pGpufreq_power_limit_notify(g_limited_max_id);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifdef MT_GPUFREQ_OC_PROTECT
|
|
/************************************************
|
|
* GPU frequency adjust interface for oc protect
|
|
*************************************************/
|
|
static void mt_gpufreq_oc_protect(unsigned int limited_index)
|
|
{
|
|
mutex_lock(&mt_gpufreq_power_lock);
|
|
|
|
gpufreq_dbg("@%s: limited_index = %d\n", __func__, limited_index);
|
|
|
|
mt_gpufreq_power_limited_index_array[IDX_OC_LIMITED] = limited_index;
|
|
mt_gpufreq_power_throttle_protect();
|
|
|
|
mutex_unlock(&mt_gpufreq_power_lock);
|
|
}
|
|
|
|
void mt_gpufreq_oc_callback(BATTERY_OC_LEVEL oc_level)
|
|
{
|
|
gpufreq_dbg("@%s: oc_level = %d\n", __func__, oc_level);
|
|
|
|
if (mt_gpufreq_ready == false) {
|
|
/*gpufreq_pr_warn("@%s: GPU DVFS not ready!\n", __func__);*/
|
|
return;
|
|
}
|
|
|
|
if (g_limited_oc_ignore_state == true) {
|
|
gpufreq_info("@%s: g_limited_oc_ignore_state == true!\n", __func__);
|
|
return;
|
|
}
|
|
|
|
mt_gpufreq_oc_level = oc_level;
|
|
|
|
/* BATTERY_OC_LEVEL_1: >= 5.5A */
|
|
if (oc_level == BATTERY_OC_LEVEL_1) {
|
|
if (mt_gpufreq_oc_limited_index != mt_gpufreq_oc_limited_index_1) {
|
|
mt_gpufreq_oc_limited_index = mt_gpufreq_oc_limited_index_1;
|
|
mt_gpufreq_oc_protect(mt_gpufreq_oc_limited_index_1); /* Limit GPU 396.5Mhz */
|
|
}
|
|
}
|
|
/* unlimit gpu */
|
|
else {
|
|
if (mt_gpufreq_oc_limited_index != mt_gpufreq_oc_limited_index_0) {
|
|
mt_gpufreq_oc_limited_index = mt_gpufreq_oc_limited_index_0;
|
|
mt_gpufreq_oc_protect(mt_gpufreq_oc_limited_index_0); /* Unlimit */
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef MT_GPUFREQ_LOW_BATT_VOLUME_PROTECT
|
|
/************************************************
|
|
* GPU frequency adjust interface for low bat_volume protect
|
|
*************************************************/
|
|
static void mt_gpufreq_low_batt_volume_protect(unsigned int limited_index)
|
|
{
|
|
mutex_lock(&mt_gpufreq_power_lock);
|
|
|
|
gpufreq_dbg("@%s: limited_index = %d\n", __func__, limited_index);
|
|
|
|
mt_gpufreq_power_limited_index_array[IDX_LOW_BATT_VOLUME_LIMITED] = limited_index;
|
|
mt_gpufreq_power_throttle_protect();
|
|
|
|
mutex_unlock(&mt_gpufreq_power_lock);
|
|
}
|
|
|
|
void mt_gpufreq_low_batt_volume_callback(BATTERY_PERCENT_LEVEL low_battery_volume)
|
|
{
|
|
gpufreq_dbg("@%s: low_battery_volume = %d\n", __func__, low_battery_volume);
|
|
|
|
if (mt_gpufreq_ready == false) {
|
|
/*gpufreq_pr_warn("@%s: GPU DVFS not ready!\n", __func__);*/
|
|
return;
|
|
}
|
|
|
|
if (g_limited_low_batt_volume_ignore_state == true) {
|
|
gpufreq_info("@%s: g_limited_low_batt_volume_ignore_state == true!\n", __func__);
|
|
return;
|
|
}
|
|
|
|
mt_gpufreq_low_battery_volume = low_battery_volume;
|
|
|
|
/* LOW_BATTERY_VOLUME_1: <= 15%, LOW_BATTERY_VOLUME_0: >15% */
|
|
if (low_battery_volume == BATTERY_PERCENT_LEVEL_1) {
|
|
if (mt_gpufreq_low_batt_volume_limited_index !=
|
|
mt_gpufreq_low_bat_volume_limited_index_1) {
|
|
mt_gpufreq_low_batt_volume_limited_index =
|
|
mt_gpufreq_low_bat_volume_limited_index_1;
|
|
|
|
/* Unlimited */
|
|
mt_gpufreq_low_batt_volume_protect(mt_gpufreq_low_bat_volume_limited_index_1);
|
|
}
|
|
}
|
|
/* unlimit gpu */
|
|
else {
|
|
if (mt_gpufreq_low_batt_volume_limited_index !=
|
|
mt_gpufreq_low_bat_volume_limited_index_0) {
|
|
mt_gpufreq_low_batt_volume_limited_index =
|
|
mt_gpufreq_low_bat_volume_limited_index_0;
|
|
mt_gpufreq_low_batt_volume_protect(mt_gpufreq_low_bat_volume_limited_index_0); /* Unlimit */
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef MT_GPUFREQ_LOW_BATT_VOLT_PROTECT
|
|
/************************************************
|
|
* GPU frequency adjust interface for low bat_volt protect
|
|
*************************************************/
|
|
static void mt_gpufreq_low_batt_volt_protect(unsigned int limited_index)
|
|
{
|
|
mutex_lock(&mt_gpufreq_power_lock);
|
|
|
|
gpufreq_dbg("@%s: limited_index = %d\n", __func__, limited_index);
|
|
mt_gpufreq_power_limited_index_array[IDX_LOW_BATT_VOLT_LIMITED] = limited_index;
|
|
mt_gpufreq_power_throttle_protect();
|
|
|
|
mutex_unlock(&mt_gpufreq_power_lock);
|
|
}
|
|
|
|
/******************************************************
|
|
* parameter: low_battery_level
|
|
*******************************************************/
|
|
void mt_gpufreq_low_batt_volt_callback(LOW_BATTERY_LEVEL low_battery_level)
|
|
{
|
|
gpufreq_dbg("@%s: low_battery_level = %d\n", __func__, low_battery_level);
|
|
|
|
if (mt_gpufreq_ready == false) {
|
|
/*gpufreq_pr_warn("@%s: GPU DVFS not ready!\n", __func__);*/
|
|
return;
|
|
}
|
|
|
|
if (g_limited_low_batt_volt_ignore_state == true) {
|
|
gpufreq_info("@%s: g_limited_low_batt_volt_ignore_state == true!\n", __func__);
|
|
return;
|
|
}
|
|
|
|
mt_gpufreq_low_battery_level = low_battery_level;
|
|
|
|
/* is_low_battery=1:need limit HW, is_low_battery=0:no limit */
|
|
/* 3.25V HW issue int and is_low_battery=1,
|
|
* 3.0V HW issue int and is_low_battery=2,
|
|
* 3.5V HW issue int and is_low_battery=0
|
|
*/
|
|
|
|
/* no need to throttle when LV1 */
|
|
#if 0
|
|
if (low_battery_level == LOW_BATTERY_LEVEL_1) {
|
|
if (mt_gpufreq_low_batt_volt_limited_index !=
|
|
mt_gpufreq_low_bat_volt_limited_index_1) {
|
|
mt_gpufreq_low_batt_volt_limited_index =
|
|
mt_gpufreq_low_bat_volt_limited_index_1;
|
|
/* Limit GPU 416Mhz */
|
|
mt_gpufreq_low_batt_volt_protect(mt_gpufreq_low_bat_volt_limited_index_1);
|
|
}
|
|
} else
|
|
#endif
|
|
if (low_battery_level == LOW_BATTERY_LEVEL_2) {
|
|
if (mt_gpufreq_low_batt_volt_limited_index !=
|
|
mt_gpufreq_low_bat_volt_limited_index_2) {
|
|
mt_gpufreq_low_batt_volt_limited_index =
|
|
mt_gpufreq_low_bat_volt_limited_index_2;
|
|
/* Limit GPU 400Mhz */
|
|
mt_gpufreq_low_batt_volt_protect(mt_gpufreq_low_bat_volt_limited_index_2);
|
|
}
|
|
} else { /* unlimit gpu */
|
|
if (mt_gpufreq_low_batt_volt_limited_index !=
|
|
mt_gpufreq_low_bat_volt_limited_index_0) {
|
|
mt_gpufreq_low_batt_volt_limited_index =
|
|
mt_gpufreq_low_bat_volt_limited_index_0;
|
|
/* Unlimit */
|
|
mt_gpufreq_low_batt_volt_protect(mt_gpufreq_low_bat_volt_limited_index_0);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/************************************************
|
|
* frequency adjust interface for thermal protect
|
|
*************************************************/
|
|
/******************************************************
|
|
* parameter: target power
|
|
*******************************************************/
|
|
static unsigned int _mt_gpufreq_get_limited_freq(unsigned int limited_power)
|
|
{
|
|
int i = 0;
|
|
unsigned int limited_freq = 0;
|
|
unsigned int found = 0;
|
|
|
|
for (i = 0; i < mt_gpufreqs_num; i++) {
|
|
if (mt_gpufreqs_power[i].gpufreq_power <= limited_power) {
|
|
limited_freq = mt_gpufreqs_power[i].gpufreq_khz;
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* not found */
|
|
if (!found)
|
|
limited_freq = mt_gpufreqs_power[mt_gpufreqs_num - 1].gpufreq_khz;
|
|
|
|
gpufreq_dbg("@%s: limited_freq = %d\n", __func__, limited_freq);
|
|
|
|
return limited_freq;
|
|
}
|
|
|
|
void mt_gpufreq_thermal_protect(unsigned int limited_power)
|
|
{
|
|
int i = 0;
|
|
unsigned int limited_freq = 0;
|
|
|
|
mutex_lock(&mt_gpufreq_power_lock);
|
|
|
|
if (mt_gpufreq_ready == false) {
|
|
/*gpufreq_pr_warn("@%s: GPU DVFS not ready!\n", __func__);*/
|
|
mutex_unlock(&mt_gpufreq_power_lock);
|
|
return;
|
|
}
|
|
|
|
if (mt_gpufreqs_num == 0) {
|
|
gpufreq_pr_warn("@%s: mt_gpufreqs_num == 0!\n", __func__);
|
|
mutex_unlock(&mt_gpufreq_power_lock);
|
|
return;
|
|
}
|
|
|
|
if (g_limited_thermal_ignore_state == true) {
|
|
gpufreq_info("@%s: g_limited_thermal_ignore_state == true!\n", __func__);
|
|
mutex_unlock(&mt_gpufreq_power_lock);
|
|
return;
|
|
}
|
|
|
|
mt_gpufreq_thermal_limited_gpu_power = limited_power;
|
|
|
|
#ifdef MT_GPUFREQ_DYNAMIC_POWER_TABLE_UPDATE
|
|
mt_update_gpufreqs_power_table();
|
|
#endif
|
|
|
|
if (limited_power == 0)
|
|
mt_gpufreq_power_limited_index_array[IDX_THERMAL_LIMITED] = 0;
|
|
else {
|
|
limited_freq = _mt_gpufreq_get_limited_freq(limited_power);
|
|
|
|
for (i = 0; i < mt_gpufreqs_num; i++) {
|
|
if (mt_gpufreqs[i].gpufreq_khz <= limited_freq) {
|
|
mt_gpufreq_power_limited_index_array[IDX_THERMAL_LIMITED] = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mt_gpufreq_prev_thermal_limited_freq != limited_freq) {
|
|
mt_gpufreq_prev_thermal_limited_freq = limited_freq;
|
|
mt_gpufreq_power_throttle_protect();
|
|
if (limited_freq < GPU_DVFS_FREQ0)
|
|
gpufreq_info("@%s: p %u f %u i %u\n", __func__, limited_power, limited_freq,
|
|
mt_gpufreq_power_limited_index_array[IDX_THERMAL_LIMITED]);
|
|
}
|
|
|
|
mutex_unlock(&mt_gpufreq_power_lock);
|
|
}
|
|
EXPORT_SYMBOL(mt_gpufreq_thermal_protect);
|
|
|
|
/* for thermal to update power budget */
|
|
unsigned int mt_gpufreq_get_max_power(void)
|
|
{
|
|
if (!mt_gpufreqs_power)
|
|
return 0;
|
|
else
|
|
return mt_gpufreqs_power[0].gpufreq_power;
|
|
}
|
|
|
|
/* for thermal to update power budget */
|
|
unsigned int mt_gpufreq_get_min_power(void)
|
|
{
|
|
if (!mt_gpufreqs_power)
|
|
return 0;
|
|
else
|
|
return mt_gpufreqs_power[mt_gpufreqs_num - 1].gpufreq_power;
|
|
}
|
|
|
|
void mt_gpufreq_set_power_limit_by_pbm(unsigned int limited_power)
|
|
{
|
|
#ifndef DISABLE_PBM_FEATURE
|
|
int i = 0;
|
|
unsigned int limited_freq = 0;
|
|
|
|
mutex_lock(&mt_gpufreq_power_lock);
|
|
|
|
if (mt_gpufreq_ready == false) {
|
|
/*gpufreq_pr_warn("@%s: GPU DVFS not ready!\n", __func__);*/
|
|
mutex_unlock(&mt_gpufreq_power_lock);
|
|
return;
|
|
}
|
|
|
|
if (mt_gpufreqs_num == 0) {
|
|
gpufreq_pr_warn("@%s: mt_gpufreqs_num == 0!\n", __func__);
|
|
mutex_unlock(&mt_gpufreq_power_lock);
|
|
return;
|
|
}
|
|
|
|
if (g_limited_pbm_ignore_state == true) {
|
|
gpufreq_info("@%s: g_limited_pbm_ignorepbm_ignore_state == true!\n", __func__);
|
|
mutex_unlock(&mt_gpufreq_power_lock);
|
|
return;
|
|
}
|
|
|
|
if (limited_power == mt_gpufreq_pbm_limited_gpu_power) {
|
|
gpufreq_dbg("@%s: limited_power(%d mW) not changed, skip it!\n",
|
|
__func__, limited_power);
|
|
mutex_unlock(&mt_gpufreq_power_lock);
|
|
return;
|
|
}
|
|
|
|
mt_gpufreq_pbm_limited_gpu_power = limited_power;
|
|
|
|
gpufreq_dbg("@%s: limited_power = %d\n", __func__, limited_power);
|
|
|
|
#ifdef MT_GPUFREQ_DYNAMIC_POWER_TABLE_UPDATE
|
|
mt_update_gpufreqs_power_table(); /* TODO: need to check overhead? */
|
|
#endif
|
|
|
|
if (limited_power == 0)
|
|
mt_gpufreq_pbm_limited_index = 0;
|
|
else {
|
|
limited_freq = _mt_gpufreq_get_limited_freq(limited_power);
|
|
|
|
for (i = 0; i < mt_gpufreqs_num; i++) {
|
|
if (mt_gpufreqs[i].gpufreq_khz <= limited_freq) {
|
|
mt_gpufreq_pbm_limited_index = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
gpufreq_dbg("PBM limit frequency upper bound to id = %d\n", mt_gpufreq_pbm_limited_index);
|
|
|
|
if (g_pGpufreq_power_limit_notify != NULL)
|
|
g_pGpufreq_power_limit_notify(mt_gpufreq_pbm_limited_index);
|
|
|
|
mutex_unlock(&mt_gpufreq_power_lock);
|
|
#endif
|
|
}
|
|
|
|
unsigned int mt_gpufreq_get_leakage_mw(void)
|
|
{
|
|
#ifndef DISABLE_PBM_FEATURE
|
|
int temp = 0;
|
|
#ifdef STATIC_PWR_READY2USE
|
|
unsigned int cur_vcore = _mt_gpufreq_get_cur_volt() / 100;
|
|
int leak_power;
|
|
#endif
|
|
|
|
#ifdef CONFIG_THERMAL
|
|
temp = get_immediate_gpu_wrap() / 1000;
|
|
#else
|
|
temp = 40;
|
|
#endif
|
|
|
|
#ifdef STATIC_PWR_READY2USE
|
|
leak_power = mt_spower_get_leakage(MTK_SPOWER_GPU, cur_vcore, temp);
|
|
if (mt_gpufreq_volt_enable_state && leak_power > 0)
|
|
return leak_power;
|
|
else
|
|
return 0;
|
|
#else
|
|
return 130;
|
|
#endif
|
|
|
|
#else /* DISABLE_PBM_FEATURE */
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
/************************************************
|
|
* return current GPU thermal limit index
|
|
*************************************************/
|
|
unsigned int mt_gpufreq_get_thermal_limit_index(void)
|
|
{
|
|
gpufreq_dbg("current GPU thermal limit index is %d\n", g_limited_max_id);
|
|
return g_limited_max_id;
|
|
}
|
|
EXPORT_SYMBOL(mt_gpufreq_get_thermal_limit_index);
|
|
|
|
/************************************************
|
|
* return current GPU thermal limit frequency
|
|
*************************************************/
|
|
unsigned int mt_gpufreq_get_thermal_limit_freq(void)
|
|
{
|
|
gpufreq_dbg("current GPU thermal limit freq is %d MHz\n",
|
|
mt_gpufreqs[g_limited_max_id].gpufreq_khz / 1000);
|
|
return mt_gpufreqs[g_limited_max_id].gpufreq_khz;
|
|
}
|
|
EXPORT_SYMBOL(mt_gpufreq_get_thermal_limit_freq);
|
|
|
|
/************************************************
|
|
* return current GPU frequency index
|
|
*************************************************/
|
|
unsigned int mt_gpufreq_get_cur_freq_index(void)
|
|
{
|
|
gpufreq_dbg("current GPU frequency OPP index is %d\n", g_cur_gpu_OPPidx);
|
|
return g_cur_gpu_OPPidx;
|
|
}
|
|
EXPORT_SYMBOL(mt_gpufreq_get_cur_freq_index);
|
|
|
|
/************************************************
|
|
* return current GPU frequency
|
|
*************************************************/
|
|
unsigned int mt_gpufreq_get_cur_freq(void)
|
|
{
|
|
gpufreq_dbg("current GPU frequency is %d MHz\n", g_cur_gpu_freq / 1000);
|
|
return g_cur_gpu_freq;
|
|
}
|
|
EXPORT_SYMBOL(mt_gpufreq_get_cur_freq);
|
|
|
|
/************************************************
|
|
* return current GPU voltage
|
|
*************************************************/
|
|
unsigned int mt_gpufreq_get_cur_volt(void)
|
|
{
|
|
#if 0
|
|
return g_cur_gpu_volt;
|
|
#else
|
|
return _mt_gpufreq_get_cur_volt();
|
|
#endif
|
|
}
|
|
EXPORT_SYMBOL(mt_gpufreq_get_cur_volt);
|
|
|
|
/************************************************
|
|
* register / unregister GPU input boost notifiction CB
|
|
*************************************************/
|
|
void mt_gpufreq_input_boost_notify_registerCB(gpufreq_input_boost_notify pCB)
|
|
{
|
|
#ifdef MT_GPUFREQ_INPUT_BOOST
|
|
g_pGpufreq_input_boost_notify = pCB;
|
|
#endif
|
|
}
|
|
EXPORT_SYMBOL(mt_gpufreq_input_boost_notify_registerCB);
|
|
|
|
/************************************************
|
|
* register / unregister GPU power limit notifiction CB
|
|
*************************************************/
|
|
void mt_gpufreq_power_limit_notify_registerCB(gpufreq_power_limit_notify pCB)
|
|
{
|
|
g_pGpufreq_power_limit_notify = pCB;
|
|
}
|
|
EXPORT_SYMBOL(mt_gpufreq_power_limit_notify_registerCB);
|
|
|
|
/************************************************
|
|
* register / unregister ptpod update GPU volt CB
|
|
*************************************************/
|
|
void mt_gpufreq_update_volt_registerCB(gpufreq_ptpod_update_notify pCB)
|
|
{
|
|
g_pGpufreq_ptpod_update_notify = pCB;
|
|
}
|
|
EXPORT_SYMBOL(mt_gpufreq_update_volt_registerCB);
|
|
|
|
/************************************************
|
|
* register / unregister set GPU freq CB
|
|
*************************************************/
|
|
void mt_gpufreq_setfreq_registerCB(sampler_func pCB)
|
|
{
|
|
g_pFreqSampler = pCB;
|
|
}
|
|
EXPORT_SYMBOL(mt_gpufreq_setfreq_registerCB);
|
|
|
|
/************************************************
|
|
* register / unregister set GPU volt CB
|
|
*************************************************/
|
|
void mt_gpufreq_setvolt_registerCB(sampler_func pCB)
|
|
{
|
|
g_pVoltSampler = pCB;
|
|
}
|
|
EXPORT_SYMBOL(mt_gpufreq_setvolt_registerCB);
|
|
|
|
#ifdef CONFIG_HAS_EARLYSUSPEND
|
|
/*********************************
|
|
* early suspend callback function
|
|
**********************************/
|
|
void mt_gpufreq_early_suspend(struct early_suspend *h)
|
|
{
|
|
/* mt_gpufreq_state_set(0); */
|
|
|
|
}
|
|
|
|
/*******************************
|
|
* late resume callback function
|
|
********************************/
|
|
void mt_gpufreq_late_resume(struct early_suspend *h)
|
|
{
|
|
/* mt_gpufreq_check_freq_and_set_pll(); */
|
|
|
|
/* mt_gpufreq_state_set(1); */
|
|
}
|
|
#endif
|
|
|
|
static int mt_gpufreq_pm_restore_early(struct device *dev)
|
|
{
|
|
int i = 0;
|
|
int found = 0;
|
|
|
|
g_cur_gpu_freq = _mt_gpufreq_get_cur_freq();
|
|
|
|
for (i = 0; i < mt_gpufreqs_num; i++) {
|
|
if (g_cur_gpu_freq == mt_gpufreqs[i].gpufreq_khz) {
|
|
g_cur_gpu_idx = mt_gpufreqs[i].gpufreq_idx;
|
|
g_cur_gpu_volt = mt_gpufreqs[i].gpufreq_volt;
|
|
g_cur_gpu_OPPidx = i;
|
|
found = 1;
|
|
gpufreq_dbg("match g_cur_gpu_OPPidx: %d\n", g_cur_gpu_OPPidx);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (found == 0) {
|
|
g_cur_gpu_idx = mt_gpufreqs[0].gpufreq_idx;
|
|
g_cur_gpu_volt = mt_gpufreqs[0].gpufreq_volt;
|
|
g_cur_gpu_OPPidx = 0;
|
|
gpufreq_pr_err("gpu freq not found, set parameter to max freq\n");
|
|
}
|
|
|
|
gpufreq_dbg("GPU freq SW/HW: %d/%d\n", g_cur_gpu_freq, _mt_gpufreq_get_cur_freq());
|
|
gpufreq_dbg("g_cur_gpu_OPPidx: %d\n", g_cur_gpu_OPPidx);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_OF
|
|
static const struct of_device_id mt_gpufreq_of_match[] = {
|
|
{.compatible = "mediatek,mt6739-gpufreq",},
|
|
{ /* sentinel */ },
|
|
};
|
|
#endif
|
|
MODULE_DEVICE_TABLE(of, mt_gpufreq_of_match);
|
|
|
|
void mt_gpufreq_set_loading(unsigned int gpu_loading)
|
|
{
|
|
}
|
|
|
|
#define TURBO_EFUSE (29)
|
|
#define SEG_EFUSE (30)
|
|
static int mt_gpufreq_pdrv_probe(struct platform_device *pdev)
|
|
{
|
|
struct device_node *apmixed_node;
|
|
int i = 0;
|
|
int mt_gpufreq_low_bat_volt_limit_freq_2;
|
|
int mt_gpufreq_oc_limit_freq_1;
|
|
#ifdef MT_GPUFREQ_INPUT_BOOST
|
|
int rc;
|
|
struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 };
|
|
#endif
|
|
|
|
#if defined(CONFIG_OF)
|
|
struct device_node *node;
|
|
|
|
node = of_find_matching_node(NULL, mt_gpufreq_of_match);
|
|
if (!node)
|
|
gpufreq_pr_err("@%s: find GPU node failed\n", __func__);
|
|
|
|
mt_gpufreq_clk = kzalloc(sizeof(struct mt_gpufreq_clk_t), GFP_KERNEL);
|
|
if (mt_gpufreq_clk == NULL)
|
|
return -ENOMEM;
|
|
|
|
/* MT6739 segment code[5]{1b0} + FAB turbo[21:20]{0x3} */
|
|
if (((get_devinfo_with_index(TURBO_EFUSE) & EFUSE_FAB_INFO_TURBO_MASK) == EFUSE_FAB_INFO_TURBO_MASK) &&
|
|
(get_devinfo_with_index(SEG_EFUSE) == 0x80 || get_devinfo_with_index(SEG_EFUSE) == 0x88 ||
|
|
get_devinfo_with_index(SEG_EFUSE) == 0x90 || get_devinfo_with_index(SEG_EFUSE) == 0x08 ||
|
|
get_devinfo_with_index(SEG_EFUSE) == 0x00 || get_devinfo_with_index(SEG_EFUSE) == 0x40 ||
|
|
get_devinfo_with_index(SEG_EFUSE) == 0x48 || get_devinfo_with_index(SEG_EFUSE) == 0xC8 ||
|
|
get_devinfo_with_index(SEG_EFUSE) == 0xC0 || get_devinfo_with_index(SEG_EFUSE) == 0xD0)) {
|
|
gpufreq_info("@%s: I am 6739TW seg_code(%x), fab_turbo(%x)\n", __func__,
|
|
get_devinfo_with_index(SEG_EFUSE), get_devinfo_with_index(TURBO_EFUSE));
|
|
device_id = ID_MT6739TW;
|
|
} else if ((get_devinfo_with_index(SEG_EFUSE) == 0xB8 || get_devinfo_with_index(SEG_EFUSE) == 0x38)) {
|
|
gpufreq_info("@%s: I am 6739WD(6731) seg_code(%x), fab_turbo(%x)\n", __func__,
|
|
get_devinfo_with_index(SEG_EFUSE), get_devinfo_with_index(TURBO_EFUSE));
|
|
device_id = ID_MT6739WD;
|
|
} else {
|
|
gpufreq_info("@%s: I am 6739 seg_code(%x), fab_turbo(%x)\n", __func__,
|
|
get_devinfo_with_index(SEG_EFUSE), get_devinfo_with_index(TURBO_EFUSE));
|
|
device_id = ID_MT6739;
|
|
}
|
|
|
|
/* alloc PMIC regulator */
|
|
{
|
|
mt_gpufreq_pmic = kzalloc(sizeof(struct mt_gpufreq_pmic_t), GFP_KERNEL);
|
|
mt_gpufreq_pmic->reg_vcore = regulator_get(&pdev->dev, "vcore");
|
|
if (IS_ERR(mt_gpufreq_pmic->reg_vcore)) {
|
|
dev_err(&pdev->dev, "cannot get vcore\n");
|
|
return PTR_ERR(mt_gpufreq_pmic->reg_vcore);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
mt_gpufreq_dvfs_table_type = device_id;
|
|
|
|
#ifdef CONFIG_HAS_EARLYSUSPEND
|
|
mt_gpufreq_early_suspend_handler.suspend = mt_gpufreq_early_suspend;
|
|
mt_gpufreq_early_suspend_handler.resume = mt_gpufreq_late_resume;
|
|
register_early_suspend(&mt_gpufreq_early_suspend_handler);
|
|
#endif
|
|
|
|
|
|
/**********************
|
|
* Initial leackage power usage
|
|
***********************/
|
|
#ifdef STATIC_PWR_READY2USE
|
|
mt_spower_init();
|
|
#endif
|
|
|
|
/**********************
|
|
* Initial SRAM debugging ptr
|
|
***********************/
|
|
#ifdef MT_GPUFREQ_AEE_RR_REC
|
|
_mt_gpufreq_aee_init();
|
|
#endif
|
|
|
|
/**********************
|
|
* setup gpufreq table
|
|
***********************/
|
|
gpufreq_info("setup gpufreqs table\n");
|
|
|
|
if (mt_gpufreq_dvfs_table_type == ID_MT6739)
|
|
mt_setup_gpufreqs_table(mt_gpufreq_opp_tbl_mt6739,
|
|
ARRAY_SIZE(mt_gpufreq_opp_tbl_mt6739));
|
|
else if (mt_gpufreq_dvfs_table_type == ID_MT6739TW)
|
|
mt_setup_gpufreqs_table(mt_gpufreq_opp_tbl_mt6739tw,
|
|
ARRAY_SIZE(mt_gpufreq_opp_tbl_mt6739tw));
|
|
else if (mt_gpufreq_dvfs_table_type == ID_MT6739WD)
|
|
mt_setup_gpufreqs_table(mt_gpufreq_opp_tbl_mt6739wd,
|
|
ARRAY_SIZE(mt_gpufreq_opp_tbl_mt6739wd));
|
|
else
|
|
mt_setup_gpufreqs_table(mt_gpufreq_opp_tbl_mt6739,
|
|
ARRAY_SIZE(mt_gpufreq_opp_tbl_mt6739));
|
|
gpufreq_dbg("[Figo] OPP Table Set Up Done (%d)", mt_gpufreq_dvfs_table_type);
|
|
|
|
/**********************
|
|
* setup PMIC init value
|
|
***********************/
|
|
gpufreq_dbg("[Figo] Skip regulator init");
|
|
mt_gpufreq_volt_enable_state = 1;
|
|
gpufreq_dbg("[Figo] power init done");
|
|
|
|
/* init PLL
|
|
* to get PLL register
|
|
*/
|
|
|
|
/* Init APMIXED base address */
|
|
apmixed_node = of_find_compatible_node(NULL, NULL, "mediatek,apmixed");
|
|
g_apmixed_base = of_iomap(apmixed_node, 0);
|
|
if (!g_apmixed_base) {
|
|
gpufreq_pr_err("Error, APMIXED iomap failed");
|
|
return -ENOENT;
|
|
}
|
|
g_cur_freq_init_keep = g_cur_gpu_freq;
|
|
|
|
/**********************
|
|
* setup initial frequency
|
|
***********************/
|
|
gpufreq_dbg("[Figo] setup initial frequency");
|
|
mt_gpufreq_set_initial();
|
|
|
|
gpufreq_info("GPU current frequency = %dKHz\n", _mt_gpufreq_get_cur_freq());
|
|
gpufreq_info("Current Vproc = %dmV\n", _mt_gpufreq_get_cur_volt() / 100);
|
|
gpufreq_info("g_cur_gpu_freq = %d, g_cur_gpu_volt = %d\n", g_cur_gpu_freq, g_cur_gpu_volt);
|
|
gpufreq_info("g_cur_gpu_idx = %d, g_cur_gpu_OPPidx = %d\n", g_cur_gpu_idx,
|
|
g_cur_gpu_OPPidx);
|
|
|
|
mt_gpufreq_ready = true;
|
|
|
|
|
|
#ifdef MT_GPUFREQ_INPUT_BOOST
|
|
mt_gpufreq_up_task =
|
|
kthread_create(mt_gpufreq_input_boost_task, NULL, "mt_gpufreq_input_boost_task");
|
|
if (IS_ERR(mt_gpufreq_up_task))
|
|
return PTR_ERR(mt_gpufreq_up_task);
|
|
|
|
sched_setscheduler_nocheck(mt_gpufreq_up_task, SCHED_FIFO, ¶m);
|
|
get_task_struct(mt_gpufreq_up_task);
|
|
|
|
rc = input_register_handler(&mt_gpufreq_input_handler);
|
|
#endif
|
|
|
|
#ifdef MT_GPUFREQ_LOW_BATT_VOLT_PROTECT
|
|
for (i = 0; i < mt_gpufreqs_num; i++) {
|
|
if (mt_gpufreqs[i].gpufreq_khz == MT_GPUFREQ_LOW_BATT_VOLT_LIMIT_FREQ_1) {
|
|
mt_gpufreq_low_bat_volt_limited_index_1 = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* limit to the lowest frequency */
|
|
mt_gpufreq_low_bat_volt_limit_freq_2 = GPUFREQ_LAST_FREQ_LEVEL;
|
|
|
|
for (i = 0; i < mt_gpufreqs_num; i++) {
|
|
if (mt_gpufreqs[i].gpufreq_khz == mt_gpufreq_low_bat_volt_limit_freq_2) {
|
|
mt_gpufreq_low_bat_volt_limited_index_2 = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
register_low_battery_notify(&mt_gpufreq_low_batt_volt_callback, LOW_BATTERY_PRIO_GPU);
|
|
#endif
|
|
|
|
#ifdef MT_GPUFREQ_LOW_BATT_VOLUME_PROTECT
|
|
for (i = 0; i < mt_gpufreqs_num; i++) {
|
|
if (mt_gpufreqs[i].gpufreq_khz == MT_GPUFREQ_LOW_BATT_VOLUME_LIMIT_FREQ_1) {
|
|
mt_gpufreq_low_bat_volume_limited_index_1 = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
register_battery_percent_notify(&mt_gpufreq_low_batt_volume_callback,
|
|
BATTERY_PERCENT_PRIO_GPU);
|
|
#endif
|
|
|
|
#ifdef MT_GPUFREQ_OC_PROTECT
|
|
mt_gpufreq_oc_limit_freq_1 = GPUFREQ_LAST_FREQ_LEVEL;
|
|
|
|
for (i = 0; i < mt_gpufreqs_num; i++) {
|
|
if (mt_gpufreqs[i].gpufreq_khz == mt_gpufreq_oc_limit_freq_1) {
|
|
mt_gpufreq_oc_limited_index_1 = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
register_battery_oc_notify(&mt_gpufreq_oc_callback, BATTERY_OC_PRIO_GPU);
|
|
#endif
|
|
|
|
#ifndef DISABLE_PBM_FEATURE
|
|
INIT_DEFERRABLE_WORK(¬ify_pbm_gpuoff_work, mt_gpufreq_notify_pbm_gpuoff);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
/***************************************
|
|
* this function should never be called
|
|
****************************************/
|
|
static int mt_gpufreq_pdrv_remove(struct platform_device *pdev)
|
|
{
|
|
#ifdef MT_GPUFREQ_INPUT_BOOST
|
|
input_unregister_handler(&mt_gpufreq_input_handler);
|
|
|
|
kthread_stop(mt_gpufreq_up_task);
|
|
put_task_struct(mt_gpufreq_up_task);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct dev_pm_ops mt_gpufreq_pm_ops = {
|
|
.suspend = NULL,
|
|
.resume = NULL,
|
|
.restore_early = mt_gpufreq_pm_restore_early,
|
|
};
|
|
#if 0
|
|
struct platform_device mt_gpufreq_pdev = {
|
|
.name = "mt-gpufreq",
|
|
.id = -1,
|
|
};
|
|
#endif
|
|
static struct platform_driver mt_gpufreq_pdrv = {
|
|
.probe = mt_gpufreq_pdrv_probe,
|
|
.remove = mt_gpufreq_pdrv_remove,
|
|
.driver = {
|
|
.name = "gpufreq",
|
|
.pm = &mt_gpufreq_pm_ops,
|
|
.owner = THIS_MODULE,
|
|
#ifdef CONFIG_OF
|
|
.of_match_table = mt_gpufreq_of_match,
|
|
#endif
|
|
},
|
|
};
|
|
|
|
|
|
#ifdef CONFIG_PROC_FS
|
|
/* #if 0 */
|
|
/*
|
|
* PROC
|
|
*/
|
|
|
|
/***************************
|
|
* show current debug status
|
|
****************************/
|
|
static int mt_gpufreq_debug_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
if (mt_gpufreq_debug)
|
|
seq_puts(m, "gpufreq debug enabled\n");
|
|
else
|
|
seq_puts(m, "gpufreq debug disabled\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
/***********************
|
|
* enable debug message
|
|
************************/
|
|
static ssize_t mt_gpufreq_debug_proc_write(struct file *file, const char __user *buffer,
|
|
size_t count, loff_t *data)
|
|
{
|
|
char desc[32];
|
|
unsigned int len = 0;
|
|
|
|
int debug = 0;
|
|
|
|
len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1);
|
|
if (copy_from_user(desc, buffer, len))
|
|
return 0;
|
|
desc[len] = '\0';
|
|
|
|
if (kstrtoint(desc, 0, &debug) == 0) {
|
|
if (debug == 0)
|
|
mt_gpufreq_debug = 0;
|
|
else if (debug == 1)
|
|
mt_gpufreq_debug = 1;
|
|
else
|
|
gpufreq_pr_warn("bad argument!! should be 0 or 1 [0: disable, 1: enable]\n");
|
|
} else
|
|
gpufreq_pr_warn("bad argument!! should be 0 or 1 [0: disable, 1: enable]\n");
|
|
|
|
return count;
|
|
}
|
|
|
|
#ifdef MT_GPUFREQ_OC_PROTECT
|
|
/****************************
|
|
* show current limited by low batt volume
|
|
*****************************/
|
|
static int mt_gpufreq_limited_oc_ignore_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
seq_printf(m, "g_limited_max_id = %d, g_limited_oc_ignore_state = %d\n", g_limited_max_id,
|
|
g_limited_oc_ignore_state);
|
|
return 0;
|
|
}
|
|
|
|
/**********************************
|
|
* limited for low batt volume protect
|
|
***********************************/
|
|
static ssize_t mt_gpufreq_limited_oc_ignore_proc_write(struct file *file,
|
|
const char __user *buffer, size_t count,
|
|
loff_t *data)
|
|
{
|
|
char desc[32];
|
|
unsigned int len = 0;
|
|
unsigned int ignore = 0;
|
|
|
|
len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1);
|
|
if (copy_from_user(desc, buffer, len))
|
|
return 0;
|
|
desc[len] = '\0';
|
|
|
|
if (kstrtouint(desc, 0, &ignore) == 0) {
|
|
if (ignore == 1)
|
|
g_limited_oc_ignore_state = true;
|
|
else if (ignore == 0)
|
|
g_limited_oc_ignore_state = false;
|
|
else
|
|
gpufreq_pr_warn
|
|
("bad argument!! should be 0 or 1 [0: not ignore, 1: ignore]\n");
|
|
} else
|
|
gpufreq_pr_warn("bad argument!! should be 0 or 1 [0: not ignore, 1: ignore]\n");
|
|
|
|
mt_gpufreq_power_limited_ignore[IDX_OC_LIMITED] = g_limited_oc_ignore_state;
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
#ifdef MT_GPUFREQ_LOW_BATT_VOLUME_PROTECT
|
|
/****************************
|
|
* show current limited by low batt volume
|
|
*****************************/
|
|
static int mt_gpufreq_limited_low_batt_volume_ignore_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
seq_printf(m, "g_limited_max_id = %d, g_limited_low_batt_volume_ignore_state = %d\n",
|
|
g_limited_max_id, g_limited_low_batt_volume_ignore_state);
|
|
return 0;
|
|
}
|
|
|
|
/**********************************
|
|
* limited for low batt volume protect
|
|
***********************************/
|
|
static ssize_t mt_gpufreq_limited_low_batt_volume_ignore_proc_write(struct file *file,
|
|
const char __user *buffer,
|
|
size_t count, loff_t *data)
|
|
{
|
|
char desc[32];
|
|
unsigned int len = 0;
|
|
|
|
unsigned int ignore = 0;
|
|
|
|
len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1);
|
|
if (copy_from_user(desc, buffer, len))
|
|
return 0;
|
|
desc[len] = '\0';
|
|
|
|
if (kstrtouint(desc, 0, &ignore) == 0) {
|
|
if (ignore == 1)
|
|
g_limited_low_batt_volume_ignore_state = true;
|
|
else if (ignore == 0)
|
|
g_limited_low_batt_volume_ignore_state = false;
|
|
else
|
|
gpufreq_pr_warn
|
|
("bad argument!! should be 0 or 1 [0: not ignore, 1: ignore]\n");
|
|
} else
|
|
gpufreq_pr_warn("bad argument!! should be 0 or 1 [0: not ignore, 1: ignore]\n");
|
|
|
|
mt_gpufreq_power_limited_ignore[IDX_LOW_BATT_VOLUME_LIMITED] = g_limited_low_batt_volume_ignore_state;
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
#ifdef MT_GPUFREQ_LOW_BATT_VOLT_PROTECT
|
|
/****************************
|
|
* show current limited by low batt volt
|
|
*****************************/
|
|
static int mt_gpufreq_limited_low_batt_volt_ignore_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
seq_printf(m, "g_limited_max_id = %d, g_limited_low_batt_volt_ignore_state = %d\n",
|
|
g_limited_max_id, g_limited_low_batt_volt_ignore_state);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**********************************
|
|
* limited for low batt volt protect
|
|
***********************************/
|
|
static ssize_t mt_gpufreq_limited_low_batt_volt_ignore_proc_write(struct file *file,
|
|
const char __user *buffer,
|
|
size_t count, loff_t *data)
|
|
{
|
|
char desc[32];
|
|
unsigned int len = 0;
|
|
|
|
unsigned int ignore = 0;
|
|
|
|
len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1);
|
|
if (copy_from_user(desc, buffer, len))
|
|
return 0;
|
|
desc[len] = '\0';
|
|
|
|
if (kstrtouint(desc, 0, &ignore) == 0) {
|
|
if (ignore == 1)
|
|
g_limited_low_batt_volt_ignore_state = true;
|
|
else if (ignore == 0)
|
|
g_limited_low_batt_volt_ignore_state = false;
|
|
else
|
|
gpufreq_pr_warn
|
|
("bad argument!! should be 0 or 1 [0: not ignore, 1: ignore]\n");
|
|
} else
|
|
gpufreq_pr_warn("bad argument!! should be 0 or 1 [0: not ignore, 1: ignore]\n");
|
|
|
|
mt_gpufreq_power_limited_ignore[IDX_LOW_BATT_VOLT_LIMITED] = g_limited_low_batt_volt_ignore_state;
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
/****************************
|
|
* show current limited by thermal
|
|
*****************************/
|
|
static int mt_gpufreq_limited_thermal_ignore_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
seq_printf(m, "g_limited_max_id = %d, g_limited_thermal_ignore_state = %d\n",
|
|
g_limited_max_id, g_limited_thermal_ignore_state);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**********************************
|
|
* limited for thermal protect
|
|
***********************************/
|
|
static ssize_t mt_gpufreq_limited_thermal_ignore_proc_write(struct file *file,
|
|
const char __user *buffer,
|
|
size_t count, loff_t *data)
|
|
{
|
|
char desc[32];
|
|
unsigned int len = 0;
|
|
|
|
unsigned int ignore = 0;
|
|
|
|
len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1);
|
|
if (copy_from_user(desc, buffer, len))
|
|
return 0;
|
|
desc[len] = '\0';
|
|
|
|
if (kstrtouint(desc, 0, &ignore) == 0) {
|
|
if (ignore == 1)
|
|
g_limited_thermal_ignore_state = true;
|
|
else if (ignore == 0)
|
|
g_limited_thermal_ignore_state = false;
|
|
else
|
|
gpufreq_pr_warn
|
|
("bad argument!! should be 0 or 1 [0: not ignore, 1: ignore]\n");
|
|
} else
|
|
gpufreq_pr_warn("bad argument!! should be 0 or 1 [0: not ignore, 1: ignore]\n");
|
|
|
|
mt_gpufreq_power_limited_ignore[IDX_THERMAL_LIMITED] = g_limited_thermal_ignore_state;
|
|
return count;
|
|
}
|
|
|
|
#ifndef DISABLE_PBM_FEATURE
|
|
/****************************
|
|
* show current limited by PBM
|
|
*****************************/
|
|
static int mt_gpufreq_limited_pbm_ignore_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
seq_printf(m, "mt_gpufreq_pbm_limited_index = %d, g_limited_pbm_ignore_state = %d\n",
|
|
mt_gpufreq_pbm_limited_index, g_limited_pbm_ignore_state);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**********************************
|
|
* limited for low batt volume protect
|
|
***********************************/
|
|
static ssize_t mt_gpufreq_limited_pbm_ignore_proc_write(struct file *file,
|
|
const char __user *buffer, size_t count,
|
|
loff_t *data)
|
|
{
|
|
char desc[32];
|
|
unsigned int len = 0;
|
|
|
|
unsigned int ignore = 0;
|
|
|
|
len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1);
|
|
if (copy_from_user(desc, buffer, len))
|
|
return 0;
|
|
desc[len] = '\0';
|
|
|
|
if (kstrtouint(desc, 0, &ignore) == 0) {
|
|
if (ignore == 1) {
|
|
g_limited_pbm_ignore_state = true;
|
|
} else if (ignore == 0)
|
|
g_limited_pbm_ignore_state = false;
|
|
else
|
|
gpufreq_pr_warn
|
|
("bad argument!! should be 0 or 1 [0: not ignore, 1: ignore]\n");
|
|
} else
|
|
gpufreq_pr_warn("bad argument!! should be 0 or 1 [0: not ignore, 1: ignore]\n");
|
|
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
/****************************
|
|
* show current limited power
|
|
*****************************/
|
|
static int mt_gpufreq_limited_power_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
seq_printf(m, "g_limited_max_id = %d, limit frequency = %d\n",
|
|
g_limited_max_id, mt_gpufreqs[g_limited_max_id].gpufreq_khz);
|
|
return 0;
|
|
}
|
|
|
|
/**********************************
|
|
* limited power for thermal protect
|
|
***********************************/
|
|
static ssize_t mt_gpufreq_limited_power_proc_write(struct file *file,
|
|
const char __user *buffer,
|
|
size_t count, loff_t *data)
|
|
{
|
|
char desc[32];
|
|
unsigned int len = 0;
|
|
|
|
unsigned int power = 0;
|
|
|
|
len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1);
|
|
if (copy_from_user(desc, buffer, len))
|
|
return 0;
|
|
desc[len] = '\0';
|
|
|
|
if (kstrtouint(desc, 0, &power) == 0)
|
|
mt_gpufreq_thermal_protect(power);
|
|
else
|
|
gpufreq_pr_warn("bad argument!! please provide the maximum limited power\n");
|
|
|
|
return count;
|
|
}
|
|
|
|
/****************************
|
|
* show current limited power by PBM
|
|
*****************************/
|
|
#ifndef DISABLE_PBM_FEATURE
|
|
static int mt_gpufreq_limited_by_pbm_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
seq_printf(m, "pbm_limited_power = %d, limit index = %d\n",
|
|
mt_gpufreq_pbm_limited_gpu_power, mt_gpufreq_pbm_limited_index);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**********************************
|
|
* limited power for thermal protect
|
|
***********************************/
|
|
static ssize_t mt_gpufreq_limited_by_pbm_proc_write(struct file *file, const char __user *buffer,
|
|
size_t count, loff_t *data)
|
|
{
|
|
char desc[32];
|
|
unsigned int len = 0;
|
|
|
|
unsigned int power = 0;
|
|
|
|
len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1);
|
|
if (copy_from_user(desc, buffer, len))
|
|
return 0;
|
|
desc[len] = '\0';
|
|
|
|
if (kstrtouint(desc, 0, &power) == 0)
|
|
mt_gpufreq_set_power_limit_by_pbm(power);
|
|
else
|
|
gpufreq_pr_warn("bad argument!! please provide the maximum limited power\n");
|
|
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
/******************************
|
|
* show current GPU DVFS stauts
|
|
*******************************/
|
|
static int mt_gpufreq_state_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
if (!mt_gpufreq_pause)
|
|
seq_puts(m, "GPU DVFS enabled\n");
|
|
else
|
|
seq_puts(m, "GPU DVFS disabled\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************
|
|
* set GPU DVFS stauts by sysfs interface
|
|
*****************************************/
|
|
static ssize_t mt_gpufreq_state_proc_write(struct file *file,
|
|
const char __user *buffer, size_t count, loff_t *data)
|
|
{
|
|
char desc[32];
|
|
unsigned int len = 0;
|
|
|
|
int enabled = 0;
|
|
|
|
len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1);
|
|
if (copy_from_user(desc, buffer, len))
|
|
return 0;
|
|
desc[len] = '\0';
|
|
|
|
if (kstrtoint(desc, 0, &enabled) == 0) {
|
|
if (enabled == 1) {
|
|
mt_gpufreq_keep_max_frequency_state = false;
|
|
mt_gpufreq_state_set(1);
|
|
} else if (enabled == 0) {
|
|
/* Keep MAX frequency when GPU DVFS disabled. */
|
|
mt_gpufreq_keep_max_frequency_state = true;
|
|
#ifdef VOLT_SET_READY
|
|
gpufreq_dbg("[Figo] Power on by mt_gpufreq_state_proc_write\n");
|
|
mt_gpufreq_voltage_enable_set(1);
|
|
#endif
|
|
mt_gpufreq_target(g_gpufreq_max_id);
|
|
mt_gpufreq_state_set(0);
|
|
} else
|
|
gpufreq_pr_warn("bad argument!! argument should be \"1\" or \"0\"\n");
|
|
} else
|
|
gpufreq_pr_warn("bad argument!! argument should be \"1\" or \"0\"\n");
|
|
|
|
return count;
|
|
}
|
|
|
|
/********************
|
|
* show GPU OPP table
|
|
*********************/
|
|
static int mt_gpufreq_opp_dump_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
int i = 0;
|
|
|
|
for (i = 0; i < mt_gpufreqs_num; i++) {
|
|
seq_printf(m, "[%d] ", i);
|
|
seq_printf(m, "freq = %d, ", mt_gpufreqs[i].gpufreq_khz);
|
|
seq_printf(m, "volt = %d, ", mt_gpufreqs[i].gpufreq_volt);
|
|
seq_printf(m, "idx = %d\n", mt_gpufreqs[i].gpufreq_idx);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/********************
|
|
* show GPU power table
|
|
*********************/
|
|
static int mt_gpufreq_power_dump_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
int i = 0;
|
|
|
|
for (i = 0; i < mt_gpufreqs_num; i++) {
|
|
seq_printf(m, "mt_gpufreqs_power[%d].gpufreq_khz = %d\n", i,
|
|
mt_gpufreqs_power[i].gpufreq_khz);
|
|
seq_printf(m, "mt_gpufreqs_power[%d].gpufreq_volt = %d\n", i,
|
|
mt_gpufreqs_power[i].gpufreq_volt);
|
|
seq_printf(m, "mt_gpufreqs_power[%d].gpufreq_power = %d\n", i,
|
|
mt_gpufreqs_power[i].gpufreq_power);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/***************************
|
|
* show current specific frequency status
|
|
****************************/
|
|
static int mt_gpufreq_opp_freq_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
if (mt_gpufreq_keep_opp_frequency_state) {
|
|
seq_puts(m, "gpufreq keep opp frequency enabled\n");
|
|
seq_printf(m, "freq = %d\n", mt_gpufreqs[mt_gpufreq_keep_opp_index].gpufreq_khz);
|
|
seq_printf(m, "volt = %d\n", mt_gpufreqs[mt_gpufreq_keep_opp_index].gpufreq_volt);
|
|
} else
|
|
seq_puts(m, "gpufreq keep opp frequency disabled\n");
|
|
return 0;
|
|
}
|
|
|
|
/***********************
|
|
* enable specific frequency
|
|
************************/
|
|
static ssize_t mt_gpufreq_opp_freq_proc_write(struct file *file, const char __user *buffer,
|
|
size_t count, loff_t *data)
|
|
{
|
|
char desc[32];
|
|
unsigned int len = 0;
|
|
|
|
int fixed_freq = 0;
|
|
int i = 0;
|
|
int found = 0;
|
|
|
|
len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1);
|
|
if (copy_from_user(desc, buffer, len))
|
|
return 0;
|
|
desc[len] = '\0';
|
|
if (kstrtoint(desc, 0, &fixed_freq) == 0) {
|
|
if (fixed_freq == 0) {
|
|
mt_gpufreq_keep_opp_frequency_state = false;
|
|
} else {
|
|
for (i = 0; i < mt_gpufreqs_num; i++) {
|
|
if (fixed_freq == mt_gpufreqs[i].gpufreq_khz) {
|
|
mt_gpufreq_keep_opp_index = i;
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (found == 1) {
|
|
mt_gpufreq_keep_opp_frequency_state = true;
|
|
mt_gpufreq_keep_opp_frequency = fixed_freq;
|
|
|
|
#ifdef VOLT_SET_READY
|
|
gpufreq_dbg("[Figo] Power on by mt_gpufreq_opp_freq_proc_write\n");
|
|
mt_gpufreq_voltage_enable_set(1);
|
|
#endif
|
|
mt_gpufreq_target(mt_gpufreq_keep_opp_index);
|
|
}
|
|
|
|
}
|
|
} else
|
|
gpufreq_pr_warn("bad argument!! please provide the fixed frequency\n");
|
|
|
|
return count;
|
|
}
|
|
|
|
/***************************
|
|
* show current specific frequency status
|
|
****************************/
|
|
static int mt_gpufreq_opp_max_freq_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
if (mt_gpufreq_opp_max_frequency_state) {
|
|
seq_puts(m, "gpufreq opp max frequency enabled\n");
|
|
seq_printf(m, "freq = %d\n", mt_gpufreqs[mt_gpufreq_opp_max_index].gpufreq_khz);
|
|
seq_printf(m, "volt = %d\n", mt_gpufreqs[mt_gpufreq_opp_max_index].gpufreq_volt);
|
|
} else
|
|
seq_puts(m, "gpufreq opp max frequency disabled\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
/***********************
|
|
* enable specific frequency
|
|
************************/
|
|
static ssize_t mt_gpufreq_opp_max_freq_proc_write(struct file *file, const char __user *buffer,
|
|
size_t count, loff_t *data)
|
|
{
|
|
char desc[32];
|
|
unsigned int len = 0;
|
|
|
|
int max_freq = 0;
|
|
int i = 0;
|
|
int found = 0;
|
|
|
|
len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1);
|
|
if (copy_from_user(desc, buffer, len))
|
|
return 0;
|
|
desc[len] = '\0';
|
|
|
|
if (kstrtoint(desc, 0, &max_freq) == 0) {
|
|
if (max_freq == 0) {
|
|
mt_gpufreq_opp_max_frequency_state = false;
|
|
} else {
|
|
for (i = 0; i < mt_gpufreqs_num; i++) {
|
|
if (mt_gpufreqs[i].gpufreq_khz <= max_freq) {
|
|
mt_gpufreq_opp_max_index = i;
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (found == 1) {
|
|
mt_gpufreq_opp_max_frequency_state = true;
|
|
mt_gpufreq_opp_max_frequency =
|
|
mt_gpufreqs[mt_gpufreq_opp_max_index].gpufreq_khz;
|
|
#ifdef VOLT_SET_READY
|
|
gpufreq_dbg("[Figo] Power on by mt_gpufreq_opp_max_freq_proc_write\n");
|
|
mt_gpufreq_voltage_enable_set(1);
|
|
#endif
|
|
mt_gpufreq_target(mt_gpufreq_opp_max_index);
|
|
}
|
|
}
|
|
} else
|
|
gpufreq_pr_warn("bad argument!! please provide the maximum limited frequency\n");
|
|
|
|
return count;
|
|
}
|
|
|
|
/********************
|
|
* show variable dump
|
|
*********************/
|
|
static int mt_gpufreq_var_dump_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
int i = 0;
|
|
|
|
seq_puts(m, "DVFS_GPU [legacy]\n");
|
|
|
|
seq_printf(m, "g_cur_gpu_freq = %d, g_cur_gpu_volt = %d\n", mt_gpufreq_get_cur_freq(),
|
|
mt_gpufreq_get_cur_volt());
|
|
seq_printf(m, "g_cur_gpu_idx = %d, g_cur_gpu_OPPidx = %d\n", g_cur_gpu_idx,
|
|
g_cur_gpu_OPPidx);
|
|
seq_printf(m, "g_limited_max_id = %d\n", g_limited_max_id);
|
|
|
|
for (i = 0; i < NR_IDX_POWER_LIMITED; i++)
|
|
seq_printf(m, "mt_gpufreq_power_limited_index_array[%d] = %d\n", i,
|
|
mt_gpufreq_power_limited_index_array[i]);
|
|
|
|
seq_printf(m, "_mt_gpufreq_get_cur_freq = %d, mt_get_ckgen_freq = %d KHz\n",
|
|
_mt_gpufreq_get_cur_freq(), mt_get_ckgen_freq(7));
|
|
seq_printf(m, "mt_gpufreq_volt_enable_state = %d\n", mt_gpufreq_volt_enable_state);
|
|
seq_printf(m, "mt_gpufreq_dvfs_table_type = %d\n", mt_gpufreq_dvfs_table_type);
|
|
seq_printf(m, "mt_gpufreq_ptpod_disable_idx = %d\n", mt_gpufreq_ptpod_disable_idx);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/***************************
|
|
* show current voltage enable status
|
|
****************************/
|
|
static int mt_gpufreq_volt_enable_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
if (mt_gpufreq_volt_enable)
|
|
seq_puts(m, "gpufreq voltage enabled\n");
|
|
else
|
|
seq_puts(m, "gpufreq voltage disabled\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
/***********************
|
|
* enable specific frequency
|
|
************************/
|
|
static ssize_t mt_gpufreq_volt_enable_proc_write(struct file *file, const char __user *buffer,
|
|
size_t count, loff_t *data)
|
|
{
|
|
char desc[32];
|
|
unsigned int len = 0;
|
|
|
|
int enable = 0;
|
|
|
|
len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1);
|
|
if (copy_from_user(desc, buffer, len))
|
|
return 0;
|
|
desc[len] = '\0';
|
|
|
|
if (kstrtoint(desc, 0, &enable) == 0) {
|
|
if (enable == 0) {
|
|
#ifdef VOLT_SET_READY
|
|
gpufreq_dbg("[Figo] Power off by mt_gpufreq_state_proc_write\n");
|
|
mt_gpufreq_voltage_enable_set(0);
|
|
#endif
|
|
mt_gpufreq_volt_enable = false;
|
|
} else if (enable == 1) {
|
|
#ifdef VOLT_SET_READY
|
|
gpufreq_dbg("[Figo] Power on by mt_gpufreq_state_proc_write\n");
|
|
mt_gpufreq_voltage_enable_set(1);
|
|
#endif
|
|
mt_gpufreq_volt_enable = true;
|
|
} else
|
|
gpufreq_pr_warn("bad argument!! should be 0 or 1 [0: disable, 1: enable]\n");
|
|
} else
|
|
gpufreq_pr_warn("bad argument!! should be 0 or 1 [0: disable, 1: enable]\n");
|
|
return count;
|
|
}
|
|
|
|
/***************************
|
|
* show current specific frequency status
|
|
****************************/
|
|
static int mt_gpufreq_fixed_freq_volt_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
if (mt_gpufreq_fixed_freq_volt_state) {
|
|
seq_puts(m, "gpufreq fixed frequency enabled\n");
|
|
seq_printf(m, "fixed frequency = %d\n", mt_gpufreq_fixed_frequency);
|
|
seq_printf(m, "fixed voltage = %d\n", mt_gpufreq_fixed_voltage);
|
|
} else
|
|
seq_puts(m, "gpufreq fixed frequency disabled\n");
|
|
return 0;
|
|
}
|
|
|
|
/***********************
|
|
* enable specific frequency
|
|
************************/
|
|
static void _mt_gpufreq_fixed_freq(int fixed_freq)
|
|
{
|
|
unsigned int last_freq_level = 0;
|
|
|
|
last_freq_level = GPUFREQ_LAST_FREQ_LEVEL;
|
|
|
|
/* freq (KHz) */
|
|
if ((fixed_freq >= GPUFREQ_LAST_FREQ_LEVEL)
|
|
&& (fixed_freq <= GPU_DVFS_FREQ0)) {
|
|
gpufreq_dbg("@ %s, mt_gpufreq_clock_switch1 fix frq = %d, fix volt = %d, volt = %d\n",
|
|
__func__, mt_gpufreq_fixed_frequency, mt_gpufreq_fixed_voltage, g_cur_gpu_volt);
|
|
mt_gpufreq_fixed_freq_volt_state = true;
|
|
mt_gpufreq_fixed_frequency = fixed_freq;
|
|
mt_gpufreq_fixed_voltage = g_cur_gpu_volt;
|
|
#ifdef VOLT_SET_READY
|
|
gpufreq_dbg("[Figo] Power on by _mt_gpufreq_fixed_freq\n");
|
|
mt_gpufreq_voltage_enable_set(1);
|
|
#endif
|
|
gpufreq_dbg("@ %s, mt_gpufreq_clock_switch2 fix frq = %d, fix volt = %d, volt = %d\n",
|
|
__func__, mt_gpufreq_fixed_frequency, mt_gpufreq_fixed_voltage, g_cur_gpu_volt);
|
|
mt_gpufreq_clock_switch(mt_gpufreq_fixed_frequency);
|
|
g_cur_gpu_freq = mt_gpufreq_fixed_frequency;
|
|
}
|
|
}
|
|
|
|
static void _mt_gpufreq_fixed_volt(int fixed_volt)
|
|
{
|
|
unsigned int max_volt = 0;
|
|
unsigned int min_volt = 0;
|
|
|
|
|
|
if (device_id == ID_MT6739) {
|
|
max_volt = PMIC_MAX_VCORE;
|
|
min_volt = PMIC_MIN_VCORE;
|
|
} else if (device_id == ID_MT6739TW) {
|
|
max_volt = PMIC_MAX_VCORE_6739TW;
|
|
min_volt = PMIC_MIN_VCORE_6739TW;
|
|
} else if (device_id == ID_MT6739WD) {
|
|
max_volt = PMIC_MAX_VCORE_6739WD;
|
|
min_volt = PMIC_MIN_VCORE_6739WD;
|
|
} else {
|
|
max_volt = PMIC_MAX_VCORE;
|
|
min_volt = PMIC_MAX_VCORE;
|
|
}
|
|
|
|
/* volt (mV) */
|
|
#ifdef VPROC_SET_BY_PMIC
|
|
if (fixed_volt >= (min_volt / 100) &&
|
|
fixed_volt <= (max_volt / 100)) {
|
|
#endif
|
|
gpufreq_dbg("@ %s, mt_gpufreq_volt_switch1 fix frq = %d, fix volt = %d, volt = %d\n",
|
|
__func__, mt_gpufreq_fixed_frequency, mt_gpufreq_fixed_voltage, g_cur_gpu_volt);
|
|
mt_gpufreq_fixed_freq_volt_state = true;
|
|
mt_gpufreq_fixed_frequency = g_cur_gpu_freq;
|
|
mt_gpufreq_fixed_voltage = fixed_volt * 100;
|
|
#ifdef VOLT_SET_READY
|
|
gpufreq_dbg("[Figo] Power on by _mt_gpufreq_fixed_volt\n");
|
|
mt_gpufreq_voltage_enable_set(1);
|
|
#endif
|
|
gpufreq_dbg("@ %s, mt_gpufreq_volt_switch2 fix frq = %d, fix volt = %d, volt = %d\n",
|
|
__func__, mt_gpufreq_fixed_frequency, mt_gpufreq_fixed_voltage, g_cur_gpu_volt);
|
|
mt_gpufreq_volt_switch(g_cur_gpu_volt, mt_gpufreq_fixed_voltage);
|
|
g_cur_gpu_volt = mt_gpufreq_fixed_voltage;
|
|
}
|
|
}
|
|
|
|
static ssize_t mt_gpufreq_fixed_freq_volt_proc_write(struct file *file, const char __user *buffer,
|
|
size_t count, loff_t *data)
|
|
{
|
|
char desc[32];
|
|
unsigned int len = 0;
|
|
|
|
int fixed_freq = 0;
|
|
int fixed_volt = 0;
|
|
|
|
len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1);
|
|
if (copy_from_user(desc, buffer, len))
|
|
return 0;
|
|
desc[len] = '\0';
|
|
|
|
if (sscanf(desc, "%d %d", &fixed_freq, &fixed_volt) == 2) {
|
|
if ((fixed_freq == 0) && (fixed_volt == 0)) {
|
|
mt_gpufreq_fixed_freq_volt_state = false;
|
|
mt_gpufreq_fixed_frequency = 0;
|
|
mt_gpufreq_fixed_voltage = 0;
|
|
} else {
|
|
g_cur_gpu_freq = _mt_gpufreq_get_cur_freq();
|
|
if (fixed_freq > g_cur_gpu_freq) {
|
|
_mt_gpufreq_fixed_volt(fixed_volt);
|
|
_mt_gpufreq_fixed_freq(fixed_freq);
|
|
} else {
|
|
_mt_gpufreq_fixed_freq(fixed_freq);
|
|
_mt_gpufreq_fixed_volt(fixed_volt);
|
|
}
|
|
}
|
|
} else
|
|
gpufreq_pr_warn("bad argument!! should be [enable fixed_freq fixed_volt]\n");
|
|
|
|
return count;
|
|
}
|
|
|
|
#ifdef MT_GPUFREQ_INPUT_BOOST
|
|
/*****************************
|
|
* show current input boost status
|
|
******************************/
|
|
static int mt_gpufreq_input_boost_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
if (mt_gpufreq_input_boost_state == 1)
|
|
seq_puts(m, "gpufreq input boost is enabled\n");
|
|
else
|
|
seq_puts(m, "gpufreq input boost is disabled\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
/***************************
|
|
* enable/disable input boost
|
|
****************************/
|
|
static ssize_t mt_gpufreq_input_boost_proc_write(struct file *file, const char __user *buffer,
|
|
size_t count, loff_t *data)
|
|
{
|
|
char desc[32];
|
|
int len = 0;
|
|
|
|
int debug = 0;
|
|
|
|
len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1);
|
|
if (copy_from_user(desc, buffer, len))
|
|
return 0;
|
|
desc[len] = '\0';
|
|
|
|
if (kstrtoint(desc, 0, &debug) == 0) {
|
|
if (debug == 0)
|
|
mt_gpufreq_input_boost_state = 0;
|
|
else if (debug == 1)
|
|
mt_gpufreq_input_boost_state = 1;
|
|
else
|
|
gpufreq_pr_warn("bad argument!! should be 0 or 1 [0: disable, 1: enable]\n");
|
|
} else
|
|
gpufreq_pr_warn("bad argument!! should be 0 or 1 [0: disable, 1: enable]\n");
|
|
|
|
return count;
|
|
}
|
|
|
|
/***************************
|
|
* show lowpower frequency opp enable status
|
|
****************************/
|
|
static int mt_gpufreq_lpt_enable_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
seq_puts(m, "not implemented\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
/***********************
|
|
* enable lowpower frequency opp
|
|
************************/
|
|
static ssize_t mt_gpufreq_lpt_enable_proc_write(struct file *file, const char __user *buffer,
|
|
size_t count, loff_t *data)
|
|
{
|
|
|
|
gpufreq_pr_warn("not implemented\n");
|
|
#if 0
|
|
char desc[32];
|
|
unsigned int len = 0;
|
|
|
|
int enable = 0;
|
|
|
|
len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1);
|
|
if (copy_from_user(desc, buffer, len))
|
|
return 0;
|
|
desc[len] = '\0';
|
|
|
|
if (kstrtoint(desc, 0, &enable) == 0) {
|
|
if (enable == 0)
|
|
mt_gpufreq_low_power_test_enable = false;
|
|
else if (enable == 1)
|
|
mt_gpufreq_low_power_test_enable = true;
|
|
else
|
|
gpufreq_pr_warn("bad argument!! should be 0 or 1 [0: disable, 1: enable]\n");
|
|
} else
|
|
gpufreq_pr_warn("bad argument!! should be 0 or 1 [0: disable, 1: enable]\n");
|
|
#endif
|
|
|
|
return count;
|
|
}
|
|
|
|
#endif
|
|
|
|
#define PROC_FOPS_RW(name) \
|
|
static int mt_ ## name ## _proc_open(struct inode *inode, struct file *file) \
|
|
{ \
|
|
return single_open(file, mt_ ## name ## _proc_show, PDE_DATA(inode)); \
|
|
} \
|
|
static const struct file_operations mt_ ## name ## _proc_fops = { \
|
|
.owner = THIS_MODULE, \
|
|
.open = mt_ ## name ## _proc_open, \
|
|
.read = seq_read, \
|
|
.llseek = seq_lseek, \
|
|
.release = single_release, \
|
|
.write = mt_ ## name ## _proc_write, \
|
|
}
|
|
|
|
#define PROC_FOPS_RO(name) \
|
|
static int mt_ ## name ## _proc_open(struct inode *inode, struct file *file) \
|
|
{ \
|
|
return single_open(file, mt_ ## name ## _proc_show, PDE_DATA(inode)); \
|
|
} \
|
|
static const struct file_operations mt_ ## name ## _proc_fops = { \
|
|
.owner = THIS_MODULE, \
|
|
.open = mt_ ## name ## _proc_open, \
|
|
.read = seq_read, \
|
|
.llseek = seq_lseek, \
|
|
.release = single_release, \
|
|
}
|
|
|
|
#define PROC_ENTRY(name) {__stringify(name), &mt_ ## name ## _proc_fops}
|
|
|
|
PROC_FOPS_RW(gpufreq_debug);
|
|
PROC_FOPS_RW(gpufreq_limited_power);
|
|
#ifdef MT_GPUFREQ_OC_PROTECT
|
|
PROC_FOPS_RW(gpufreq_limited_oc_ignore);
|
|
#endif
|
|
#ifdef MT_GPUFREQ_LOW_BATT_VOLUME_PROTECT
|
|
PROC_FOPS_RW(gpufreq_limited_low_batt_volume_ignore);
|
|
#endif
|
|
#ifdef MT_GPUFREQ_LOW_BATT_VOLT_PROTECT
|
|
PROC_FOPS_RW(gpufreq_limited_low_batt_volt_ignore);
|
|
#endif
|
|
PROC_FOPS_RW(gpufreq_limited_thermal_ignore);
|
|
#ifndef DISABLE_PBM_FEATURE
|
|
PROC_FOPS_RW(gpufreq_limited_pbm_ignore);
|
|
PROC_FOPS_RW(gpufreq_limited_by_pbm);
|
|
#endif
|
|
PROC_FOPS_RW(gpufreq_state);
|
|
PROC_FOPS_RO(gpufreq_opp_dump);
|
|
PROC_FOPS_RO(gpufreq_power_dump);
|
|
PROC_FOPS_RW(gpufreq_opp_freq);
|
|
PROC_FOPS_RW(gpufreq_opp_max_freq);
|
|
PROC_FOPS_RO(gpufreq_var_dump);
|
|
PROC_FOPS_RW(gpufreq_volt_enable);
|
|
PROC_FOPS_RW(gpufreq_fixed_freq_volt);
|
|
#ifdef MT_GPUFREQ_INPUT_BOOST
|
|
PROC_FOPS_RW(gpufreq_input_boost);
|
|
#endif
|
|
PROC_FOPS_RW(gpufreq_lpt_enable);
|
|
|
|
static int mt_gpufreq_create_procfs(void)
|
|
{
|
|
struct proc_dir_entry *dir = NULL;
|
|
int i;
|
|
|
|
struct pentry {
|
|
const char *name;
|
|
const struct file_operations *fops;
|
|
};
|
|
|
|
const struct pentry entries[] = {
|
|
PROC_ENTRY(gpufreq_debug),
|
|
PROC_ENTRY(gpufreq_limited_power),
|
|
#ifdef MT_GPUFREQ_OC_PROTECT
|
|
PROC_ENTRY(gpufreq_limited_oc_ignore),
|
|
#endif
|
|
#ifdef MT_GPUFREQ_LOW_BATT_VOLUME_PROTECT
|
|
PROC_ENTRY(gpufreq_limited_low_batt_volume_ignore),
|
|
#endif
|
|
#ifdef MT_GPUFREQ_LOW_BATT_VOLT_PROTECT
|
|
PROC_ENTRY(gpufreq_limited_low_batt_volt_ignore),
|
|
#endif
|
|
PROC_ENTRY(gpufreq_limited_thermal_ignore),
|
|
#ifndef DISABLE_PBM_FEATURE
|
|
PROC_ENTRY(gpufreq_limited_pbm_ignore),
|
|
PROC_ENTRY(gpufreq_limited_by_pbm),
|
|
#endif
|
|
PROC_ENTRY(gpufreq_state),
|
|
PROC_ENTRY(gpufreq_opp_dump),
|
|
PROC_ENTRY(gpufreq_power_dump),
|
|
PROC_ENTRY(gpufreq_opp_freq),
|
|
PROC_ENTRY(gpufreq_opp_max_freq),
|
|
PROC_ENTRY(gpufreq_var_dump),
|
|
PROC_ENTRY(gpufreq_volt_enable),
|
|
PROC_ENTRY(gpufreq_fixed_freq_volt),
|
|
#ifdef MT_GPUFREQ_INPUT_BOOST
|
|
PROC_ENTRY(gpufreq_input_boost),
|
|
#endif
|
|
PROC_ENTRY(gpufreq_lpt_enable),
|
|
};
|
|
|
|
|
|
dir = proc_mkdir("gpufreq", NULL);
|
|
|
|
if (!dir) {
|
|
gpufreq_pr_err("fail to create /proc/gpufreq @ %s()\n", __func__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(entries); i++) {
|
|
if (!proc_create
|
|
(entries[i].name, S_IRUGO | S_IWUSR | S_IWGRP, dir, entries[i].fops))
|
|
gpufreq_pr_err("@%s: create /proc/gpufreq/%s failed\n", __func__,
|
|
entries[i].name);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_PROC_FS */
|
|
|
|
/**********************************
|
|
* mediatek gpufreq initialization
|
|
***********************************/
|
|
#if 1
|
|
static int __init mt_gpufreq_init(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
#ifdef BRING_UP
|
|
/* Skip driver init in bring up stage */
|
|
return 0;
|
|
#endif
|
|
|
|
gpufreq_info("@%s\n", __func__);
|
|
|
|
#ifdef CONFIG_PROC_FS
|
|
|
|
/* init proc */
|
|
if (mt_gpufreq_create_procfs())
|
|
goto out;
|
|
|
|
#endif /* CONFIG_PROC_FS */
|
|
|
|
/* register platform device/driver */
|
|
#if !defined(CONFIG_OF)
|
|
ret = platform_device_register(&mt_gpufreq_pdev);
|
|
if (ret) {
|
|
gpufreq_pr_err("fail to register gpufreq device @ %s()\n", __func__);
|
|
goto out;
|
|
}
|
|
#endif
|
|
ret = platform_driver_register(&mt_gpufreq_pdrv);
|
|
if (ret) {
|
|
gpufreq_pr_err("fail to register gpufreq driver @ %s()\n", __func__);
|
|
#if !defined(CONFIG_OF)
|
|
platform_device_unregister(&mt_gpufreq_pdev);
|
|
#endif
|
|
}
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
#endif
|
|
static void __exit mt_gpufreq_exit(void)
|
|
{
|
|
platform_driver_unregister(&mt_gpufreq_pdrv);
|
|
#if !defined(CONFIG_OF)
|
|
platform_device_unregister(&mt_gpufreq_pdev);
|
|
#endif
|
|
}
|
|
|
|
module_init(mt_gpufreq_init);
|
|
module_exit(mt_gpufreq_exit);
|
|
|
|
MODULE_DESCRIPTION("MediaTek GPU Frequency Scaling driver");
|
|
MODULE_LICENSE("GPL");
|
|
|
|
|