aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVikas Sajjan <vikas.sajjan@linaro.org>2012-11-28 15:34:01 +0530
committerTushar Behera <tushar.behera@linaro.org>2013-03-14 10:47:21 +0530
commit1eb02a0125000a1893d869e161f0dfe9aa024497 (patch)
tree1a2fe6819ab877c7cdf6251c5d4cbe310f163fdd
parent7c461ce6389ed1bcd04970866b1493c5987b3bd9 (diff)
gpu: mali: Add devfreq platform support
This patch adds the devfreq platform support for Origen board. Signed-off-by: Vikas C Sajjan <vikas.sajjan@linaro.org> Signed-off-by: Tushar Behera <tushar.behera@linaro.org>
-rwxr-xr-xdrivers/gpu/arm/mali/Makefile4
-rw-r--r--drivers/gpu/arm/mali/linux/mali_kernel_devfreq.c1
-rw-r--r--drivers/gpu/arm/mali/linux/mali_kernel_devfreq.h11
-rw-r--r--drivers/gpu/arm/mali/platform/mach-origen/mali_devfreq.c422
-rw-r--r--drivers/gpu/arm/mali/platform/mach-origen/mali_devfreq.h49
-rw-r--r--drivers/gpu/arm/mali/platform/mach-origen/mali_platform.c365
-rw-r--r--drivers/gpu/arm/mali/platform/mali_platform.h116
7 files changed, 923 insertions, 45 deletions
diff --git a/drivers/gpu/arm/mali/Makefile b/drivers/gpu/arm/mali/Makefile
index 0e3d29d9b046..4a24d7490ec1 100755
--- a/drivers/gpu/arm/mali/Makefile
+++ b/drivers/gpu/arm/mali/Makefile
@@ -77,7 +77,7 @@ OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB ?= 6
USING_PROFILING ?= 0
USING_INTERNAL_PROFILING ?= 0
TIMESTAMP ?= default
-TARGET_PLATFORM ?= default
+TARGET_PLATFORM ?= mach-origen
ifeq ($(USING_UMP),1)
ifeq ($(USE_UMPV2),1)
@@ -109,7 +109,7 @@ DEFINES += -DMALI_OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB=$(OS_MEMORY_KERNEL_BUFFER_S
ifneq ($(call submodule_enabled, $M, PMU),0)
MALI_PLATFORM_FILE = platform/mali400-pmu/mali_platform.o
else
- MALI_PLATFORM_FILE = platform/$(TARGET_PLATFORM)/mali_platform.o
+ MALI_PLATFORM_FILE = platform/$(TARGET_PLATFORM)/mali_platform.o platform/$(TARGET_PLATFORM)/mali_devfreq.o
endif
DEFINES += -DUSING_MALI_PMM=$(USING_PMM)
diff --git a/drivers/gpu/arm/mali/linux/mali_kernel_devfreq.c b/drivers/gpu/arm/mali/linux/mali_kernel_devfreq.c
index 1213e7bc6946..da4435f297c0 100644
--- a/drivers/gpu/arm/mali/linux/mali_kernel_devfreq.c
+++ b/drivers/gpu/arm/mali/linux/mali_kernel_devfreq.c
@@ -66,7 +66,6 @@ static int mali_get_dev_status(struct device *dev,
/* start a new period */
period_start_time = time_now;
_mali_osk_lock_signal(time_data_lock, _MALI_OSK_LOCKMODE_RW);
-
return 0;
}
diff --git a/drivers/gpu/arm/mali/linux/mali_kernel_devfreq.h b/drivers/gpu/arm/mali/linux/mali_kernel_devfreq.h
index e0a76dcbb351..fa921eaeab7d 100644
--- a/drivers/gpu/arm/mali/linux/mali_kernel_devfreq.h
+++ b/drivers/gpu/arm/mali/linux/mali_kernel_devfreq.h
@@ -26,11 +26,6 @@ _mali_osk_errcode_t mali_utilization_init(void);
void mali_utilization_term(void);
/**
- * Should be called when a job is about to execute a job
- */
-void mali_utilization_core_start(void);
-
-/**
* Should be called to suspend the utilization monitoring during
* system suspend or device pm-runtime suspend
*/
@@ -42,10 +37,4 @@ void mali_utilization_suspend(void);
*/
void mali_utilization_resume(void);
-/**
- * Should be called when a job has completed executing a job
- */
-void mali_utilization_core_end(void);
-
-
#endif /* __MALI_KERNEL_DEVFREQ_H__ */
diff --git a/drivers/gpu/arm/mali/platform/mach-origen/mali_devfreq.c b/drivers/gpu/arm/mali/platform/mach-origen/mali_devfreq.c
new file mode 100644
index 000000000000..b9d23d61f600
--- /dev/null
+++ b/drivers/gpu/arm/mali/platform/mach-origen/mali_devfreq.c
@@ -0,0 +1,422 @@
+ /*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ * Vikas Sajjan <vikas.sajjan@samsung.com>
+ *
+ * EXYNOS4 - MALI frequency/voltage scaling support in DEVFREQ framework
+ * This version supports only EXYNOS4412 only.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/suspend.h>
+#include <linux/opp.h>
+#include <linux/devfreq.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/module.h>
+
+#include <mach/regs-clock.h>
+#include "mali_kernel_common.h"
+#include "mali_osk.h"
+#include "mali_platform.h"
+#include "mali_devfreq.h"
+#include <plat/map-s5p.h>
+
+/* dvfs status */
+struct mali_dvfs_status maliDvfsStatus;
+
+#define MAX_MALI_DVFS_STEPS 4
+#define MALI_DVFS_STEPS 4
+
+int mali_dvfs_control;
+
+struct mali_dvfs_threshold_tbl {
+ unsigned int downthreshold;
+ unsigned int upthreshold;
+};
+
+struct mali_dvfs_staycount {
+ unsigned int staycount;
+};
+
+struct mali_dvfs_threshold_tbl mali_dvfs_threshold[MALI_DVFS_STEPS] = {
+ {0, 70},
+ {50, 70},
+ {50, 85},
+ {75, 100}
+};
+
+struct mali_dvfs_staycount mali_dvfs_staycount[MALI_DVFS_STEPS] = {
+ /*step 0*/{1},
+ /*step 1*/{1},
+ /*step 2*/{1},
+ /*step 3*/{1}
+};
+
+/* dvfs information */
+/* L0 = 440Mhz, 1.025V */
+/* L1 = 350Mhz, 0.95V */
+/* L2 = 266Mhz, 0.90V */
+/* L3 = 160Mhz, 0.875V */
+
+int step0_clk = 160;
+int step0_vol = 875000;
+int step1_clk = 266;
+int step1_vol = 900000;
+int step0_up = 70;
+int step1_down = 50;
+int step2_clk = 350;
+int step2_vol = 950000;
+int step1_up = 70;
+int step2_down = 50;
+int step3_clk = 440;
+int step3_vol = 1025000;
+int step2_up = 85;
+int step3_down = 75;
+
+struct mali_dvfs_stp {
+ int clk;
+ int vol;
+};
+
+struct mali_dvfs_tbl mali_dvfs_value[MALI_DVFS_STEPS] = {
+ { 160, 1000000, 875000 },
+ { 266, 1000000, 900000 },
+ { 350, 1000000, 950000 },
+ { 440, 1000000, 1025000} };
+
+struct mali_dvfs_stp step[MALI_DVFS_STEPS] = {
+ /* step 0 clk */ { 160, 875000 },
+ /* step 1 clk */ { 266, 900000 },
+ /* step 2 clk */ { 350, 950000 },
+ /* step 3 clk */ { 440, 1025000 }
+};
+
+int change_dvfs_tableset(int change_clk, int change_step)
+{
+ if (change_clk < mali_dvfs_value[1].clock) {
+ mali_dvfs_value[change_step].clock = mali_dvfs_value[0].clock;
+ mali_dvfs_value[change_step].vol = mali_dvfs_value[0].vol;
+ } else if (change_clk < mali_dvfs_value[2].clock && change_clk >=
+ mali_dvfs_value[1].clock) {
+ mali_dvfs_value[change_step].clock = mali_dvfs_value[1].clock;
+ mali_dvfs_value[change_step].vol = mali_dvfs_value[1].vol;
+ } else if (change_clk < mali_dvfs_value[3].clock && change_clk >=
+ mali_dvfs_value[2].clock) {
+ mali_dvfs_value[change_step].clock = mali_dvfs_value[2].clock;
+ mali_dvfs_value[change_step].vol = mali_dvfs_value[2].vol;
+ } else {
+ mali_dvfs_value[change_step].clock = mali_dvfs_value[3].clock;
+ mali_dvfs_value[change_step].vol = mali_dvfs_value[3].vol;
+ }
+
+ if (maliDvfsStatus.currentStep == change_step) {
+ /* change the voltage */
+ mali_regulator_set_voltage(mali_dvfs_value[change_step].vol,
+ mali_dvfs_value[change_step].vol);
+ /* change the clock */
+ mali_clk_set_rate(mali_dvfs_value[change_step].clock,
+ mali_dvfs_value[change_step].freq);
+ }
+
+ return mali_dvfs_value[change_step].clock;
+}
+
+mali_bool set_mali_dvfs_current_step(unsigned int step)
+{
+ _mali_osk_lock_wait(mali_dvfs_lock, _MALI_OSK_LOCKMODE_RW);
+ maliDvfsStatus.currentStep = step;
+ _mali_osk_lock_signal(mali_dvfs_lock, _MALI_OSK_LOCKMODE_RW);
+ return MALI_TRUE;
+}
+
+static mali_bool set_mali_dvfs_status(u32 step, mali_bool boostup)
+{
+ u32 validatedStep = step;
+
+ if (mali_regulator_get_usecount() == 0)
+ return MALI_FALSE;
+
+ if (boostup) {
+ /* change the voltage */
+ mali_regulator_set_voltage(mali_dvfs_value[step].vol,
+ mali_dvfs_value[step].vol);
+ /* change the clock */
+ mali_clk_set_rate(mali_dvfs_value[step].clock,
+ mali_dvfs_value[step].freq);
+ } else {
+ /* change the clock */
+ mali_clk_set_rate(mali_dvfs_value[step].clock,
+ mali_dvfs_value[step].freq);
+ /* change the voltage */
+ mali_regulator_set_voltage(mali_dvfs_value[step].vol,
+ mali_dvfs_value[step].vol);
+ }
+
+ set_mali_dvfs_current_step(validatedStep);
+
+ /* for future use */
+ maliDvfsStatus.pCurrentDvfs = &mali_dvfs_value[validatedStep];
+
+ return MALI_TRUE;
+}
+
+static void mali_platform_waiting(u32 msec)
+{
+ unsigned int read_val;
+ while (1) {
+ read_val = _mali_osk_mem_ioread32(
+ clk_register_map,
+ 0x00);
+ if ((read_val & 0x8000) == 0x0000)
+ break;
+ /* 1000 -> 100 : 20101218 */
+ _mali_osk_time_ubusydelay(100);
+ }
+}
+
+static mali_bool change_mali_dvfs_status(u32 step, mali_bool boostup)
+{
+ if (!set_mali_dvfs_status(step, boostup))
+ return MALI_FALSE;
+
+ /* wait until clock and voltage is stablized */
+ mali_platform_waiting(MALI_DVFS_WAITING); /* msec */
+ return MALI_TRUE;
+}
+
+static unsigned int decideNextStatus(unsigned int mali_dvfs_freq)
+{
+ static unsigned int level; /* 0:stay, 1:up */
+ static int mali_dvfs_clk;
+
+ if (!mali_dvfs_control && level == maliDvfsStatus.currentStep) {
+ if (mali_dvfs_freq >
+ (int)((mali_dvfs_value[maliDvfsStatus.currentStep].clock *
+ mali_dvfs_value[maliDvfsStatus.currentStep].freq))
+ && level < MALI_DVFS_STEPS - 1) {
+ level++;
+ }
+ if (mali_dvfs_freq <
+ (int)((mali_dvfs_value[maliDvfsStatus.currentStep].clock *
+ mali_dvfs_value[maliDvfsStatus.currentStep].freq))
+ && 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_value[i].clock;
+#ifdef EXYNOS4_ASV_ENABLED
+ mali_dvfs_table_update();
+#endif
+ i = 0;
+ for (i = 0; i < MALI_DVFS_STEPS; i++)
+ mali_dvfs_value[i].clock = step[i].clk;
+
+ mali_dvfs_control = 0;
+ level = 0;
+
+ step0_clk = step[0].clk;
+ change_dvfs_tableset(step0_clk, 0);
+
+ step1_clk = step[1].clk;
+ change_dvfs_tableset(step1_clk, 1);
+
+ step2_clk = step[2].clk;
+ change_dvfs_tableset(step2_clk, 2);
+
+ step3_clk = step[3].clk;
+ change_dvfs_tableset(step3_clk, 3);
+
+ } else if (mali_dvfs_control != mali_dvfs_clk && mali_dvfs_control
+ != 999) {
+ if (mali_dvfs_control < mali_dvfs_value[1].clock
+ && mali_dvfs_control > 0) {
+ int i = 0;
+ for (i = 0; i < MALI_DVFS_STEPS; i++)
+ step[i].clk = mali_dvfs_value[0].clock;
+ } else if (mali_dvfs_control < mali_dvfs_value[2].clock
+ && mali_dvfs_control >= mali_dvfs_value[1].clock) {
+ int i = 0;
+ for (i = 0; i < MALI_DVFS_STEPS; i++)
+ step[i].clk = mali_dvfs_value[1].clock;
+ } else if (mali_dvfs_control < mali_dvfs_value[3].clock
+ && mali_dvfs_control >= mali_dvfs_value[2].clock) {
+ int i = 0;
+ for (i = 0; i < MALI_DVFS_STEPS; i++)
+ step[i].clk = mali_dvfs_value[2].clock;
+ } else {
+ int i = 0;
+ for (i = 0; i < MALI_DVFS_STEPS; i++)
+ step[i].clk = mali_dvfs_value[3].clock;
+ }
+
+ step0_clk = step[0].clk;
+ change_dvfs_tableset(step0_clk, 0);
+ step1_clk = step[1].clk;
+ change_dvfs_tableset(step1_clk, 1);
+ step2_clk = step[2].clk;
+ change_dvfs_tableset(step2_clk, 2);
+ step3_clk = step[3].clk;
+ change_dvfs_tableset(step3_clk, 3);
+ level = maliDvfsStatus.currentStep;
+ }
+
+ mali_dvfs_clk = mali_dvfs_control;
+ return level;
+}
+
+static unsigned int get_mali_dvfs_status(void)
+{
+ return maliDvfsStatus.currentStep;
+}
+
+static mali_bool mali_dvfs_status(u32 mali_dvfs_freq)
+{
+ unsigned int nextStatus = 0;
+ unsigned int curStatus = 0;
+ mali_bool boostup = MALI_FALSE;
+ static int stay_count;
+#ifdef EXYNOS4_ASV_ENABLED
+ static mali_bool asv_applied = MALI_FALSE;
+#endif
+#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(mali_dvfs_freq);
+
+ /* 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))
+ return MALI_FALSE;
+ stay_count =
+ mali_dvfs_staycount[maliDvfsStatus.currentStep].staycount;
+ } else {
+ if (stay_count > 0)
+ stay_count--;
+ }
+ return MALI_TRUE;
+}
+
+mali_bool init_mali_dvfs_status(int step)
+{
+ set_mali_dvfs_current_step(step);
+ return MALI_TRUE;
+}
+
+void deinit_mali_dvfs_status(void)
+{
+ if (clk_register_map) {
+ _mali_osk_mem_unmapioregion(CLK_DIV_STAT_G3D,
+ 0x20,
+ clk_register_map);
+ clk_register_map = 0;
+ }
+}
+
+void mali_default_step_set(int step, mali_bool boostup)
+{
+ mali_clk_set_rate(mali_dvfs_value[step].clock,
+ mali_dvfs_value[step].freq);
+ if (maliDvfsStatus.currentStep == 1)
+ set_mali_dvfs_status(step, boostup);
+}
+
+void mali_gpu_utilization_handler(u32 mali_dvfs_freq)
+{
+ int change_clk = 0;
+ int change_step = 0;
+
+ /* dvfs table change when clock was changed */
+ if (step0_clk != mali_dvfs_value[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 (step1_clk != mali_dvfs_value[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 (step2_clk != mali_dvfs_value[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 (step3_clk != mali_dvfs_value[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;
+ }
+#ifdef DEBUG
+ mali_dvfs_value[0].vol = step0_vol;
+ mali_dvfs_value[1].vol = step1_vol;
+ mali_dvfs_value[2].vol = step2_vol;
+ mali_dvfs_value[3].vol = step3_vol;
+#endif
+ MALI_DEBUG_PRINT(3, ("=== mali_dvfs_work_handler\n"));
+
+ if (!mali_dvfs_status(mali_dvfs_freq))
+ MALI_DEBUG_PRINT(1, ("error on mali dvfs status"
+ "in mali_dvfs_work_handler"));
+
+}
+/** @brief Get MALI current running frequency
+ *
+ * This function gets the current running frequency of MALI
+ *
+ * @return frequency in Hz
+ */
+unsigned long get_mali_platform_cur_freq(void)
+{
+ unsigned long rate = 0;
+ rate = mali_clk_get_rate();
+ return rate;
+}
diff --git a/drivers/gpu/arm/mali/platform/mach-origen/mali_devfreq.h b/drivers/gpu/arm/mali/platform/mach-origen/mali_devfreq.h
new file mode 100644
index 000000000000..47e4a8f888dc
--- /dev/null
+++ b/drivers/gpu/arm/mali/platform/mach-origen/mali_devfreq.h
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#ifndef __MALI_DEVFREQ_H__
+#define __MALI_DEVFREQ_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MALI_DVFS_STAY_AFTER_CHANGE 1 /* stay count after clock change */
+#define MALI_DVFS_DEFAULT_STEP 0 /* 134Mhz default */
+#define GPU_DVFS_UP_THRESHOLD ((int)((255*65)/100)) /* 60% */
+#define GPU_DVFS_DOWN_THRESHOLD ((int)((255*30)/100)) /* 30% */
+#define MALI_DVFS_WAITING 10 /* msec */
+
+extern struct regulator *g3d_regulator;
+extern mali_io_address clk_register_map;
+extern _mali_osk_lock_t *mali_dvfs_lock;
+
+struct mali_dvfs_tbl {
+ unsigned int clock;
+ unsigned int freq;
+ unsigned int vol;
+};
+
+struct mali_dvfs_status {
+ unsigned int currentStep;
+ struct mali_dvfs_tbl *pCurrentDvfs;
+};
+
+mali_bool init_mali_dvfs_status(int step);
+
+void deinit_mali_dvfs_status(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/drivers/gpu/arm/mali/platform/mach-origen/mali_platform.c b/drivers/gpu/arm/mali/platform/mach-origen/mali_platform.c
new file mode 100644
index 000000000000..c6f9513b5532
--- /dev/null
+++ b/drivers/gpu/arm/mali/platform/mach-origen/mali_platform.c
@@ -0,0 +1,365 @@
+/*
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+#include "mali_kernel_common.h"
+#include "mali_osk.h"
+#include "mali_platform.h"
+#include "mali_devfreq.h"
+#include "mali_linux_pm.h"
+
+#define MALI_DVFS_ENABLED 1
+
+#define EXTXTALCLK_NAME "ext_xtal"
+#define VPLLSRCCLK_NAME "vpll_src"
+#define FOUTVPLLCLK_NAME "fout_vpll"
+#define SCLVPLLCLK_NAME "sclk_vpll"
+#define GPUMOUT1CLK_NAME "mout_g3d1"
+
+static struct clk *ext_xtal_clock;
+static struct clk *vpll_src_clock;
+static struct clk *fout_vpll_clock;
+static struct clk *sclk_vpll_clock;
+
+int gpu_power_state;
+static struct clk *mpll_clock;
+static struct clk *mali_parent_clock;
+struct regulator *g3d_regulator;
+static struct clk *mali_clock;
+static unsigned int GPU_MHZ = 1000000;
+int mali_gpu_clk = 266;
+int mali_gpu_vol = 900000;
+
+mali_io_address clk_register_map;
+_mali_osk_lock_t *mali_dvfs_lock;
+
+mali_bool mali_clk_get(mali_bool bis_vpll);
+
+unsigned long mali_clk_get_rate(void)
+{
+ return clk_get_rate(mali_clock);
+}
+
+mali_bool mali_clk_set_rate(unsigned int clk, unsigned int mhz)
+{
+ unsigned long rate = 0;
+ mali_bool bis_vpll = MALI_TRUE;
+
+ _mali_osk_lock_wait(mali_dvfs_lock, _MALI_OSK_LOCKMODE_RW);
+ if (mali_clk_get(bis_vpll) == MALI_FALSE)
+ return MALI_FALSE;
+ rate = (unsigned long)clk * (unsigned long)mhz;
+ if (bis_vpll) {
+ clk_set_rate(fout_vpll_clock, (unsigned int)clk * GPU_MHZ);
+ clk_set_parent(vpll_src_clock, ext_xtal_clock);
+ clk_set_parent(sclk_vpll_clock, fout_vpll_clock);
+ clk_set_parent(mali_parent_clock, sclk_vpll_clock);
+ clk_set_parent(mali_clock, mali_parent_clock);
+ } else {
+ clk_set_parent(mali_parent_clock, mpll_clock);
+ clk_set_parent(mali_clock, mali_parent_clock);
+ }
+
+ if (clk_enable(mali_clock) < 0)
+ return MALI_FALSE;
+
+ clk_set_rate(mali_clock, rate);
+ rate = clk_get_rate(mali_clock);
+
+ if (bis_vpll)
+ mali_gpu_clk = (int)(rate / mhz);
+ else
+ mali_gpu_clk = (int)((rate + 500000) / mhz);
+
+ GPU_MHZ = mhz;
+
+ mali_clk_put(MALI_FALSE);
+
+ _mali_osk_lock_signal(mali_dvfs_lock, _MALI_OSK_LOCKMODE_RW);
+ return MALI_TRUE;
+}
+
+int mali_regulator_get_usecount(void)
+{
+ struct regulator_dev *rdev;
+ if (g3d_regulator == NULL || g3d_regulator->rdev == NULL)
+ return 0;
+ rdev = g3d_regulator->rdev;
+ return rdev->use_count;
+}
+
+void mali_regulator_disable(void)
+{
+ if (g3d_regulator == NULL)
+ return;
+ regulator_disable(g3d_regulator);
+}
+
+void mali_regulator_enable(void)
+{
+ if (g3d_regulator == NULL)
+ return;
+ regulator_enable(g3d_regulator);
+}
+
+void mali_regulator_set_voltage(int min_uV, int max_uV)
+{
+ int voltage;
+ if (g3d_regulator == NULL)
+ return;
+ regulator_set_voltage(g3d_regulator, min_uV, max_uV);
+ voltage = regulator_get_voltage(g3d_regulator);
+ mali_gpu_vol = voltage;
+}
+
+mali_bool mali_clk_get(mali_bool bis_vpll)
+{
+ if (bis_vpll == MALI_TRUE) {
+ if (ext_xtal_clock == NULL) {
+ ext_xtal_clock = clk_get(NULL, EXTXTALCLK_NAME);
+ if (IS_ERR(ext_xtal_clock))
+ return MALI_FALSE;
+ }
+
+ if (vpll_src_clock == NULL) {
+ vpll_src_clock = clk_get(NULL, VPLLSRCCLK_NAME);
+ if (IS_ERR(vpll_src_clock))
+ return MALI_FALSE;
+ }
+
+ if (fout_vpll_clock == NULL) {
+ fout_vpll_clock = clk_get(NULL, FOUTVPLLCLK_NAME);
+ if (IS_ERR(fout_vpll_clock))
+ return MALI_FALSE;
+ }
+
+ if (sclk_vpll_clock == NULL) {
+ sclk_vpll_clock = clk_get(NULL, SCLVPLLCLK_NAME);
+ if (IS_ERR(sclk_vpll_clock))
+ return MALI_FALSE;
+ }
+
+ if (mali_parent_clock == NULL) {
+ mali_parent_clock = clk_get(NULL, GPUMOUT1CLK_NAME);
+ if (IS_ERR(mali_parent_clock))
+ return MALI_FALSE;
+ } /* mpll */
+ } else {
+ if (mpll_clock == NULL) {
+ mpll_clock = clk_get(NULL, MPLLCLK_NAME);
+
+ if (IS_ERR(mpll_clock))
+ return MALI_FALSE;
+ }
+
+ if (mali_parent_clock == NULL) {
+ mali_parent_clock = clk_get(NULL, GPUMOUT0CLK_NAME);
+ if (IS_ERR(mali_parent_clock))
+ return MALI_FALSE;
+ }
+ }
+ /* mali clock get always */
+ if (mali_clock == NULL) {
+ mali_clock = clk_get(NULL, GPUCLK_NAME);
+ if (IS_ERR(mali_clock))
+ return MALI_FALSE;
+ }
+ return MALI_TRUE;
+}
+
+void mali_clk_put(mali_bool binc_mali_clock)
+{
+ if (mali_parent_clock) {
+ clk_put(mali_parent_clock);
+ mali_parent_clock = 0;
+ }
+ if (mpll_clock) {
+ clk_put(mpll_clock);
+ mpll_clock = 0;
+ }
+ if (sclk_vpll_clock) {
+ clk_put(sclk_vpll_clock);
+ sclk_vpll_clock = 0;
+ }
+ if (fout_vpll_clock) {
+ clk_put(fout_vpll_clock);
+ fout_vpll_clock = 0;
+ }
+ if (vpll_src_clock) {
+ clk_put(vpll_src_clock);
+ vpll_src_clock = 0;
+ }
+ if (ext_xtal_clock) {
+ clk_put(ext_xtal_clock);
+ ext_xtal_clock = 0;
+ }
+ if (binc_mali_clock == MALI_TRUE && mali_clock) {
+ clk_put(mali_clock);
+ mali_clock = 0;
+ }
+}
+
+static mali_bool init_mali_clock(void)
+{
+ mali_bool ret = MALI_TRUE;
+ unsigned long rate = 0;
+ gpu_power_state = 0;
+
+ if (mali_clock != 0)
+ return ret; /* already initialized */
+
+ mali_dvfs_lock = _mali_osk_lock_init(
+ _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE |
+ _MALI_OSK_LOCKFLAG_ONELOCK, 0, 0);
+ if (mali_dvfs_lock == NULL)
+ return _MALI_OSK_ERR_FAULT;
+
+ if (mali_clk_set_rate(mali_gpu_clk, GPU_MHZ) == MALI_FALSE) {
+ ret = MALI_FALSE;
+ goto err_clock_get;
+ }
+
+ rate = clk_get_rate(mali_clock);
+
+ return MALI_TRUE;
+
+err_clock_get:
+ mali_clk_put(MALI_TRUE);
+ return ret;
+}
+
+static mali_bool deinit_mali_clock(void)
+{
+ if (mali_clock == 0)
+ return MALI_TRUE;
+
+ if (g3d_regulator) {
+ regulator_put(g3d_regulator);
+ g3d_regulator = NULL;
+ }
+ mali_clk_put(MALI_TRUE);
+ return MALI_TRUE;
+}
+
+static _mali_osk_errcode_t disable_mali_clocks(void)
+{
+ clk_disable(mali_clock);
+ MALI_SUCCESS;
+}
+
+static _mali_osk_errcode_t enable_mali_clocks(void)
+{
+ int err;
+ err = clk_enable(mali_clock);
+ mali_clk_set_rate(mali_gpu_clk, GPU_MHZ);
+ MALI_SUCCESS;
+}
+
+_mali_osk_errcode_t mali_platform_init(void)
+{
+#if MALI_DVFS_ENABLED
+ MALI_CHECK(init_mali_clock(), _MALI_OSK_ERR_FAULT);
+ init_mali_regulator();
+ if (!clk_register_map)
+ clk_register_map =
+ _mali_osk_mem_mapioregion(CLK_DIV_STAT_G3D, 0x20, CLK_DESC);
+ if (!init_mali_dvfs_status(MALI_DVFS_DEFAULT_STEP))
+ MALI_DEBUG_PRINT(1, ("mali_platform_init failed\n"));
+#endif
+ MALI_SUCCESS;
+}
+
+_mali_osk_errcode_t mali_platform_deinit(void)
+{
+ deinit_mali_dvfs_status();
+
+ deinit_mali_clock();
+
+ if (clk_register_map) {
+ _mali_osk_mem_unmapioregion(CLK_DIV_STAT_G3D,
+ 0x20,
+ clk_register_map);
+ clk_register_map = 0;
+ }
+ deinit_mali_regulator();
+ MALI_SUCCESS;
+}
+
+_mali_osk_errcode_t mali_platform_power_mode_change(mali_power_mode power_mode)
+{
+ MALI_SUCCESS;
+}
+
+_mali_osk_errcode_t mali_platform_powerdown(u32 cores)
+{
+ /* power down after state is 0 */
+ if (gpu_power_state != 0) {
+ gpu_power_state = gpu_power_state & (~cores);
+ if (gpu_power_state == 0) {
+ MALI_DEBUG_PRINT(3, ("disable clock\n"));
+ disable_mali_clocks();
+ }
+ } else {
+ }
+ MALI_SUCCESS;
+}
+
+_mali_osk_errcode_t mali_platform_powerup(u32 cores)
+{
+ /* power down after state is 0 */
+ if (gpu_power_state == 0) {
+ gpu_power_state = gpu_power_state | cores;
+ if (gpu_power_state != 0)
+ enable_mali_clocks();
+ } else {
+ gpu_power_state = gpu_power_state | cores;
+ }
+ MALI_SUCCESS;
+}
+
+void set_mali_parent_power_domain(void *dev)
+{
+ return;
+}
+
+mali_bool init_mali_regulator(void)
+{
+ mali_bool ret;
+ g3d_regulator = regulator_get(NULL, "vdd_g3d");
+ if (IS_ERR(g3d_regulator)) {
+ ret = MALI_FALSE;
+ goto err_regulator;
+ }
+
+ regulator_enable(g3d_regulator);
+ mali_regulator_set_voltage(mali_gpu_vol, mali_gpu_vol);
+ return MALI_TRUE;
+
+err_regulator:
+ regulator_put(g3d_regulator);
+ return ret;
+}
+
+mali_bool deinit_mali_regulator(void)
+{
+ if (g3d_regulator) {
+ regulator_put(g3d_regulator);
+ g3d_regulator = NULL;
+ }
+
+ return MALI_TRUE;
+}
diff --git a/drivers/gpu/arm/mali/platform/mali_platform.h b/drivers/gpu/arm/mali/platform/mali_platform.h
index f1bb2b5c7ad4..3d2a4ee56cb3 100644
--- a/drivers/gpu/arm/mali/platform/mali_platform.h
+++ b/drivers/gpu/arm/mali/platform/mali_platform.h
@@ -1,25 +1,31 @@
/*
* 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.
+ * 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.
+ * 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.h
- * Platform specific Mali driver functions
- */
-
#ifndef __MALI_PLATFORM_H__
#define __MALI_PLATFORM_H__
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+
+
#include "mali_osk.h"
#if !USING_MALI_PMM
-/* @brief System power up/down cores that can be passed into mali_platform_powerdown/up() */
+/* @brief System power up/down cores that can be passed into
+ * mali_platform_powerdown/up()
+ */
#define MALI_PLATFORM_SYSTEM 0
#endif
@@ -27,8 +33,14 @@
extern "C" {
#endif
-/** @brief description of power change reasons
- */
+#define MPLLCLK_NAME "mout_mpll"
+#define GPUMOUT0CLK_NAME "mout_g3d0"
+#define GPUCLK_NAME "sclk_g3d"
+#define CLK_DIV_STAT_G3D 0x1003C62C
+#define CLK_DESC "clk-divider-status"
+
+extern struct platform_device mali_gpu_device;
+/* @brief description of power change reasons */
typedef enum mali_power_mode_tag
{
MALI_POWER_MODE_ON,
@@ -36,11 +48,45 @@ typedef enum mali_power_mode_tag
MALI_POWER_MODE_DEEP_SLEEP,
} mali_power_mode;
+struct regulator {
+ struct device *dev;
+ struct list_head list;
+ unsigned int always_on:1;
+ unsigned int bypass:1;
+ int uA_load;
+ int min_uV;
+ int max_uV;
+ char *supply_name;
+ struct device_attribute dev_attr;
+ struct regulator_dev *rdev;
+ struct dentry *debugfs;
+};
+
+int mali_regulator_get_usecount(void);
+
+void mali_regulator_disable(void);
+
+void mali_regulator_enable(void);
+
+void mali_regulator_set_voltage(int min_uV, int max_uV);
+
+mali_bool mali_clk_set_rate(unsigned int clk, unsigned int mhz);
+
+unsigned long mali_clk_get_rate(void);
+
+void mali_clk_put(mali_bool binc_mali_clock);
+
+mali_bool init_mali_regulator(void);
+
+mali_bool deinit_mali_regulator(void);
+
+
/** @brief Platform specific setup and initialisation of MALI
*
* This is called from the entrypoint of the driver to initialize the platform
*
- * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error.
+ * @return _MALI_OSK_ERR_OK on success otherwise, a suitable
+ * _mali_osk_errcode_t error.
*/
_mali_osk_errcode_t mali_platform_init(void);
@@ -48,48 +94,56 @@ _mali_osk_errcode_t mali_platform_init(void);
*
* This is called on the exit of the driver to terminate the platform
*
- * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error.
+ * @return _MALI_OSK_ERR_OK on success otherwise, a suitable
+ * _mali_osk_errcode_t error.
*/
_mali_osk_errcode_t mali_platform_deinit(void);
/** @brief Platform specific powerdown sequence of MALI
*
* Call as part of platform init if there is no PMM support, else the
- * PMM will call it.
+ * PMM will call it.
* There are three power modes defined:
* 1) MALI_POWER_MODE_ON
* 2) MALI_POWER_MODE_LIGHT_SLEEP
* 3) MALI_POWER_MODE_DEEP_SLEEP
- * MALI power management module transitions to MALI_POWER_MODE_LIGHT_SLEEP mode when MALI is idle
- * for idle timer (software timer defined in mali_pmm_policy_jobcontrol.h) duration, MALI transitions
- * to MALI_POWER_MODE_LIGHT_SLEEP mode during timeout if there are no more jobs queued.
- * MALI power management module transitions to MALI_POWER_MODE_DEEP_SLEEP mode when OS does system power
- * off.
- * Customer has to add power down code when MALI transitions to MALI_POWER_MODE_LIGHT_SLEEP or MALI_POWER_MODE_DEEP_SLEEP
+ * MALI power management module transitions to MALI_POWER_MODE_LIGHT_SLEEP mode
+ * when MALI is idle for idle timer (software timer defined in
+ * mali_pmm_policy_jobcontrol.h) duration, MALI transitions to
+ * MALI_POWER_MODE_LIGHT_SLEEP mode during timeout if there are no more
+ * jobs queued.
+ * MALI power management module transitions to MALI_POWER_MODE_DEEP_SLEEP mode
+ * when OS does system power off.
+ * Customer has to add power down code when MALI transitions to
+ * MALI_POWER_MODE_LIGHT_SLEEP or MALI_POWER_MODE_DEEP_SLEEP
* mode.
- * MALI_POWER_MODE_ON mode is entered when the MALI is to powered up. Some customers want to control voltage regulators during
- * the whole system powers on/off. Customer can track in this function whether the MALI is powered up from
- * MALI_POWER_MODE_LIGHT_SLEEP or MALI_POWER_MODE_DEEP_SLEEP mode and manage the voltage regulators as well.
+ * MALI_POWER_MODE_ON mode is entered when the MALI is to powered up.
+ * Some customers want to control voltage regulators during the whole system
+ * powers on/off. Customer can track in this function whether the MALI is
+ * powered up from MALI_POWER_MODE_LIGHT_SLEEP or MALI_POWER_MODE_DEEP_SLEEP
+ * mode and manage the voltage regulators as well.
* @param power_mode defines the power modes
- * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error.
+ * @return _MALI_OSK_ERR_OK on success otherwise, a suitable
+ * _mali_osk_errcode_t error.
*/
_mali_osk_errcode_t mali_platform_power_mode_change(mali_power_mode power_mode);
-
/** @brief Platform specific handling of GPU utilization data
*
* When GPU utilization data is enabled, this function will be
* periodically called.
*
- * @param utilization The workload utilization of the Mali GPU. 0 = no utilization, 256 = full utilization.
+ * @param utilization The workload utilization of the Mali GPU.
+ * 0 = no utilization, 256 = full utilization.
*/
void mali_gpu_utilization_handler(u32 utilization);
/** @brief Setting the power domain of MALI
*
- * This function sets the power domain of MALI if Linux run time power management is enabled
- *
- * @param dev Reference to struct platform_device (defined in linux) used by MALI GPU
+ * This function sets the power domain of MALI if Linux run time power
+ * management is enabled
+ * @param dev Reference to struct platform_device (defined in linux) used by
+ * MALI GPU
*/
void set_mali_parent_power_domain(void* dev);