@@ -39,6 +39,13 @@ config USING_GPU_UTILIZATION
---help---
This enables GPU utilization information.
+config USING_GPU_DEVFREQ
+ bool "GPU devfreq"
+ depends on MALI400MP && USING_GPU_UTILIZATION
+ default n
+ ---help---
+ This enables GPU devfreq.
+
config USING_MALI_RUN_TIME_PM
bool "Using Run time Power Management"
depends on MALI400MP
@@ -45,6 +45,10 @@ ifeq ($(CONFIG_USING_GPU_UTILIZATION),y)
USING_GPU_UTILIZATION =1
endif
+ifeq ($(CONFIG_USING_GPU_DEVFREQ),y)
+USING_GPU_DEVFREQ =1
+endif
+
ifeq ($(CONFIG_USING_MALI_RUN_TIME_PM),y)
USING_MALI_RUN_TIME_PM =1
endif
@@ -64,6 +68,7 @@ USING_UMP ?= 0
USING_OS_MEMORY ?= 0
USING_PMM ?= 0
USING_GPU_UTILIZATION ?= 0
+USING_GPU_DEVFREQ ?= 0
USING_MALI_RUN_TIME_PM ?= 0
USING_MALI_PMM_TESTSUITE ?= 0
OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB ?= 6
@@ -105,6 +110,7 @@ endif
DEFINES += -DUSING_MALI_PMM=$(USING_PMM)
DEFINES += -DMALI_GPU_UTILIZATION=$(USING_GPU_UTILIZATION)
+DEFINES += -DMALI_GPU_DEVFREQ=$(USING_GPU_DEVFREQ)
ifeq ($(CONFIG_DEBUG_BUILD),y)
DEFINES += -DDEBUG
@@ -201,9 +207,14 @@ mali-y += \
endif
ifeq ($(USING_GPU_UTILIZATION),1)
+ifeq ($(USING_GPU_DEVFREQ),1)
+mali-y += \
+ linux/mali_kernel_devfreq.o
+else
mali-y += \
common/mali_kernel_utilization.o
endif
+endif
ifneq ($(call submodule_enabled, $M, MALI400PP),0)
# Mali-400 PP in use
new file mode 100644
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2010-2011 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/devfreq.h>
+#include <linux/platform_device.h>
+#include "mali_kernel_devfreq.h"
+#include "mali_osk.h"
+#include "mali_platform.h"
+#include "mali_linux_pm.h"
+
+#define MALI_GPU_UTILIZATION_PERIOD 500
+
+static _mali_osk_lock_t *time_data_lock;
+
+static _mali_osk_atomic_t num_running_cores;
+
+static u64 period_start_time = 0;
+static u64 work_start_time = 0;
+static u64 accumulated_work_time = 0;
+static mali_bool timer_running = MALI_FALSE;
+
+static struct devfreq *mali_devfreq;
+
+static int mali_get_dev_status(struct device *dev,
+ struct devfreq_dev_status *stat)
+{
+ u64 time_now;
+ u64 time_period;
+
+ _mali_osk_lock_wait(time_data_lock, _MALI_OSK_LOCKMODE_RW);
+
+ if (accumulated_work_time == 0 && work_start_time == 0)
+ {
+ /* No work done for this period, report zero usage */
+ stat->total_time = 0;
+ stat->busy_time = 0;
+ stat->current_frequency = get_mali_platform_cur_freq();
+
+ _mali_osk_lock_signal(time_data_lock, _MALI_OSK_LOCKMODE_RW);
+
+ return 0;
+ }
+
+ time_now = _mali_osk_time_get_ns();
+ time_period = time_now - period_start_time;
+
+ /* If we are currently busy, update working period up to now */
+ if (work_start_time != 0)
+ {
+ accumulated_work_time += (time_now - work_start_time);
+ work_start_time = time_now;
+ }
+
+ stat->total_time = time_period;
+ stat->busy_time = accumulated_work_time;
+ stat->current_frequency = get_mali_platform_cur_freq();
+
+ accumulated_work_time = 0;
+ /* start a new period */
+ period_start_time = time_now;
+ _mali_osk_lock_signal(time_data_lock, _MALI_OSK_LOCKMODE_RW);
+
+ return 0;
+}
+
+static int mali_set_target_freq(struct device *dev,
+ unsigned long *freq,
+ u32 flags)
+{
+ mali_gpu_utilization_handler(*freq);
+ return 0;
+}
+
+static int mali_get_cur_freq(struct device *dev, unsigned long *freq)
+{
+ *freq = get_mali_platform_cur_freq();
+ return 0;
+}
+
+static struct devfreq_dev_profile mali_devfreq_profile = {
+ .polling_ms = MALI_GPU_UTILIZATION_PERIOD,
+ .initial_freq = 0,
+ .target = mali_set_target_freq,
+ .get_dev_status = mali_get_dev_status,
+ .get_cur_freq = mali_get_cur_freq,
+};
+
+_mali_osk_errcode_t mali_utilization_init(void)
+{
+ /* Register mali devfreq with ondemand governor */
+ mali_devfreq = devfreq_add_device(&mali_gpu_device.dev,
+ &mali_devfreq_profile,
+ &devfreq_simple_ondemand,
+ NULL);
+ if (NULL == mali_devfreq)
+ {
+ return _MALI_OSK_ERR_FAULT;
+ }
+
+ time_data_lock = _mali_osk_lock_init( 0, 0, 0 );
+ if (NULL == time_data_lock)
+ {
+ return _MALI_OSK_ERR_FAULT;
+ }
+
+ _mali_osk_atomic_init(&num_running_cores, 0);
+
+ return _MALI_OSK_ERR_OK;
+}
+
+void mali_utilization_suspend(void)
+{
+ if (timer_running == MALI_TRUE)
+ {
+ devfreq_suspend_device(mali_devfreq);
+ _mali_osk_lock_wait(time_data_lock, _MALI_OSK_LOCKMODE_RW);
+ timer_running = MALI_FALSE;
+ work_start_time = 0;
+ period_start_time = 0;
+ accumulated_work_time = 0;
+ _mali_osk_lock_signal(time_data_lock, _MALI_OSK_LOCKMODE_RW);
+ }
+}
+
+void mali_utilization_resume(void)
+{
+ devfreq_resume_device(mali_devfreq);
+}
+
+void mali_utilization_term(void)
+{
+ devfreq_remove_device(mali_devfreq);
+ mali_devfreq = NULL;
+
+ timer_running = MALI_FALSE;
+
+ _mali_osk_atomic_term(&num_running_cores);
+
+ _mali_osk_lock_term(time_data_lock);
+}
+
+void mali_utilization_core_start(void)
+{
+ if (_mali_osk_atomic_inc_return(&num_running_cores) == 1)
+ {
+ /*
+ * We went from zero cores working, to one core working,
+ * we now consider the entire GPU for being busy
+ */
+ _mali_osk_lock_wait(time_data_lock, _MALI_OSK_LOCKMODE_RW);
+
+ work_start_time = _mali_osk_time_get_ns();
+
+ if (timer_running != MALI_TRUE)
+ {
+ timer_running = MALI_TRUE;
+ period_start_time = work_start_time;
+ }
+
+ _mali_osk_lock_signal(time_data_lock, _MALI_OSK_LOCKMODE_RW);
+ }
+}
+
+void mali_utilization_core_end(void)
+{
+ if (_mali_osk_atomic_dec_return(&num_running_cores) == 0)
+ {
+ /*
+ * No more cores are working, so accumulate the time we was busy.
+ */
+ u64 time_now;
+
+ _mali_osk_lock_wait(time_data_lock, _MALI_OSK_LOCKMODE_RW);
+
+ time_now = _mali_osk_time_get_ns();
+ accumulated_work_time += (time_now - work_start_time);
+ work_start_time = 0;
+
+ _mali_osk_lock_signal(time_data_lock, _MALI_OSK_LOCKMODE_RW);
+ }
+}
new file mode 100644
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010-2011 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_KERNEL_DEVFREQ_H__
+#define __MALI_KERNEL_DEVFREQ_H__
+
+#include "mali_osk.h"
+
+/**
+ * Initialize/start the Mali GPU utilization metrics reporting.
+ *
+ * @return _MALI_OSK_ERR_OK on success, otherwise failure.
+ */
+_mali_osk_errcode_t mali_utilization_init(void);
+
+/**
+ * Terminate the Mali GPU utilization metrics reporting
+ */
+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
+ */
+void mali_utilization_suspend(void);
+
+/**
+ * Should be called to resume the utilization monitoring during
+ * system resume or device pm-runtime resume
+ */
+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__ */
@@ -40,6 +40,10 @@
#include "mali_kernel_utilization.h"
#endif /* MALI_GPU_UTILIZATION */
+#if MALI_GPU_DEVFREQ
+#include "mali_kernel_devfreq.h"
+#endif /* MALI_GPU_DEVFREQ */
+
#if MALI_POWER_MGMT_TEST_SUITE
#ifdef CONFIG_PM
#include "mali_linux_pm_testsuite.h"
@@ -418,6 +422,9 @@ static int mali_pm_os_resume_on_hibernation(struct device *dev)
*/
static int mali_device_runtime_suspend(struct device *dev)
{
+#if MALI_GPU_DEVFREQ
+ mali_utilization_suspend();
+#endif /* MALI_GPU_DEVFREQ */
MALI_DEBUG_PRINT(4, ("PMMDEBUG: Mali device Run time suspended \n" ));
return 0;
}
@@ -426,6 +433,9 @@ static int mali_device_runtime_suspend(struct device *dev)
*/
static int mali_device_runtime_resume(struct device *dev)
{
+#if MALI_GPU_DEVFREQ
+ mali_utilization_resume();
+#endif /* MALI_GPU_DEVFREQ */
MALI_DEBUG_PRINT(4, ("PMMDEBUG: Mali device Run time Resumed \n" ));
return 0;
}
@@ -40,4 +40,7 @@ void set_mali_parent_power_domain(void* dev)
{
}
-
+unsigned long get_mali_platform_cur_freq(void)
+{
+ return 0;
+}
@@ -93,6 +93,14 @@ void mali_gpu_utilization_handler(u32 utilization);
*/
void set_mali_parent_power_domain(void* dev);
+/** @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);
+
#ifdef __cplusplus
}
#endif