endif
ifeq ($(TARGET_PLATFORM),meson8)
-MALI_PLATFORM_FILES:= platform/meson8/arm_core_scaling.c \
- platform/meson8/meson_main.c
+MALI_PLATFORM_FILES:= platform/meson8/mali_scaling.c \
+ platform/meson8/meson_main.c \
+ platform/meson8/mali_clock.c
endif
ifneq ($(MALI_PLATFORM_FILES),)
return mask;
}
+
+
+/*
+ *
+ * kasin.li@amlogic.com.
+ **/
+
+u32 mali_pmu_get_status(struct mali_pmu_core * pmu)
+{
+ MALI_DEBUG_ASSERT_POINTER(pmu);
+ return mali_hw_core_register_read(&pmu->hw_core, PMU_REG_ADDR_MGMT_STATUS);
+
+}
* @return The Mali PMU object, or NULL if no PMU exists.
*/
struct mali_pmu_core *mali_pmu_get_global_pmu_core(void);
-
+/** @brief Retrieves the Mali Power Domain status.
+ *
+ * @return the Mali Power Domain status 1 off, 0 on.
+ */
+extern u32 mali_pmu_get_status(struct mali_pmu_core * pmu);
#endif /* __MALI_PMU_H__ */
};
-
-
-
-
int mali_module_init(void)
{
int err = 0;
#define POWER_BUFFER_SIZE 3
static struct dentry *mali_debugfs_dir = NULL;
+static struct dentry *mali_classfs_dir = NULL;
typedef enum
{
.owner = THIS_MODULE,
.read = pp_num_cores_total_read,
};
+#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON8
+extern u32 get_mali_def_freq_idx(void);
+extern void set_mali_freq_idx(u32 idx);
+extern u32 get_mali_qq_for_sched(void);
+extern void set_mali_qq_for_sched(u32 pp_num);
+extern u32 get_mali_schel_mode(void);
+extern void set_mali_schel_mode(u32 mode);
+static ssize_t pp_for_sched_read(struct file *filp, char __user *buf, size_t count, loff_t *offp)
+{
+ int r;
+ char buffer[64];
+ r = sprintf(buffer, "%d\n", get_mali_qq_for_sched());
+
+ return simple_read_from_buffer(buf, count, offp, buffer, r);
+}
+
+static ssize_t pp_for_sched_write(struct file *filp, const char __user *buf, size_t count, loff_t *offp)
+{
+ int ret;
+ char buffer[32];
+ unsigned long val;
+
+ if (count >= sizeof(buffer))
+ {
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(&buffer[0], buf, count))
+ {
+ return -EFAULT;
+ }
+ buffer[count] = '\0';
+
+ ret = strict_strtoul(&buffer[0], 10, &val);
+ if (0 != ret)
+ {
+ return -EINVAL;
+ }
+
+ set_mali_qq_for_sched(val);
+
+ *offp += count;
+ return count;
+}
+
+static const struct file_operations pp_for_sched_fops = {
+ .owner = THIS_MODULE,
+ .read = pp_for_sched_read,
+ .write = pp_for_sched_write,
+};
+
+static ssize_t cur_freq_read (struct file *filp, char __user *buf, size_t count, loff_t *offp)
+{
+ int r;
+ char buffer[64];
+ r = sprintf(buffer, "%d\n", get_mali_def_freq_idx());
+
+ return simple_read_from_buffer(buf, count, offp, buffer, r);
+}
+
+static ssize_t cur_freq_write (struct file *filp, const char __user *buf, size_t count, loff_t *offp)
+{
+ int ret;
+ char buffer[32];
+ unsigned long val;
+
+ if (count >= sizeof(buffer))
+ {
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(&buffer[0], buf, count))
+ {
+ return -EFAULT;
+ }
+ buffer[count] = '\0';
+
+ ret = strict_strtoul(&buffer[0], 10, &val);
+ if (0 != ret)
+ {
+ return -EINVAL;
+ }
+
+ set_mali_freq_idx(val);
+
+ *offp += count;
+ return count;
+}
+
+static const struct file_operations cur_freq_fops = {
+ .owner = THIS_MODULE,
+ .read = cur_freq_read,
+ .write = cur_freq_write,
+};
+
+static ssize_t scale_mode_read(struct file *filp, char __user *buf, size_t count, loff_t *offp)
+{
+ int r;
+ char buffer[64];
+ r = sprintf(buffer, "%d\n", get_mali_schel_mode());
+
+ return simple_read_from_buffer(buf, count, offp, buffer, r);
+}
+
+static ssize_t scale_mode_write(struct file *filp, const char __user *buf, size_t count, loff_t *offp)
+{
+ int ret;
+ char buffer[32];
+ unsigned long val;
+
+ if (count >= sizeof(buffer))
+ {
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(&buffer[0], buf, count))
+ {
+ return -EFAULT;
+ }
+ buffer[count] = '\0';
+
+ ret = strict_strtoul(&buffer[0], 10, &val);
+ if (0 != ret)
+ {
+ return -EINVAL;
+ }
+
+ set_mali_schel_mode(val);
+
+ *offp += count;
+ return count;
+}
+
+static const struct file_operations scale_mode_fops = {
+ .owner = THIS_MODULE,
+ .read = scale_mode_read,
+ .write = scale_mode_write
+};
+
+static ssize_t domain_stat_read(struct file *filp, char __user *buf, size_t count, loff_t *offp)
+{
+ struct mali_pmu_core *pmu;
+ int r;
+ char buffer[64];
+ pmu = mali_pmu_get_global_pmu_core();
+ r = sprintf(buffer, "%x\n", mali_pmu_get_status(pmu));
+
+ return simple_read_from_buffer(buf, count, offp, buffer, r);
+}
+
+static const struct file_operations domain_stat_fops = {
+ .owner = THIS_MODULE,
+ .read = domain_stat_read,
+};
+#endif /* MESON_CPU_TYPE_MESON8 */
static ssize_t version_read(struct file *filp, char __user *buf, size_t count, loff_t *offp)
{
debugfs_create_file("state_dump", 0400, mali_debugfs_dir, NULL, &mali_seq_internal_state_fops);
#endif
+#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON8
+ /* kasin.li@amlogic.com. misc setting. */
+ {
+ struct dentry *mali_misc_setting_dir = debugfs_create_dir("misc", mali_debugfs_dir);
+ if (mali_misc_setting_dir != NULL)
+ {
+ debugfs_create_file("pp_for_sched", 0600, mali_misc_setting_dir, NULL, &pp_for_sched_fops);
+ debugfs_create_file("cur_freq", 0600, mali_misc_setting_dir, NULL, &cur_freq_fops);
+ debugfs_create_file("scale_mode", 0600, mali_misc_setting_dir, NULL, &scale_mode_fops);
+ debugfs_create_file("domain_stat", 0600, mali_misc_setting_dir, NULL, &domain_stat_fops);
+ }
+ }
+#endif /* MESON_CPU_TYPE_MESON8 */
+
if (mali_sysfs_user_settings_register())
{
/* Failed to create the debugfs entries for the user settings DB. */
#include "mali_kernel_common.h"
#include <linux/workqueue.h>
+#include "mali_clock.h"
static int num_cores_total;
static int num_cores_enabled;
+static current_mali_clock_index;
static struct work_struct wq_work;
MALI_DEBUG_ASSERT(num_cores_total == num_cores_enabled);
}
-void mali_core_scaling_init(int num_pp_cores)
+void mali_core_scaling_init(int num_pp_cores, int clock_rate_index)
{
INIT_WORK(&wq_work, set_num_cores);
num_cores_total = num_pp_cores;
num_cores_enabled = num_pp_cores;
+ current_mali_clock_index = clock_rate_index;
/* NOTE: Mali is not fully initialized at this point. */
}
/* NOTE: this function is normally called directly from the utilization callback which is in
* timer context. */
- if ( PERCENT_OF(90, 256) < data->utilization_pp)
+ if (PERCENT_OF(90, 256) < data->utilization_pp)
{
enable_max_num_cores();
}
*
* @param num_pp_cores Total number of PP cores.
*/
-void mali_core_scaling_init(int num_pp_cores);
+void mali_core_scaling_init(int num_pp_cores, int clock_rate_index);
/**
* Terminate core scaling policy.
--- /dev/null
+#include <linux/platform_device.h>
+#include <linux/version.h>
+#include <linux/pm.h>
+#include <mach/register.h>
+#include <mach/irqs.h>
+#include <linux/io.h>
+#include <mach/io.h>
+#include <plat/io.h>
+#include <asm/io.h>
+#include "mali_clock.h"
+
+unsigned int mali_default_clock_step = MALI_CLOCK_637;
+
+int mali_clock_set(unsigned int clock) {
+ clrbits_le32(P_HHI_MALI_CLK_CNTL, 1 << 8);
+ clrbits_le32(P_HHI_MALI_CLK_CNTL, (0x7F | (0x7 << 9)));
+ writel(clock, P_HHI_MALI_CLK_CNTL | (1 << 8)); /* set clock to 333MHZ.*/
+ setbits_le32(P_HHI_MALI_CLK_CNTL, 1 << 8);
+}
--- /dev/null
+#ifndef _MALI_CLOCK_H_
+#define _MALI_CLOCK_H_
+
+typedef struct mali_dvfs_Tag{
+ unsigned int step;
+ unsigned int mali_clk;
+}mali_dvfs_table;
+
+typedef struct mali_dvfs_thresholdTag{
+ unsigned int downthreshold;
+ unsigned int upthreshold;
+}mali_dvfs_threshold_table;
+
+/* fclk is 2550Mhz. */
+#define FCLK_DEV3 (6 << 9) /* 850 Mhz */
+#define FCLK_DEV4 (5 << 9) /* 637.5 Mhz */
+#define FCLK_DEV5 (7 << 9) /* 510 Mhz */
+#define FCLK_DEV7 (4 << 9) /* 364.3 Mhz */
+
+enum mali_clock_rate {
+// MALI_CLOCK_91,
+ MALI_CLOCK_182 = 0,
+ MALI_CLOCK_318,
+ MALI_CLOCK_425,
+ MALI_CLOCK_637,
+
+ MALI_CLOCK_INDX_MAX
+};
+
+extern unsigned int mali_default_clock_step;
+extern unsigned int mali_dvfs_clk[];
+
+extern int mali_clock_set(unsigned int index);
+
+#endif /* _MALI_CLOCK_H_ */
--- /dev/null
+/*
+ * Copyright (C) 2013 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 arm_core_scaling.c
+ * Example core scaling policy.
+ */
+#include <linux/workqueue.h>
+#include <linux/mali/mali_utgard.h>
+#include "mali_kernel_common.h"
+#include "mali_scaling.h"
+#include "mali_clock.h"
+
+static int num_cores_total;
+static int num_cores_enabled;
+static int currentStep;
+static int lastStep;
+static struct work_struct wq_work;
+unsigned int utilization;
+
+
+unsigned int mali_dvfs_clk[] = {
+// FCLK_DEV7 | 3, /* 91 Mhz */
+ FCLK_DEV7 | 1, /* 182.1 Mhz */
+ FCLK_DEV4 | 1, /* 318.7 Mhz */
+ FCLK_DEV3 | 1, /* 425 Mhz */
+ FCLK_DEV4 | 0, /* 637.5 Mhz */
+};
+
+mali_dvfs_threshold_table mali_dvfs_threshold[]={
+ { 0 , 43 * 256 / 100 },
+ { 40 * 256 / 100, 53 * 256 / 100 },
+ { 50 * 256 / 100, 92 * 256 / 100 },
+ { 87 * 256 / 100, 256 }
+};
+
+static void do_scaling(struct work_struct *work)
+{
+ int err = mali_perf_set_num_pp_cores(num_cores_enabled);
+ MALI_DEBUG_ASSERT(0 == err);
+ MALI_IGNORE(err);
+ if (currentStep != lastStep) {
+ mali_dev_pause();
+ mali_clock_set (mali_dvfs_clk[currentStep]);
+ mali_dev_resume();
+ lastStep = currentStep;
+ }
+}
+
+static void enable_one_core(void)
+{
+ if (num_cores_enabled < num_cores_total)
+ {
+ ++num_cores_enabled;
+ schedule_work(&wq_work);
+ MALI_DEBUG_PRINT(3, ("Core scaling: Enabling one more core\n"));
+ }
+
+ MALI_DEBUG_ASSERT( 1 <= num_cores_enabled);
+ MALI_DEBUG_ASSERT(num_cores_total >= num_cores_enabled);
+}
+
+static void disable_one_core(void)
+{
+ if (1 < num_cores_enabled)
+ {
+ --num_cores_enabled;
+ schedule_work(&wq_work);
+ MALI_DEBUG_PRINT(3, ("Core scaling: Disabling one core\n"));
+ }
+
+ MALI_DEBUG_ASSERT( 1 <= num_cores_enabled);
+ MALI_DEBUG_ASSERT(num_cores_total >= num_cores_enabled);
+}
+
+static void enable_max_num_cores(void)
+{
+ if (num_cores_enabled < num_cores_total)
+ {
+ num_cores_enabled = num_cores_total;
+ schedule_work(&wq_work);
+ MALI_DEBUG_PRINT(3, ("Core scaling: Enabling maximum number of cores\n"));
+ }
+
+ MALI_DEBUG_ASSERT(num_cores_total == num_cores_enabled);
+}
+
+void mali_core_scaling_init(int num_pp_cores, int clock_rate_index)
+{
+ INIT_WORK(&wq_work, do_scaling);
+
+ num_cores_total = num_pp_cores;
+ num_cores_enabled = num_pp_cores;
+
+ currentStep = clock_rate_index;
+ lastStep = currentStep;
+ /* NOTE: Mali is not fully initialized at this point. */
+}
+
+void mali_core_scaling_term(void)
+{
+ flush_scheduled_work();
+}
+
+#define PERCENT_OF(percent, max) ((int) ((percent)*(max)/100.0 + 0.5))
+
+void mali_pp_scaling_update(struct mali_gpu_utilization_data *data)
+{
+ /*
+ * This function implements a very trivial PP core scaling algorithm.
+ *
+ * It is _NOT_ of production quality.
+ * The only intention behind this algorithm is to exercise and test the
+ * core scaling functionality of the driver.
+ * It is _NOT_ tuned for neither power saving nor performance!
+ *
+ * Other metrics than PP utilization need to be considered as well
+ * in order to make a good core scaling algorithm.
+ */
+
+ MALI_DEBUG_PRINT(3, ("Utilization: (%3d, %3d, %3d), cores enabled: %d/%d\n", data->utilization_gpu, data->utilization_gp, data->utilization_pp, num_cores_enabled, num_cores_total));
+
+ /* NOTE: this function is normally called directly from the utilization callback which is in
+ * timer context. */
+
+ if (PERCENT_OF(90, 256) < data->utilization_pp)
+ {
+ enable_max_num_cores();
+ }
+ else if (PERCENT_OF(50, 256) < data->utilization_pp)
+ {
+ enable_one_core();
+ }
+ else if (PERCENT_OF(40, 256) < data->utilization_pp)
+ {
+ /* do nothing */
+ }
+ else if (PERCENT_OF( 0, 256) < data->utilization_pp)
+ {
+ disable_one_core();
+ }
+ else
+ {
+ /* do nothing */
+ }
+}
+
+void mali_pp_fs_scaling_update(struct mali_gpu_utilization_data *data)
+{
+ MALI_DEBUG_PRINT(2, ("Utilization: (%3d, %3d, %3d), cores enabled: %d/%d\n", data->utilization_gpu, data->utilization_gp, data->utilization_pp, num_cores_enabled, num_cores_total));
+ MALI_DEBUG_PRINT(2, (" %d \n", currentStep));
+ utilization = data->utilization_gpu;
+
+ if (utilization > mali_dvfs_threshold[currentStep].upthreshold) {
+ currentStep = MALI_CLOCK_637;
+ if (data->utilization_pp > 230) // 90%
+ enable_max_num_cores();
+ else
+ enable_one_core();
+ } else if (utilization < mali_dvfs_threshold[currentStep].downthreshold && currentStep > 0) {
+ currentStep--;
+ MALI_DEBUG_PRINT(2, ("Mali clock set %d..\n",currentStep));
+ } else {
+ if (data->utilization_pp < mali_dvfs_threshold[0].upthreshold)
+ disable_one_core();
+ return;
+ }
+
+}
+
+void reset_mali_scaling_stat(void)
+{
+ printk(" ****** scaling mode reset to default.*****\n");
+ currentStep = mali_default_clock_step;
+ enable_max_num_cores();
+}
+
+void mali_fs_scaling_update(struct mali_gpu_utilization_data *data)
+{
+
+ utilization = data->utilization_gpu;
+
+ if (utilization > mali_dvfs_threshold[currentStep].upthreshold) {
+ currentStep = MALI_CLOCK_637;
+ } else if (utilization < mali_dvfs_threshold[currentStep].downthreshold && currentStep > 0) {
+ currentStep--;
+ MALI_DEBUG_PRINT(2, ("Mali clock set %d..\n",currentStep));
+ }
+}
+
+u32 get_mali_def_freq_idx(void)
+{
+ return mali_default_clock_step;
+}
+
+void set_mali_freq_idx(u32 idx)
+{
+ MALI_DEBUG_ASSERT(clock_rate_index < MALI_CLOCK_INDX_MAX);
+ currentStep = idx;
+ lastStep = MALI_CLOCK_INDX_MAX;
+ mali_default_clock_step = currentStep;
+ schedule_work(&wq_work);
+ /* NOTE: Mali is not fully initialized at this point. */
+}
+
+void set_mali_qq_for_sched(u32 pp_num)
+{
+ num_cores_total = pp_num;
+ num_cores_enabled = pp_num;
+ schedule_work(&wq_work);
+}
+
+u32 get_mali_qq_for_sched(void)
+{
+ return num_cores_total;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 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 arm_core_scaling.h
+ * Example core scaling policy.
+ */
+
+#ifndef __ARM_CORE_SCALING_H__
+#define __ARM_CORE_SCALING_H__
+
+#define MALI_PP_NUMBER 6
+
+struct mali_gpu_utilization_data;
+
+/**
+ * Initialize core scaling policy.
+ *
+ * @note The core scaling policy will assume that all PP cores are on initially.
+ *
+ * @param num_pp_cores Total number of PP cores.
+ */
+void mali_core_scaling_init(int num_pp_cores, int clock_rate_index);
+
+/**
+ * Terminate core scaling policy.
+ */
+void mali_core_scaling_term(void);
+
+/**
+ * Update core scaling policy with new utilization data.
+ *
+ * @param data Utilization data.
+ */
+extern void mali_pp_fs_scaling_update(struct mali_gpu_utilization_data *data);
+extern void mali_pp_scaling_update(struct mali_gpu_utilization_data *data);
+extern void mali_fs_scaling_update(struct mali_gpu_utilization_data *data);
+extern void reset_mali_scaling_stat(void);
+#endif /* __ARM_CORE_SCALING_H__ */
#include <linux/platform_device.h>
#include <linux/version.h>
#include <linux/pm.h>
+#include <linux/module.h> /* kernel module definitions */
+#include <linux/ioport.h> /* request_mem_region */
#include <mach/register.h>
#include <mach/irqs.h>
-#include <linux/io.h>
#include <mach/io.h>
-#include <plat/io.h>
#ifdef CONFIG_PM_RUNTIME
#include <linux/pm_runtime.h>
#endif
#include <linux/mali/mali_utgard.h>
#include "mali_kernel_common.h"
-#include "arm_core_scaling.h"
+#include "mali_scaling.h"
+#include "mali_clock.h"
+
+/* Configure dvfs mode */
+enum mali_scale_mode_t {
+ MALI_PP_SCALING,
+ MALI_FS_SCALING,
+ MALI_PP_FS_SCALING,
+ MALI_SCALING_DISABLE,
+ MALI_SCALING_MODE_MAX
+};
+
+static int scaling_mode = MALI_PP_FS_SCALING;
+module_param(scaling_mode, int, 0664);
+MODULE_PARM_DESC(scaling_mode, "0 disable, 1 pp, 2 fs, 4 double");
+static int last_scaling_mode;
static void mali_platform_device_release(struct device *device);
static void mali_platform_device_release(struct device *device);
static int mali_runtime_resume(struct device *device);
static int mali_runtime_idle(struct device *device);
#endif
-
-static DEFINE_SPINLOCK(lock);
-
void mali_gpu_utilization_callback(struct mali_gpu_utilization_data *data);
static struct resource mali_gpu_resources_m450[] =
int mali_platform_device_register(void)
{
- unsigned long flags;
int err = -1;
- int num_pp_cores = 6;
+ int num_pp_cores = MALI_PP_NUMBER;
- spin_lock_irqsave(&lock, flags);
- clrbits_le32(P_HHI_MALI_CLK_CNTL, 1 << 8);
- writel((5 << 9 | 0), P_HHI_MALI_CLK_CNTL); /* set clock to 333MHZ.*/
- readl(P_HHI_MALI_CLK_CNTL);
- setbits_le32(P_HHI_MALI_CLK_CNTL, 1 << 8);
- spin_unlock_irqrestore(&lock, flags);
+ mali_clock_set(mali_dvfs_clk[mali_default_clock_step]);
+ printk(" %x \n", mali_dvfs_clk[mali_default_clock_step]);
if (mali_gpu_data.shared_mem_size < 10) {
MALI_DEBUG_PRINT(2, ("mali os memory didn't configered, set to default(512M)\n"));
#endif
pm_runtime_enable(&(mali_gpu_device.dev));
#endif
+
MALI_DEBUG_ASSERT(0 < num_pp_cores);
- mali_core_scaling_init(num_pp_cores);
+ mali_core_scaling_init(num_pp_cores, mali_default_clock_step);
+ last_scaling_mode = scaling_mode;
return 0;
}
void mali_platform_device_unregister(void)
{
MALI_DEBUG_PRINT(4, ("mali_platform_device_unregister() called\n"));
-
mali_core_scaling_term();
platform_device_unregister(&mali_gpu_device);
}
void mali_gpu_utilization_callback(struct mali_gpu_utilization_data *data)
{
- mali_core_scaling_update(data);
+ if (last_scaling_mode != scaling_mode) {
+ reset_mali_scaling_stat();
+ last_scaling_mode = scaling_mode;
+ }
+ switch (scaling_mode) {
+ case MALI_PP_FS_SCALING:
+ mali_pp_fs_scaling_update(data);
+ break;
+ case MALI_PP_SCALING:
+ mali_pp_scaling_update(data);
+ break;
+ case MALI_FS_SCALING:
+ mali_fs_scaling_update(data);
+ break;
+ }
+}
+
+u32 get_mali_schel_mode(void)
+{
+ return scaling_mode;
+}
+void set_mali_schel_mode(u32 mode)
+{
+ MALI_DEBUG_ASSERT(mode < MALI_SCALING_MODE_MAX);
+ if (mode >= MALI_SCALING_MODE_MAX)return;
+ scaling_mode = mode;
+ reset_mali_scaling_stat();
}
static int mali_os_suspend(struct device *device)