aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/samsung/mali/platform/pegasus-m400/mali_platform_dvfs.c
diff options
context:
space:
mode:
authorDorian Snyder <dastin1015@gmail.com>2014-06-15 01:24:33 -0700
committerDorian Snyder <dastin1015@gmail.com>2014-08-04 18:46:06 +0000
commitd90b43b963027b4d1559cec14e97117827a6458d (patch)
tree00d1334c383628e7d6f38a4f7ca0c575a4916d91 /drivers/media/video/samsung/mali/platform/pegasus-m400/mali_platform_dvfs.c
parent89e6992285b4274996b39cd953c0adb5e95a3236 (diff)
downloadkernel_samsung_smdk4412-d90b43b963027b4d1559cec14e97117827a6458d.zip
kernel_samsung_smdk4412-d90b43b963027b4d1559cec14e97117827a6458d.tar.gz
kernel_samsung_smdk4412-d90b43b963027b4d1559cec14e97117827a6458d.tar.bz2
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
Diffstat (limited to 'drivers/media/video/samsung/mali/platform/pegasus-m400/mali_platform_dvfs.c')
-rw-r--r--drivers/media/video/samsung/mali/platform/pegasus-m400/mali_platform_dvfs.c847
1 files changed, 847 insertions, 0 deletions
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 <linux/clk.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+
+#include <asm/io.h>
+
+#include "mali_device_pause_resume.h"
+#include <linux/workqueue.h>
+
+#define MAX_MALI_DVFS_STEPS 5
+#define MALI_DVFS_WATING 10 // msec
+
+#ifdef CONFIG_CPU_FREQ
+#include <mach/asv.h>
+#define EXYNOS4_ASV_ENABLED
+#endif
+
+#include <plat/cpu.h>
+
+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 <linux/types.h>
+#include <mach/cpufreq.h>
+
+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<MAX_MALI_DVFS_STEPS);
+
+ return mali_dvfs[step].vol;
+}
+
+#if MALI_VOLTAGE_LOCK
+int mali_vol_get_from_table(int vol)
+{
+ int i;
+ for (i = 0; i < MALI_DVFS_STEPS; i++) {
+ if (mali_dvfs[i].vol >= 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