/* * 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