From d90b43b963027b4d1559cec14e97117827a6458d Mon Sep 17 00:00:00 2001 From: Dorian Snyder Date: Sun, 15 Jun 2014 01:24:33 -0700 Subject: mali: add r3p1 for devices that need it d710 needs to use old mali drivers due to new ones causing signal to be completely killed Change-Id: I450c356b50e3f3521a63717a1c241e3b818b936f --- .../platform/pegasus-m400/mali_platform_dvfs.c | 847 +++++++++++++++++++++ 1 file changed, 847 insertions(+) create mode 100644 drivers/media/video/samsung/mali/platform/pegasus-m400/mali_platform_dvfs.c (limited to 'drivers/media/video/samsung/mali/platform/pegasus-m400/mali_platform_dvfs.c') diff --git a/drivers/media/video/samsung/mali/platform/pegasus-m400/mali_platform_dvfs.c b/drivers/media/video/samsung/mali/platform/pegasus-m400/mali_platform_dvfs.c new file mode 100644 index 0000000..cc1164e --- /dev/null +++ b/drivers/media/video/samsung/mali/platform/pegasus-m400/mali_platform_dvfs.c @@ -0,0 +1,847 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** + * @file mali_platform_dvfs.c + * Platform specific Mali driver dvfs functions + */ + +#include "mali_kernel_common.h" +#include "mali_osk.h" +#include "mali_platform.h" + +#include +#include +#include +#include + +#include + +#include "mali_device_pause_resume.h" +#include + +#define MAX_MALI_DVFS_STEPS 5 +#define MALI_DVFS_WATING 10 // msec + +#ifdef CONFIG_CPU_FREQ +#include +#define EXYNOS4_ASV_ENABLED +#endif + +#include + +static int bMaliDvfsRun=0; + +static _mali_osk_atomic_t bottomlock_status; +int bottom_lock_step = 0; + +typedef struct mali_dvfs_tableTag{ + unsigned int clock; + unsigned int freq; + unsigned int vol; +}mali_dvfs_table; + +typedef struct mali_dvfs_statusTag{ + unsigned int currentStep; + mali_dvfs_table * pCurrentDvfs; + +}mali_dvfs_currentstatus; + +typedef struct mali_dvfs_thresholdTag{ + unsigned int downthreshold; + unsigned int upthreshold; +}mali_dvfs_threshold_table; + +typedef struct mali_dvfs_staycount{ + unsigned int staycount; +}mali_dvfs_staycount_table; + +typedef struct mali_dvfs_stepTag{ + int clk; + int vol; +}mali_dvfs_step; + +mali_dvfs_step step[MALI_DVFS_STEPS]={ + /*step 0 clk*/ {160, 875000}, +#if (MALI_DVFS_STEPS > 1) + /*step 1 clk*/ {266, 900000}, +#if (MALI_DVFS_STEPS > 2) + /*step 2 clk*/ {350, 950000}, +#if (MALI_DVFS_STEPS > 3) + /*step 3 clk*/ {440, 1025000}, +#if (MALI_DVFS_STEPS > 4) + /*step 4 clk*/ {533, 1075000} +#endif +#endif +#endif +#endif +}; + +mali_dvfs_staycount_table mali_dvfs_staycount[MALI_DVFS_STEPS]={ + /*step 0*/{0}, +#if (MALI_DVFS_STEPS > 1) + /*step 1*/{0}, +#if (MALI_DVFS_STEPS > 2) + /*step 2*/{0}, +#if (MALI_DVFS_STEPS > 3) + /*step 3*/{0}, +#if (MALI_DVFS_STEPS > 4) + /*step 4*/{0} +#endif +#endif +#endif +#endif +}; + +/* dvfs information */ +// L0 = 533Mhz, 1.075V +// L1 = 440Mhz, 1.025V +// L2 = 350Mhz, 0.95V +// L3 = 266Mhz, 0.90V +// L4 = 160Mhz, 0.875V + +int step0_clk = 160; +int step0_vol = 875000; +#if (MALI_DVFS_STEPS > 1) +int step1_clk = 266; +int step1_vol = 900000; +int step0_up = 70; +int step1_down = 62; +#if (MALI_DVFS_STEPS > 2) +int step2_clk = 350; +int step2_vol = 950000; +int step1_up = 90; +int step2_down = 85; +#if (MALI_DVFS_STEPS > 3) +int step3_clk = 440; +int step3_vol = 1025000; +int step2_up = 90; +int step3_down = 85; +#if (MALI_DVFS_STEPS > 4) +int step4_clk = 533; +int step4_vol = 1075000; +int step3_up = 90; +int step4_down = 95; +#endif +#endif +#endif +#endif + +mali_dvfs_table mali_dvfs_all[MAX_MALI_DVFS_STEPS]={ + {160 ,1000000 , 875000}, + {266 ,1000000 , 900000}, + {350 ,1000000 , 950000}, + {440 ,1000000 , 1025000}, + {533 ,1000000 , 1075000} }; + +mali_dvfs_table mali_dvfs[MALI_DVFS_STEPS]={ + {160 ,1000000 , 875000}, +#if (MALI_DVFS_STEPS > 1) + {266 ,1000000 , 900000}, +#if (MALI_DVFS_STEPS > 2) + {350 ,1000000 , 950000}, +#if (MALI_DVFS_STEPS > 3) + {440 ,1000000 ,1025000}, +#if (MALI_DVFS_STEPS > 4) + {533 ,1000000 ,1075000} +#endif +#endif +#endif +#endif +}; + +mali_dvfs_threshold_table mali_dvfs_threshold[MALI_DVFS_STEPS]={ + {0 , 70}, +#if (MALI_DVFS_STEPS > 1) + {62 , 90}, +#if (MALI_DVFS_STEPS > 2) + {85 , 90}, +#if (MALI_DVFS_STEPS > 3) + {85 ,90}, +#if (MALI_DVFS_STEPS > 4) + {95 ,100} +#endif +#endif +#endif +#endif +}; + +#ifdef EXYNOS4_ASV_ENABLED +#define ASV_LEVEL 12 /* ASV0, 1, 11 is reserved */ +#define ASV_LEVEL_PRIME 13 /* ASV0, 1, 12 is reserved */ + +static unsigned int asv_3d_volt_9_table_1ghz_type[MALI_DVFS_STEPS-1][ASV_LEVEL] = { + { 975000, 950000, 950000, 950000, 925000, 925000, 925000, 900000, 900000, 900000, 900000, 875000}, /* L3(160Mhz) */ +#if (MALI_DVFS_STEPS > 1) + { 1000000, 975000, 975000, 975000, 950000, 950000, 950000, 900000, 900000, 900000, 900000, 875000}, /* L2(266Mhz) */ +#if (MALI_DVFS_STEPS > 2) + { 1075000, 1050000, 1050000, 1050000, 1000000, 1000000, 1000000, 975000, 975000, 975000, 975000, 925000}, /* L1(350Mhz) */ +#if (MALI_DVFS_STEPS > 3) + { 1125000, 1100000, 1100000, 1100000, 1075000, 1075000, 1075000, 1025000, 1025000, 1025000, 1025000, 975000}, /* L0(440Mhz) */ +#endif +#endif +#endif +}; + +static unsigned int asv_3d_volt_9_table[MALI_DVFS_STEPS-1][ASV_LEVEL] = { + { 950000, 925000, 900000, 900000, 875000, 875000, 875000, 875000, 850000, 850000, 850000, 850000}, /* L3(160Mhz) */ +#if (MALI_DVFS_STEPS > 1) + { 975000, 950000, 925000, 925000, 925000, 900000, 900000, 875000, 875000, 875000, 875000, 850000}, /* L2(266Mhz) */ +#if (MALI_DVFS_STEPS > 2) + { 1050000, 1025000, 1000000, 1000000, 975000, 950000, 950000, 950000, 925000, 925000, 925000, 900000}, /* L1(350Mhz) */ +#if (MALI_DVFS_STEPS > 3) + { 1100000, 1075000, 1050000, 1050000, 1050000, 1025000, 1025000, 1000000, 1000000, 1000000, 975000, 950000}, /* L0(440Mhz) */ +#endif +#endif +#endif +}; + +static unsigned int asv_3d_volt_9_table_for_prime[MALI_DVFS_STEPS][ASV_LEVEL_PRIME] = { + { 950000, 937500, 925000, 912500, 900000, 887500, 875000, 862500, 875000, 862500, 850000, 850000}, /* L4(160Mhz) */ +#if (MALI_DVFS_STEPS > 1) + { 975000, 962500, 950000, 937500, 925000, 912500, 900000, 887500, 900000, 887500, 875000, 862500}, /* L3(266Mhz) */ +#if (MALI_DVFS_STEPS > 2) + { 1025000, 1012500, 1000000, 987500, 975000, 962500, 950000, 937500, 950000, 937500, 925000, 912500}, /* L2(350Mhz) */ +#if (MALI_DVFS_STEPS > 3) + { 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 1012500, 1000000, 987500, 975000}, /* L1(440Mhz) */ +#if (MALI_DVFS_STEPS > 4) + { 1150000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1087500, 1075000, 1062500, 1050000}, /* L0(600Mhz) */ +#endif +#endif +#endif +#endif +}; +#endif /* ASV_LEVEL */ + +/*dvfs status*/ +mali_dvfs_currentstatus maliDvfsStatus; +int mali_dvfs_control=0; + +static u32 mali_dvfs_utilization = 255; + +static void mali_dvfs_work_handler(struct work_struct *w); + +static struct workqueue_struct *mali_dvfs_wq = 0; +extern mali_io_address clk_register_map; +extern _mali_osk_lock_t *mali_dvfs_lock; + +int mali_runtime_resumed = -1; + +static DECLARE_WORK(mali_dvfs_work, mali_dvfs_work_handler); + +/* lock/unlock CPU freq by Mali */ +#include +#include + +atomic_t mali_cpufreq_lock; + +int cpufreq_lock_by_mali(unsigned int freq) +{ +#ifdef CONFIG_EXYNOS4_CPUFREQ +/* #if defined(CONFIG_CPU_FREQ) && defined(CONFIG_ARCH_EXYNOS4) */ + unsigned int level; + + if (atomic_read(&mali_cpufreq_lock) == 0) { + if (exynos_cpufreq_get_level(freq * 1000, &level)) { + printk(KERN_ERR + "Mali: failed to get cpufreq level for %dMHz", + freq); + return -EINVAL; + } + + if (exynos_cpufreq_lock(DVFS_LOCK_ID_G3D, level)) { + printk(KERN_ERR + "Mali: failed to cpufreq lock for L%d", level); + return -EINVAL; + } + + atomic_set(&mali_cpufreq_lock, 1); + printk(KERN_DEBUG "Mali: cpufreq locked on <%d>%dMHz\n", level, + freq); + } +#endif + return 0; +} + +void cpufreq_unlock_by_mali(void) +{ +#ifdef CONFIG_EXYNOS4_CPUFREQ +/* #if defined(CONFIG_CPU_FREQ) && defined(CONFIG_ARCH_EXYNOS4) */ + if (atomic_read(&mali_cpufreq_lock) == 1) { + exynos_cpufreq_lock_free(DVFS_LOCK_ID_G3D); + atomic_set(&mali_cpufreq_lock, 0); + printk(KERN_DEBUG "Mali: cpufreq locked off\n"); + } +#endif +} + +static unsigned int get_mali_dvfs_status(void) +{ + return maliDvfsStatus.currentStep; +} +#if MALI_PMM_RUNTIME_JOB_CONTROL_ON +int get_mali_dvfs_control_status(void) +{ + return mali_dvfs_control; +} + +mali_bool set_mali_dvfs_current_step(unsigned int step) +{ + _mali_osk_lock_wait(mali_dvfs_lock, _MALI_OSK_LOCKMODE_RW); + maliDvfsStatus.currentStep = step % MAX_MALI_DVFS_STEPS; + if (step >= MAX_MALI_DVFS_STEPS) + mali_runtime_resumed = maliDvfsStatus.currentStep; + _mali_osk_lock_signal(mali_dvfs_lock, _MALI_OSK_LOCKMODE_RW); + return MALI_TRUE; +} +#endif +static mali_bool set_mali_dvfs_status(u32 step,mali_bool boostup) +{ + u32 validatedStep=step; + int err; + +#ifdef CONFIG_REGULATOR + if (mali_regulator_get_usecount() == 0) { + MALI_DEBUG_PRINT(1, ("regulator use_count is 0 \n")); + return MALI_FALSE; + } +#endif + + if (boostup) { +#ifdef CONFIG_REGULATOR + /*change the voltage*/ + mali_regulator_set_voltage(mali_dvfs[step].vol, mali_dvfs[step].vol); +#endif + /*change the clock*/ + mali_clk_set_rate(mali_dvfs[step].clock, mali_dvfs[step].freq); + } else { + /*change the clock*/ + mali_clk_set_rate(mali_dvfs[step].clock, mali_dvfs[step].freq); +#ifdef CONFIG_REGULATOR + /*change the voltage*/ + mali_regulator_set_voltage(mali_dvfs[step].vol, mali_dvfs[step].vol); +#endif + } + +#ifdef EXYNOS4_ASV_ENABLED + if (samsung_rev() < EXYNOS4412_REV_2_0) { + if (mali_dvfs[step].clock == 160) + exynos4x12_set_abb_member(ABB_G3D, ABB_MODE_100V); + else + exynos4x12_set_abb_member(ABB_G3D, ABB_MODE_130V); + } +#endif + + + set_mali_dvfs_current_step(validatedStep); + /*for future use*/ + maliDvfsStatus.pCurrentDvfs = &mali_dvfs[validatedStep]; + +#if CPUFREQ_LOCK_DURING_440 + /* lock/unlock CPU freq by Mali */ + if (mali_dvfs[step].clock == 440) + err = cpufreq_lock_by_mali(1200); + else + cpufreq_unlock_by_mali(); +#endif + + return MALI_TRUE; +} + +static void mali_platform_wating(u32 msec) +{ + /*sample wating + change this in the future with proper check routine. + */ + unsigned int read_val; + while(1) { + read_val = _mali_osk_mem_ioread32(clk_register_map, 0x00); + if ((read_val & 0x8000)==0x0000) break; + _mali_osk_time_ubusydelay(100); // 1000 -> 100 : 20101218 + } + /* _mali_osk_time_ubusydelay(msec*1000);*/ +} + +static mali_bool change_mali_dvfs_status(u32 step, mali_bool boostup ) +{ + + MALI_DEBUG_PRINT(1, ("> change_mali_dvfs_status: %d, %d \n",step, boostup)); + + if (!set_mali_dvfs_status(step, boostup)) { + MALI_DEBUG_PRINT(1, ("error on set_mali_dvfs_status: %d, %d \n",step, boostup)); + return MALI_FALSE; + } + + /*wait until clock and voltage is stablized*/ + mali_platform_wating(MALI_DVFS_WATING); /*msec*/ + + return MALI_TRUE; +} + +#ifdef EXYNOS4_ASV_ENABLED +extern unsigned int exynos_result_of_asv; + +static mali_bool mali_dvfs_table_update(void) +{ + unsigned int i; + unsigned int step_num = MALI_DVFS_STEPS; + + if(samsung_rev() < EXYNOS4412_REV_2_0) + step_num = MALI_DVFS_STEPS - 1; + + if(soc_is_exynos4412()) { + if (exynos_armclk_max == 1000000) { + MALI_PRINT(("::C::exynos_result_of_asv : %d\n", exynos_result_of_asv)); + for (i = 0; i < step_num; i++) { + mali_dvfs[i].vol = asv_3d_volt_9_table_1ghz_type[i][exynos_result_of_asv]; + MALI_PRINT(("mali_dvfs[%d].vol = %d \n", i, mali_dvfs[i].vol)); + } + } else if(((is_special_flag() >> G3D_LOCK_FLAG) & 0x1) && (samsung_rev() >= EXYNOS4412_REV_2_0)) { + MALI_PRINT(("::L::exynos_result_of_asv : %d\n", exynos_result_of_asv)); + for (i = 0; i < step_num; i++) { + mali_dvfs[i].vol = asv_3d_volt_9_table_for_prime[i][exynos_result_of_asv] + 25000; + MALI_PRINT(("mali_dvfs[%d].vol = %d \n ", i, mali_dvfs[i].vol)); + } + } else if (samsung_rev() >= EXYNOS4412_REV_2_0) { + MALI_PRINT(("::P::exynos_result_of_asv : %d\n", exynos_result_of_asv)); + for (i = 0; i < step_num; i++) { + mali_dvfs[i].vol = asv_3d_volt_9_table_for_prime[i][exynos_result_of_asv]; + MALI_PRINT(("mali_dvfs[%d].vol = %d \n", i, mali_dvfs[i].vol)); + } + } else { + MALI_PRINT(("::Q::exynos_result_of_asv : %d\n", exynos_result_of_asv)); + for (i = 0; i < step_num; i++) { + mali_dvfs[i].vol = asv_3d_volt_9_table[i][exynos_result_of_asv]; + MALI_PRINT(("mali_dvfs[%d].vol = %d \n", i, mali_dvfs[i].vol)); + } + } + } + + return MALI_TRUE; +} +#endif + +static unsigned int decideNextStatus(unsigned int utilization) +{ + static unsigned int level = 0; // 0:stay, 1:up + static int mali_dvfs_clk = 0; + + if (mali_runtime_resumed >= 0) { + level = mali_runtime_resumed; + mali_runtime_resumed = -1; + } + + if (mali_dvfs_threshold[maliDvfsStatus.currentStep].upthreshold + <= mali_dvfs_threshold[maliDvfsStatus.currentStep].downthreshold) { + MALI_PRINT(("upthreadshold is smaller than downthreshold: %d < %d\n", + mali_dvfs_threshold[maliDvfsStatus.currentStep].upthreshold, + mali_dvfs_threshold[maliDvfsStatus.currentStep].downthreshold)); + return level; + } + + if (!mali_dvfs_control && level == maliDvfsStatus.currentStep) { + if (utilization > (int)(255 * mali_dvfs_threshold[maliDvfsStatus.currentStep].upthreshold / 100) && + level < MALI_DVFS_STEPS - 1) { + level++; + if ((samsung_rev() < EXYNOS4412_REV_2_0) && (maliDvfsStatus.currentStep == 3)) { + level=get_mali_dvfs_status(); + } + } + if (utilization < (int)(255 * mali_dvfs_threshold[maliDvfsStatus.currentStep].downthreshold / 100) && + level > 0) { + level--; + } + } else if (mali_dvfs_control == 999) { + int i = 0; + for (i = 0; i < MALI_DVFS_STEPS; i++) { + step[i].clk = mali_dvfs_all[i].clock; + } +#ifdef EXYNOS4_ASV_ENABLED + mali_dvfs_table_update(); +#endif + i = 0; + for (i = 0; i < MALI_DVFS_STEPS; i++) { + mali_dvfs[i].clock = step[i].clk; + } + mali_dvfs_control = 0; + level = 0; + + step0_clk = step[0].clk; + change_dvfs_tableset(step0_clk, 0); +#if (MALI_DVFS_STEPS > 1) + step1_clk = step[1].clk; + change_dvfs_tableset(step1_clk, 1); +#if (MALI_DVFS_STEPS > 2) + step2_clk = step[2].clk; + change_dvfs_tableset(step2_clk, 2); +#if (MALI_DVFS_STEPS > 3) + step3_clk = step[3].clk; + change_dvfs_tableset(step3_clk, 3); +#if (MALI_DVFS_STEPS > 4) + step4_clk = step[4].clk; + change_dvfs_tableset(step4_clk, 4); +#endif +#endif +#endif +#endif + } else if (mali_dvfs_control != mali_dvfs_clk && mali_dvfs_control != 999) { + if (mali_dvfs_control < mali_dvfs_all[1].clock && mali_dvfs_control > 0) { + int i = 0; + for (i = 0; i < MALI_DVFS_STEPS; i++) { + step[i].clk = mali_dvfs_all[0].clock; + } + maliDvfsStatus.currentStep = 0; + } else if (mali_dvfs_control < mali_dvfs_all[2].clock && mali_dvfs_control >= mali_dvfs_all[1].clock) { + int i = 0; + for (i = 0; i < MALI_DVFS_STEPS; i++) { + step[i].clk = mali_dvfs_all[1].clock; + } + maliDvfsStatus.currentStep = 1; + } else if (mali_dvfs_control < mali_dvfs_all[3].clock && mali_dvfs_control >= mali_dvfs_all[2].clock) { + int i = 0; + for (i = 0; i < MALI_DVFS_STEPS; i++) { + step[i].clk = mali_dvfs_all[2].clock; + } + maliDvfsStatus.currentStep = 2; + } else if (mali_dvfs_control < mali_dvfs_all[4].clock && mali_dvfs_control >= mali_dvfs_all[3].clock) { + int i = 0; + for (i = 0; i < MALI_DVFS_STEPS; i++) { + step[i].clk = mali_dvfs_all[3].clock; + } + maliDvfsStatus.currentStep = 3; + } else { + int i = 0; + for (i = 0; i < MALI_DVFS_STEPS; i++) { + step[i].clk = mali_dvfs_all[4].clock; + } + maliDvfsStatus.currentStep = 4; + } + step0_clk = step[0].clk; + change_dvfs_tableset(step0_clk, 0); +#if (MALI_DVFS_STEPS > 1) + step1_clk = step[1].clk; + change_dvfs_tableset(step1_clk, 1); +#if (MALI_DVFS_STEPS > 2) + step2_clk = step[2].clk; + change_dvfs_tableset(step2_clk, 2); +#if (MALI_DVFS_STEPS > 3) + step3_clk = step[3].clk; + change_dvfs_tableset(step3_clk, 3); +#if (MALI_DVFS_STEPS > 4) + step4_clk = step[4].clk; + change_dvfs_tableset(step4_clk, 4); +#endif +#endif +#endif +#endif + level = maliDvfsStatus.currentStep; + } + + mali_dvfs_clk = mali_dvfs_control; + + if (_mali_osk_atomic_read(&bottomlock_status) > 0) { + if (level < bottom_lock_step) + level = bottom_lock_step; + } + + return level; +} + +static mali_bool mali_dvfs_status(u32 utilization) +{ + unsigned int nextStatus = 0; + unsigned int curStatus = 0; + mali_bool boostup = MALI_FALSE; + static int stay_count = 0; +#ifdef EXYNOS4_ASV_ENABLED + static mali_bool asv_applied = MALI_FALSE; +#endif + + MALI_DEBUG_PRINT(1, ("> mali_dvfs_status: %d \n",utilization)); +#ifdef EXYNOS4_ASV_ENABLED + if (asv_applied == MALI_FALSE) { + mali_dvfs_table_update(); + change_mali_dvfs_status(1, 0); + asv_applied = MALI_TRUE; + + return MALI_TRUE; + } +#endif + + /*decide next step*/ + curStatus = get_mali_dvfs_status(); + nextStatus = decideNextStatus(utilization); + + MALI_DEBUG_PRINT(1, ("= curStatus %d, nextStatus %d, maliDvfsStatus.currentStep %d \n", curStatus, nextStatus, maliDvfsStatus.currentStep)); + + /*if next status is same with current status, don't change anything*/ + if ((curStatus != nextStatus && stay_count == 0)) { + /*check if boost up or not*/ + if (nextStatus > maliDvfsStatus.currentStep) boostup = 1; + + /*change mali dvfs status*/ + if (!change_mali_dvfs_status(nextStatus,boostup)) { + MALI_DEBUG_PRINT(1, ("error on change_mali_dvfs_status \n")); + return MALI_FALSE; + } + stay_count = mali_dvfs_staycount[maliDvfsStatus.currentStep].staycount; + } else { + if (stay_count > 0) + stay_count--; + } + + return MALI_TRUE; +} + + + +int mali_dvfs_is_running(void) +{ + return bMaliDvfsRun; + +} + + + +void mali_dvfs_late_resume(void) +{ + // set the init clock as low when resume + set_mali_dvfs_status(0,0); +} + + +static void mali_dvfs_work_handler(struct work_struct *w) +{ + int change_clk = 0; + int change_step = 0; + bMaliDvfsRun=1; + + /* dvfs table change when clock was changed */ + if (step0_clk != mali_dvfs[0].clock) { + MALI_PRINT(("::: step0_clk change to %d Mhz\n", step0_clk)); + change_clk = step0_clk; + change_step = 0; + step0_clk = change_dvfs_tableset(change_clk, change_step); + } +#if (MALI_DVFS_STEPS > 1) + if (step1_clk != mali_dvfs[1].clock) { + MALI_PRINT(("::: step1_clk change to %d Mhz\n", step1_clk)); + change_clk = step1_clk; + change_step = 1; + step1_clk = change_dvfs_tableset(change_clk, change_step); + } + if (step0_up != mali_dvfs_threshold[0].upthreshold) { + MALI_PRINT(("::: step0_up change to %d %\n", step0_up)); + mali_dvfs_threshold[0].upthreshold = step0_up; + } + if (step1_down != mali_dvfs_threshold[1].downthreshold) { + MALI_PRINT((":::step1_down change to %d %\n", step1_down)); + mali_dvfs_threshold[1].downthreshold = step1_down; + } +#if (MALI_DVFS_STEPS > 2) + if (step2_clk != mali_dvfs[2].clock) { + MALI_PRINT(("::: step2_clk change to %d Mhz\n", step2_clk)); + change_clk = step2_clk; + change_step = 2; + step2_clk = change_dvfs_tableset(change_clk, change_step); + } + if (step1_up != mali_dvfs_threshold[1].upthreshold) { + MALI_PRINT((":::step1_up change to %d %\n", step1_up)); + mali_dvfs_threshold[1].upthreshold = step1_up; + } + if (step2_down != mali_dvfs_threshold[2].downthreshold) { + MALI_PRINT((":::step2_down change to %d %\n", step2_down)); + mali_dvfs_threshold[2].downthreshold = step2_down; + } +#if (MALI_DVFS_STEPS > 3) + if (step3_clk != mali_dvfs[3].clock) { + MALI_PRINT(("::: step3_clk change to %d Mhz\n", step3_clk)); + change_clk = step3_clk; + change_step = 3; + step3_clk = change_dvfs_tableset(change_clk, change_step); + } + if (step2_up != mali_dvfs_threshold[2].upthreshold) { + MALI_PRINT((":::step2_up change to %d %\n", step2_up)); + mali_dvfs_threshold[2].upthreshold = step2_up; + } + if (step3_down != mali_dvfs_threshold[3].downthreshold) { + MALI_PRINT((":::step3_down change to %d %\n", step3_down)); + mali_dvfs_threshold[3].downthreshold = step3_down; + } +#if (MALI_DVFS_STEPS > 4) + if (step4_clk != mali_dvfs[4].clock) { + MALI_PRINT(("::: step4_clk change to %d Mhz\n", step4_clk)); + change_clk = step4_clk; + change_step = 4; + step4_clk = change_dvfs_tableset(change_clk, change_step); + } + if (step3_up != mali_dvfs_threshold[3].upthreshold) { + MALI_PRINT((":::step3_up change to %d %\n", step3_up)); + mali_dvfs_threshold[3].upthreshold = step3_up; + } + if (step4_down != mali_dvfs_threshold[4].downthreshold) { + MALI_PRINT((":::step4_down change to %d %\n", step4_down)); + mali_dvfs_threshold[4].downthreshold = step4_down; + } +#endif +#endif +#endif +#endif + + +#ifdef DEBUG + mali_dvfs[0].vol = step0_vol; + mali_dvfs[1].vol = step1_vol; + mali_dvfs[2].vol = step2_vol; + mali_dvfs[3].vol = step3_vol; + mali_dvfs[4].vol = step4_vol; +#endif + MALI_DEBUG_PRINT(3, ("=== mali_dvfs_work_handler\n")); + + if (!mali_dvfs_status(mali_dvfs_utilization)) + MALI_DEBUG_PRINT(1,( "error on mali dvfs status in mali_dvfs_work_handler")); + + bMaliDvfsRun=0; +} + +mali_bool init_mali_dvfs_status(int step) +{ + /*default status + add here with the right function to get initilization value. + */ + if (!mali_dvfs_wq) + mali_dvfs_wq = create_singlethread_workqueue("mali_dvfs"); + + _mali_osk_atomic_init(&bottomlock_status, 0); + + /*add a error handling here*/ + set_mali_dvfs_current_step(step); + + return MALI_TRUE; +} + +void deinit_mali_dvfs_status(void) +{ + if (mali_dvfs_wq) + destroy_workqueue(mali_dvfs_wq); + + _mali_osk_atomic_term(&bottomlock_status); + + mali_dvfs_wq = NULL; +} + +mali_bool mali_dvfs_handler(u32 utilization) +{ + mali_dvfs_utilization = utilization; + queue_work_on(0, mali_dvfs_wq,&mali_dvfs_work); + + /*add error handle here*/ + return MALI_TRUE; +} + +int change_dvfs_tableset(int change_clk, int change_step) +{ + int err; + + if (change_clk < mali_dvfs_all[1].clock) { + mali_dvfs[change_step].clock = mali_dvfs_all[0].clock; + } else if (change_clk < mali_dvfs_all[2].clock && change_clk >= mali_dvfs_all[1].clock) { + mali_dvfs[change_step].clock = mali_dvfs_all[1].clock; + } else if (change_clk < mali_dvfs_all[3].clock && change_clk >= mali_dvfs_all[2].clock) { + mali_dvfs[change_step].clock = mali_dvfs_all[2].clock; + } else if (change_clk < mali_dvfs_all[4].clock && change_clk >= mali_dvfs_all[3].clock) { + mali_dvfs[change_step].clock = mali_dvfs_all[3].clock; + } else { + mali_dvfs[change_step].clock = mali_dvfs_all[4].clock; + } + + MALI_PRINT((":::mali dvfs step %d clock and voltage = %d Mhz, %d V\n",change_step, mali_dvfs[change_step].clock, mali_dvfs[change_step].vol)); + + if (maliDvfsStatus.currentStep == change_step) { +#ifdef CONFIG_REGULATOR + /*change the voltage*/ + mali_regulator_set_voltage(mali_dvfs[change_step].vol, mali_dvfs[change_step].vol); +#endif + /*change the clock*/ + mali_clk_set_rate(mali_dvfs[change_step].clock, mali_dvfs[change_step].freq); + +#if CPUFREQ_LOCK_DURING_440 + /* lock/unlock CPU freq by Mali */ + if (mali_dvfs[change_step].clock == 440) + err = cpufreq_lock_by_mali(1200); + else + cpufreq_unlock_by_mali(); +#endif + } + + return mali_dvfs[change_step].clock; +} + +void mali_default_step_set(int step, mali_bool boostup) +{ + mali_clk_set_rate(mali_dvfs[step].clock, mali_dvfs[step].freq); + + if (maliDvfsStatus.currentStep == 1) + set_mali_dvfs_status(step, boostup); +} + +int mali_dvfs_bottom_lock_push(int lock_step) +{ + int prev_status = _mali_osk_atomic_read(&bottomlock_status); + + if (prev_status < 0) { + MALI_PRINT(("gpu bottom lock status is not valid for push\n")); + return -1; + } + if (bottom_lock_step < lock_step) { + bottom_lock_step = lock_step; + if (get_mali_dvfs_status() < lock_step) { + mali_regulator_set_voltage(mali_dvfs[lock_step].vol, mali_dvfs[lock_step].vol); + mali_clk_set_rate(mali_dvfs[lock_step].clock, mali_dvfs[lock_step].freq); + set_mali_dvfs_current_step(lock_step); + } + } + return _mali_osk_atomic_inc_return(&bottomlock_status); +} + +int mali_dvfs_bottom_lock_pop(void) +{ + int prev_status = _mali_osk_atomic_read(&bottomlock_status); + if (prev_status <= 0) { + MALI_PRINT(("gpu bottom lock status is not valid for pop\n")); + return -1; + } else if (prev_status == 1) { + bottom_lock_step = 0; + MALI_PRINT(("gpu bottom lock release\n")); + } + + return _mali_osk_atomic_dec_return(&bottomlock_status); +} + +int mali_dvfs_get_vol(int step) +{ + step = step % MAX_MALI_DVFS_STEPS; + MALI_DEBUG_ASSERT(step= vol) + return mali_dvfs[i].vol; + } + MALI_PRINT(("Failed to get voltage from mali_dvfs table, maximum voltage is %d uV\n", mali_dvfs[MALI_DVFS_STEPS-1].vol)); + return 0; +} +#endif -- cgit v1.1