aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/arm/mali/platform/mach-origen/mali_platform.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/arm/mali/platform/mach-origen/mali_platform.c')
-rw-r--r--drivers/gpu/arm/mali/platform/mach-origen/mali_platform.c365
1 files changed, 365 insertions, 0 deletions
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;
+}