From 096ef17ea3975fac278cc06b96f0dcfbc135d9e8 Mon Sep 17 00:00:00 2001 From: Show Liu Date: Tue, 20 May 2014 15:27:07 +0800 Subject: add exynos 5250 arndale support --- drivers/gpu/arm/midgard/platform/Kconfig | 24 + drivers/gpu/arm/midgard/platform/arndale/Kbuild | 14 + drivers/gpu/arm/midgard/platform/arndale/Kconfig | 37 + .../platform/arndale/mali_kbase_config_arndale.c | 2815 ++++++++++++++++++++ .../platform/arndale/mali_linux_dvfs_trace.h | 69 + .../platform/arndale/mali_linux_hwc_trace.h | 262 ++ 6 files changed, 3221 insertions(+) create mode 100755 drivers/gpu/arm/midgard/platform/Kconfig create mode 100644 drivers/gpu/arm/midgard/platform/arndale/Kbuild create mode 100644 drivers/gpu/arm/midgard/platform/arndale/Kconfig create mode 100644 drivers/gpu/arm/midgard/platform/arndale/mali_kbase_config_arndale.c create mode 100644 drivers/gpu/arm/midgard/platform/arndale/mali_linux_dvfs_trace.h create mode 100644 drivers/gpu/arm/midgard/platform/arndale/mali_linux_hwc_trace.h diff --git a/drivers/gpu/arm/midgard/platform/Kconfig b/drivers/gpu/arm/midgard/platform/Kconfig new file mode 100755 index 00000000000..58248afe4b2 --- /dev/null +++ b/drivers/gpu/arm/midgard/platform/Kconfig @@ -0,0 +1,24 @@ +# +# (C) COPYRIGHT 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. +# +# + + + + +# Add your platform specific Kconfig file here +# +source "drivers/gpu/arm/midgard/platform/arndale/Kconfig" +# +# Where xxx is the platform name is the name set in MALI_PLATFORM_THIRDPARTY_NAME +# + diff --git a/drivers/gpu/arm/midgard/platform/arndale/Kbuild b/drivers/gpu/arm/midgard/platform/arndale/Kbuild new file mode 100644 index 00000000000..bdcc83aa402 --- /dev/null +++ b/drivers/gpu/arm/midgard/platform/arndale/Kbuild @@ -0,0 +1,14 @@ +# Copyright: +# ---------------------------------------------------------------------------- +# This confidential and proprietary software may be used only as authorized +# by a licensing agreement from ARM Limited. +# (C) COPYRIGHT 2012 ARM Limited, ALL RIGHTS RESERVED +# The entire notice above must be reproduced on all authorized copies and +# copies may only be made to the extent permitted by a licensing agreement +# from ARM Limited. +# ---------------------------------------------------------------------------- +# + +SRC += $(MALI_PLATFORM_THIRDPARTY_DIR)/mali_kbase_config_arndale.c + +obj-y += mali_kbase_config_arndale.o diff --git a/drivers/gpu/arm/midgard/platform/arndale/Kconfig b/drivers/gpu/arm/midgard/platform/arndale/Kconfig new file mode 100644 index 00000000000..d4d518645e0 --- /dev/null +++ b/drivers/gpu/arm/midgard/platform/arndale/Kconfig @@ -0,0 +1,37 @@ +# +# (C) COPYRIGHT 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. +# +# +if MALI_PLATFORM_THIRDPARTY_NAME = "arndale" + +menu "Arndale options" + depends on MALI_T6XX && MALI_EXPERT && MALI_PLATFORM_THIRDPARTY + +config T6XX_DVFS_FREQ_LOCK + bool "Enable dvfs frequency lock support" + depends on MALI_T6XX_DVFS && MALI_EXPERT + default n + help + Choose this option to enable locking the DVFS frequency. If sysfs + support is enabled files will be created for inspecting and + (potentially) setting a fixed DVFS frequency. This is used + for debugging; enable only if you know what you are doing. + +config MALI_HWC_TRACE + bool "Enable hardware counter event tracing support" + depends on MALI_T6XX && MALI_EXPERT + default n + help + Choose this option to enable collecting hardware counter data + with system trace events. This is typically used for debugging + but has minimal overhead when not in use. Enable only if you + know what you are doing. + +endmenu +endif diff --git a/drivers/gpu/arm/midgard/platform/arndale/mali_kbase_config_arndale.c b/drivers/gpu/arm/midgard/platform/arndale/mali_kbase_config_arndale.c new file mode 100644 index 00000000000..455437c0c4b --- /dev/null +++ b/drivers/gpu/arm/midgard/platform/arndale/mali_kbase_config_arndale.c @@ -0,0 +1,2815 @@ +/* + * + * (C) COPYRIGHT 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. + * + */ + +#define CREATE_TRACE_POINTS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +//#include +#include <../common.h> +#include +#include +#include +#include +#include +#if defined(CONFIG_MALI_T6XX_DVFS) && defined(CONFIG_CPU_FREQ) +#include +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +//#include + +#include "mali_linux_dvfs_trace.h" + +#define MALI_DVFS_DEBUG 0 +#define MALI_DVFS_STEP 8 +#define MALI_DVFS_KEEP_STAY_CNT 10 + +#ifdef CONFIG_MALI_T6XX_DVFS +#define KBASE_PM_DVFS_FREQUENCY (100) /* 100ms */ +#ifdef CONFIG_CPU_FREQ +#define MALI_DVFS_ASV_ENABLE +#endif +#endif + +#ifdef MALI_DVFS_ASV_ENABLE +#define MALI_DVFS_ASV_GROUP_SPECIAL_NUM 10 +#define MALI_DVFS_ASV_GROUP_NUM 13 +#endif + +#define HZ_IN_MHZ (1000000) +#define MALI_RTPM_DEBUG 0 +#define RUNTIME_PM_DELAY_TIME 10 +#define CONFIG_T6XX_HWVER_R0P0 1 +#define G3D_ASV_VOL_OFFSET 25000 + +struct regulator *kbase_platform_get_regulator(void); +int kbase_platform_regulator_init(void); +int kbase_platform_regulator_disable(void); +int kbase_platform_regulator_enable(void); +int kbase_platform_get_default_voltage(struct device *dev, int *vol); +int kbase_platform_get_voltage(struct device *dev, int *vol); +#if defined CONFIG_MALI_T6XX_DVFS +static int kbase_platform_set_voltage(struct device *dev, int vol); +static void kbase_platform_dvfs_set_clock(kbase_device *kbdev, int freq); +static void kbase_platform_dvfs_set_level(kbase_device *kbdev, int level); +static int kbase_platform_dvfs_get_level(int freq); +#endif + +#if defined(CONFIG_MALI_T6XX_DVFS) || defined(CONFIG_MALI_T6XX_DEBUG_SYS) +struct mali_dvfs_info { + unsigned int voltage; + unsigned int clock; + int min_threshold; + int max_threshold; + int up_cnt_threshold; + int down_cnt_threshold; +}; +static struct mali_dvfs_info *mali_dvfs_infotbl; +#endif + +#ifdef CONFIG_MALI_T6XX_DVFS +/* + * Governor parameters. The governor gets periodic samples of the + * GPU utilisation (%busy) and maintains a weighted average over the + * last DVFS_AVG_LPF_LEN values. When the average is in the range + * [min_threshold..max_threshold] we maintain the current clock+voltage. + * If the utilisation drops below min for down_cnt_threshold samples + * we step down. If the utilisation exceeds max_threshold for + * up_cnt_threshold samples we step up. + * + * The up/down thresholds are chosen to enable fast step up under + * load with a longer step down; this optimizes for performance over + * power consumption. 266MHz is the "sweet spot"; it has the best + * performance/power ratio. For this reason it has slightly extended + * up/down thresholds to make it "sticky". + */ +/* TODO(sleffler) round or verify time is a multiple of frequency */ +/* convert a time in milliseconds to a dvfs sample count */ +#define DVFS_TIME_TO_CNT(t) ((t) / KBASE_PM_DVFS_FREQUENCY) + +/* TODO(sleffler) should be const but for voltage */ +static struct mali_dvfs_info mali_dvfs_infotbl_exynos5250[MALI_DVFS_STEP] = { +/* A duumy level is added in 5250 to make 8 levels. Since, max_threshold + * value of step 6 is 100, the dvfs code will never come to dummy step 7 + */ +#if (MALI_DVFS_STEP == 8) + { 912500, 100000000, 0, 60, DVFS_TIME_TO_CNT(750), DVFS_TIME_TO_CNT(2000)}, + { 925000, 160000000, 40, 75, DVFS_TIME_TO_CNT(750), DVFS_TIME_TO_CNT(2000)}, + {1025000, 266000000, 65, 85, DVFS_TIME_TO_CNT(1000), DVFS_TIME_TO_CNT(3000)}, + {1075000, 350000000, 65, 85, DVFS_TIME_TO_CNT(750), DVFS_TIME_TO_CNT(1500)}, + {1125000, 400000000, 65, 85, DVFS_TIME_TO_CNT(750), DVFS_TIME_TO_CNT(1500)}, + {1025000, 450000000, 65, 90, DVFS_TIME_TO_CNT(1000), DVFS_TIME_TO_CNT(1500)}, + {1250000, 533000000, 75, 100, DVFS_TIME_TO_CNT(750), DVFS_TIME_TO_CNT(1500)}, + {1250000, 533000000, 75, 100, DVFS_TIME_TO_CNT(750), DVFS_TIME_TO_CNT(1500)} + +#else +#error no table +#endif +}; + +static struct mali_dvfs_info mali_dvfs_infotbl_exynos5420[MALI_DVFS_STEP] = { +#if (MALI_DVFS_STEP == 8) + { 862500, 100000000, 0, 60, DVFS_TIME_TO_CNT(750), DVFS_TIME_TO_CNT(2000)}, + { 862500, 177000000, 40, 75, DVFS_TIME_TO_CNT(750), DVFS_TIME_TO_CNT(2000)}, + { 862500, 266000000, 65, 85, DVFS_TIME_TO_CNT(1000), DVFS_TIME_TO_CNT(3000)}, + { 900000, 350000000, 65, 85, DVFS_TIME_TO_CNT(750), DVFS_TIME_TO_CNT(1500)}, + { 937500, 420000000, 65, 85, DVFS_TIME_TO_CNT(750), DVFS_TIME_TO_CNT(1500)}, + { 950000, 480000000, 65, 90, DVFS_TIME_TO_CNT(1000), DVFS_TIME_TO_CNT(1500)}, + { 987500, 533000000, 75, 90, DVFS_TIME_TO_CNT(750), DVFS_TIME_TO_CNT(1500)}, + {1025000, 600000000, 75, 100, DVFS_TIME_TO_CNT(750), DVFS_TIME_TO_CNT(1500)} + +#else +#error no table +#endif +}; +int kbase_platform_dvfs_init(kbase_device *kbdev); +void kbase_platform_dvfs_term(void); +int kbase_platform_dvfs_get_control_status(void); +int kbase_platform_dvfs_get_utilisation(void); + +#ifdef MALI_DVFS_ASV_ENABLE + +static const unsigned int (*mali_dvfs_asv_vol_tbl_special)[MALI_DVFS_STEP]; +static const unsigned int (*mali_dvfs_asv_vol_tbl)[MALI_DVFS_STEP]; +static const unsigned int *mali_dvfs_vol_default; + +static const unsigned int mali_dvfs_asv_vol_tbl_special_exynos5250 + [MALI_DVFS_ASV_GROUP_SPECIAL_NUM][MALI_DVFS_STEP] = { + /* 100Mh 160Mh 266Mh 350Mh 400Mh 450Mh 533Mh*/ + {/*Group 1*/ + 912500, 925000, 1025000, 1075000, 1100000, 1150000, 1225000, + 1225000, + }, + {/*Group 2*/ + 900000, 900000, 1000000, 1037500, 1087500, 1125000, 1200000, + 1200000, + }, + {/*Group 3*/ + 912500, 925000, 1025000, 1037500, 1100000, 1150000, 1225000, + 1225000, + }, + {/*Group 4*/ + 900000, 900000, 1000000, 1025000, 1087500, 1125000, 1200000, + 1200000, + }, + {/*Group 5*/ + 912500, 925000, 1000000, 1000000, 1125000, 1150000, 1250000, + 1250000, + }, + {/*Group 6*/ + 900000, 912500, 987500, 987500, 1112500, 1150000, 1237500, + 1237500, + }, + {/*Group 7*/ + 900000, 900000, 975000, 987500, 1100000, 1137500, 1225000, + 1225000, + }, + {/*Group 8*/ + 900000, 900000, 975000, 987500, 1100000, 1137500, 1225000, + 1225000, + }, + {/*Group 9*/ + 887500, 900000, 962500, 975000, 1087500, 1125000, 1212500, + 1212500, + }, + {/*Group 10*/ + 887500, 900000, 962500, 962500, 1087500, 1125000, 1212500, + 1212500, + }, +}; + +static const unsigned int mali_dvfs_asv_vol_tbl_exynos5250 + [MALI_DVFS_ASV_GROUP_NUM][MALI_DVFS_STEP] = { + /* 100Mh 160Mh 266Mh 350Mh, 400Mh 450Mh 533Mh*/ + {/*Group 0*/ + 925000, 925000, 1025000, 1075000, 1125000, 1150000, 1200000, + 1200000, + }, + {/*Group 1*/ + 900000, 900000, 1000000, 1037500, 1087500, 1137500, 1187500, + 1187500, + }, + {/*Group 2*/ + 900000, 900000, 950000, 1037500, 1075000, 1125000, 1187500, + 1187500, + }, + {/*Group 3*/ + 900000, 900000, 950000, 1037500, 1075000, 1125000, 1187500, + 1187500, + }, + {/*Group 4*/ + 900000, 900000, 937500, 1025000, 1075000, 1112500, 1175000, + 1175000, + }, + {/*Group 5*/ + 900000, 900000, 937500, 1000000, 1050000, 1100000, 1150000, + 1150000, + }, + {/*Group 6*/ + 900000, 900000, 925000, 987500, 1037500, 1087500, 1137500, + 1137500, + }, + {/*Group 7*/ + 900000, 900000, 912500, 987500, 1025000, 1075000, 1125000, + 1125000, + }, + {/*Group 8*/ + 900000, 900000, 912500, 987500, 1012500, 1075000, 1125000, + 1112500, + }, + {/*Group 9*/ + 900000, 900000, 900000, 975000, 1012500, 1050000, 1125000, + 1112500, + }, + {/*Group 10*/ + 875000, 900000, 900000, 962500, 1000000, 1050000, 1112500, + 1112500, + }, + {/*Group 11*/ + 875000, 900000, 900000, 962500, 1000000, 1050000, 1112500, + 1112500, + }, + {/*Group 12*/ /*Same as Group 11 because other socs may need more ASV groups*/ + 875000, 900000, 900000, 962500, 1000000, 1050000, 1112500, + 1112500, + }, +}; + +static const unsigned int mali_dvfs_vol_default_exynos5250[MALI_DVFS_STEP] = { + 925000, 925000, 1025000, 1075000, 1125000, 1150000, 1200000, 1200000 +}; + +static int kbase_platform_asv_set(int enable); +#endif /* MALI_DVFS_ASV_ENABLE */ +#endif /* CONFIG_MALI_T6XX_DVFS */ + +int kbase_platform_cmu_pmu_control(struct kbase_device *kbdev, int control); +void kbase_platform_remove_sysfs_file(struct device *dev); +mali_error kbase_platform_init(struct kbase_device *kbdev); +static int kbase_platform_is_power_on(void); +void kbase_platform_term(struct kbase_device *kbdev); + +#ifdef CONFIG_MALI_T6XX_DEBUG_SYS +static int kbase_platform_create_sysfs_file(struct device *dev); +#ifdef CONFIG_MALI_HWC_TRACE +static int mali_setup_system_tracing(struct device *dev); +static void mali_cleanup_system_tracing(struct device *dev); +#endif /* CONFIG_MALI_HWC_TRACE */ +#endif /* CONFIG_MALI_T6XX_DEBUG_SYS */ + +#ifdef CONFIG_MALI_T6XX_DVFS +static struct mali_dvfs_status mali_dvfs_status_current; +#endif /* CONFIG_MALI_T6XX_DVFS */ + +struct exynos_context +{ + /** Indicator if system clock to mail-t604 is active */ + int cmu_pmu_status; + /** cmd & pmu lock */ + spinlock_t cmu_pmu_lock; + struct clk *sclk_g3d; + int t6xx_default_clock; +}; +#ifndef CONFIG_OF +static kbase_io_resources io_resources_exynos5250 = +{ + .job_irq_number = EXYNOS5_JOB_IRQ_NUMBER, + .mmu_irq_number = EXYNOS5_MMU_IRQ_NUMBER, + .gpu_irq_number = EXYNOS5_GPU_IRQ_NUMBER, + .io_memory_region = + { + .start = EXYNOS5_PA_G3D, + .end = EXYNOS5_PA_G3D + (4096 * 5) - 1 + } +}; +#endif + +/** + * Read the CPU clock speed + */ +int get_cpu_clock_speed(u32* cpu_clock) +{ + struct clk * cpu_clk; + u32 freq=0; + cpu_clk = clk_get(NULL, "armclk"); + if (IS_ERR(cpu_clk)) + return 1; + freq = clk_get_rate(cpu_clk); + *cpu_clock = (freq/HZ_IN_MHZ); + return 0; +} + +/** + * Power Management callback - power ON + */ +static int pm_callback_power_on(kbase_device *kbdev) +{ +#ifdef CONFIG_PM_RUNTIME + pm_runtime_resume(kbdev->dev); +#endif /* CONFIG_PM_RUNTIME */ + return 0; +} + +/** + * Power Management callback - power OFF + */ +static void pm_callback_power_off(kbase_device *kbdev) +{ +#ifdef CONFIG_PM_RUNTIME + pm_schedule_suspend(kbdev->dev, RUNTIME_PM_DELAY_TIME); +#endif /* CONFIG_PM_RUNTIME */ +} + +static kbase_pm_callback_conf pm_callbacks = +{ + .power_on_callback = pm_callback_power_on, + .power_off_callback = pm_callback_power_off, +}; + +/** + * Exynos5 hardware specific initialization + */ +mali_bool kbase_platform_exynos5_init(kbase_device *kbdev) +{ + if(MALI_ERROR_NONE == kbase_platform_init(kbdev)) + { +#ifdef CONFIG_MALI_T6XX_DEBUG_SYS + if(kbase_platform_create_sysfs_file(kbdev->osdev.dev)) + { + return MALI_TRUE; + } +#endif /* CONFIG_MALI_T6XX_DEBUG_SYS */ + return MALI_TRUE; + } + + return MALI_FALSE; +} + +/** + * Exynos5 hardware specific termination + */ +void kbase_platform_exynos5_term(kbase_device *kbdev) +{ +#ifdef CONFIG_MALI_T6XX_DEBUG_SYS + kbase_platform_remove_sysfs_file(kbdev->osdev.dev); +#endif /* CONFIG_MALI_T6XX_DEBUG_SYS */ + kbase_platform_term(kbdev); +} + +kbase_platform_funcs_conf platform_funcs = +{ + .platform_init_func = &kbase_platform_exynos5_init, + .platform_term_func = &kbase_platform_exynos5_term, +}; + +const kbase_attribute config_attributes_exynos5250[] = { +#if 0 + { + KBASE_CONFIG_ATTR_MEMORY_OS_SHARED_MAX, + 2048 * 1024 * 1024UL /* 2048MB */ + }, + + { + KBASE_CONFIG_ATTR_MEMORY_OS_SHARED_PERF_GPU, + KBASE_MEM_PERF_FAST + }, +#endif + { + KBASE_CONFIG_ATTR_POWER_MANAGEMENT_CALLBACKS, + (uintptr_t)&pm_callbacks + }, +#ifdef CONFIG_MALI_T6XX_DVFS + { + KBASE_CONFIG_ATTR_POWER_MANAGEMENT_DVFS_FREQ, + KBASE_PM_DVFS_FREQUENCY /* 100ms */ + }, +#endif /* CONFIG_MALI_T6XX_DVFS */ + { + KBASE_CONFIG_ATTR_PLATFORM_FUNCS, + (uintptr_t)&platform_funcs + }, + + { + KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MAX, + 533000 + }, + { + KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MIN, + 100000 + }, + { + KBASE_CONFIG_ATTR_JS_RESET_TIMEOUT_MS, + 500 /* 500ms before cancelling stuck jobs */ + }, + { + KBASE_CONFIG_ATTR_CPU_SPEED_FUNC, + (uintptr_t)&get_cpu_clock_speed + }, + { + KBASE_CONFIG_ATTR_END, + 0 + } +}; + +const kbase_attribute config_attributes_exynos5420[] = { +#if 0 + { + KBASE_CONFIG_ATTR_MEMORY_OS_SHARED_MAX, + 2048 * 1024 * 1024UL /* 2048MB */ + /* TODO: Once we have 4GB available we can change this*/ + }, + + { + KBASE_CONFIG_ATTR_MEMORY_OS_SHARED_PERF_GPU, + KBASE_MEM_PERF_FAST + }, +#endif + { + KBASE_CONFIG_ATTR_POWER_MANAGEMENT_CALLBACKS, + (uintptr_t)&pm_callbacks + }, +#ifdef CONFIG_MALI_T6XX_DVFS + { + KBASE_CONFIG_ATTR_POWER_MANAGEMENT_DVFS_FREQ, + KBASE_PM_DVFS_FREQUENCY /* 100ms */ + }, +#endif + { + KBASE_CONFIG_ATTR_PLATFORM_FUNCS, + (uintptr_t)&platform_funcs + }, + + { + KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MAX, + 533000 + }, + { + KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MIN, + 100000 + }, + { + KBASE_CONFIG_ATTR_JS_RESET_TIMEOUT_MS, + 500 /* 500ms before cancelling stuck jobs */ + }, + { + KBASE_CONFIG_ATTR_CPU_SPEED_FUNC, + (uintptr_t)&get_cpu_clock_speed + }, + { + KBASE_CONFIG_ATTR_END, + 0 + } +}; + +kbase_platform_config chromebook_platform_config; +kbase_platform_config *kbase_get_platform_config(void) { + if (soc_is_exynos5250()) + { + + chromebook_platform_config.attributes = config_attributes_exynos5250; +#ifndef CONFIG_OF + chromebook_platform_config.io_resources = &io_resources_exynos5250; +#endif + chromebook_platform_config.midgard_type = KBASE_MALI_T604; + return &chromebook_platform_config; + } + + return NULL; +} + +static struct clk *clk_g3d = NULL; + +/** + * Initialize GPU clocks + */ +static int kbase_platform_power_clock_init(kbase_device *kbdev) +{ + struct device *dev = kbdev->dev; + int timeout; + struct exynos_context *platform; + + platform = (struct exynos_context *) kbdev->platform_context; + if(NULL == platform) + { + panic("oops"); + } + + /* Turn on G3D power */ + __raw_writel(0x7, EXYNOS5_G3D_CONFIGURATION); + + /* Wait for G3D power stability for 1ms */ + timeout = 10; + while((__raw_readl(EXYNOS5_G3D_STATUS) & 0x7) != 0x7) { + if(timeout == 0) { + /* need to call panic */ + panic("failed to turn on g3d power\n"); + goto out; + } + timeout--; + udelay(100); + } + + /* Turn on G3D clock */ + clk_g3d = clk_get(dev, "g3d"); + if (IS_ERR(clk_g3d)) { + clk_g3d = NULL; + printk(KERN_ERR "failed to clk_get [clk_g3d]\n"); + /* chrome linux does not have this clock */ + } + else + { + /* android_v4 support */ + clk_prepare_enable(clk_g3d); + printk("v4 support\n"); + } + +#ifdef CONFIG_T6XX_HWVER_R0P0 + platform->sclk_g3d = clk_get(dev, "aclk_g3d"); + if(IS_ERR(platform->sclk_g3d)) { + printk(KERN_ERR "failed to clk_get [aclk_g3d]\n"); + goto out; + } +#else /* CONFIG_T6XX_HWVER_R0P0 */ + { + struct clk *mpll = NULL; + mpll = clk_get(dev, "mout_mpll_user"); + if(IS_ERR(mpll)) { + printk(KERN_ERR "failed to clk_get [mout_mpll_user]\n"); + goto out; + } + + platform->sclk_g3d = clk_get(dev, "sclk_g3d"); + if(IS_ERR(platform->sclk_g3d)) { + printk(KERN_ERR "failed to clk_get [sclk_g3d]\n"); + goto out; + } + + clk_set_parent(platform->sclk_g3d, mpll); + if(IS_ERR(platform->sclk_g3d)) { + printk(KERN_ERR "failed to clk_set_parent\n"); + goto out; + } + + clk_set_rate(platform->sclk_g3d, platform->t6xx_default_clock); + if (IS_ERR(platform->sclk_g3d)) { + printk(KERN_ERR "failed to clk_set_rate [sclk_g3d] = %d\n", + platform->t6xx_default_clock); + goto out; + } + } +#endif /* CONFIG_T6XX_HWVER_R0P0 */ + (void) clk_prepare_enable(platform->sclk_g3d); + return 0; +out: + return -EPERM; +} + +/** + * Enable GPU clocks + */ +static int kbase_platform_clock_on(struct kbase_device *kbdev) +{ + struct exynos_context *platform; + if (!kbdev) + return -ENODEV; + + platform = (struct exynos_context *) kbdev->platform_context; + if (!platform) + return -ENODEV; + + if(clk_g3d) + { + /* android_v4 support */ + (void) clk_enable(clk_g3d); + } + else + { + /* chrome support */ + (void) clk_enable(platform->sclk_g3d); + } + + return 0; +} + +/** + * Disable GPU clocks + */ +static int kbase_platform_clock_off(struct kbase_device *kbdev) +{ + struct exynos_context *platform; + if (!kbdev) + return -ENODEV; + + platform = (struct exynos_context *) kbdev->platform_context; + if (!platform) + return -ENODEV; + + if(clk_g3d) + { + /* android_v4 support */ + (void)clk_disable_unprepare(clk_g3d); + } + else + { + /* chrome support */ + (void)clk_disable_unprepare(platform->sclk_g3d); + } + return 0; +} + +/** + * Report GPU power status + */ +static inline int kbase_platform_is_power_on(void) +{ + return ((__raw_readl(EXYNOS5_G3D_STATUS) & 0x7) == 0x7) ? 1 : 0; +} + +/** + * Enable GPU power + */ +static int kbase_platform_power_on(void) +{ + int timeout; + + /* Turn on G3D */ + __raw_writel(0x7, EXYNOS5_G3D_CONFIGURATION); + + /* Wait for G3D power stability */ + timeout = 1000; + + while((__raw_readl(EXYNOS5_G3D_STATUS) & 0x7) != 0x7) { + if(timeout == 0) { + /* need to call panic */ + panic("failed to turn on g3d via g3d_configuration\n"); + return -ETIMEDOUT; + } + timeout--; + udelay(10); + } + + return 0; +} + +/** + * Disable GPU power + */ +static int kbase_platform_power_off(void) +{ + int timeout; + + /* Turn off G3D */ + __raw_writel(0x0, EXYNOS5_G3D_CONFIGURATION); + + /* Wait for G3D power stability */ + timeout = 1000; + + while(__raw_readl(EXYNOS5_G3D_STATUS) & 0x7) { + if(timeout == 0) { + /* need to call panic */ + panic( "failed to turn off g3d via g3d_configuration\n"); + return -ETIMEDOUT; + } + timeout--; + udelay(10); + } + + return 0; +} + +/** + * Power Management unit control. Enable/disable power and clocks to GPU + */ +int kbase_platform_cmu_pmu_control(struct kbase_device *kbdev, int control) +{ + unsigned long flags; + struct exynos_context *platform; + if (!kbdev) + { + return -ENODEV; + } + + platform = (struct exynos_context *) kbdev->platform_context; + if (!platform) + { + return -ENODEV; + } + + spin_lock_irqsave(&platform->cmu_pmu_lock, flags); + + /* off */ + if(control == 0) + { + if(platform->cmu_pmu_status == 0) + { + spin_unlock_irqrestore(&platform->cmu_pmu_lock, flags); + return 0; + } + + if(kbase_platform_power_off()) + panic("failed to turn off g3d power\n"); + if(kbase_platform_clock_off(kbdev)) + + panic("failed to turn off sclk_g3d\n"); + + platform->cmu_pmu_status = 0; +#if MALI_RTPM_DEBUG + printk( KERN_ERR "3D cmu_pmu_control - off\n" ); +#endif /* MALI_RTPM_DEBUG */ + } + else + { + /* on */ + if(platform->cmu_pmu_status == 1) + { + spin_unlock_irqrestore(&platform->cmu_pmu_lock, flags); + return 0; + } + + if(kbase_platform_clock_on(kbdev)) + panic("failed to turn on sclk_g3d\n"); + if(kbase_platform_power_on()) + panic("failed to turn on g3d power\n"); + + platform->cmu_pmu_status = 1; +#if MALI_RTPM_DEBUG + printk( KERN_ERR "3D cmu_pmu_control - on\n"); +#endif /* MALI_RTPM_DEBUG */ + } + + spin_unlock_irqrestore(&platform->cmu_pmu_lock, flags); + + return 0; +} + +#ifdef CONFIG_MALI_T6XX_DEBUG_SYS +/** The sysfs file @c clock, fbdev. + * + * This is used for obtaining information about the vithar + * operating clock & framebuffer address, + */ + +static ssize_t mali_sysfs_show_clock(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kbase_device *kbdev; + struct exynos_context *platform; + unsigned int clkrate; + + kbdev = dev_get_drvdata(dev); + + if (!kbdev) + return -ENODEV; + + platform = (struct exynos_context *) kbdev->platform_context; + if(!platform) + return -ENODEV; + + if(!platform->sclk_g3d) + return -ENODEV; + + clkrate = clk_get_rate(platform->sclk_g3d); + + return scnprintf(buf, PAGE_SIZE, "%u\n", clkrate); +} + +static ssize_t mali_sysfs_set_clock(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ +#ifdef CONFIG_MALI_T6XX_DVFS + struct kbase_device *kbdev = dev_get_drvdata(dev); + struct exynos_context *platform; + unsigned int tmp = 0; + unsigned long freq; + int level; + + if (!kbdev) { + pr_err("%s: no kbdev\n", __func__); + return -ENODEV; + } + + platform = (struct exynos_context *) kbdev->platform_context; + if (platform == NULL) { + pr_err("%s: no platform\n", __func__); + return -ENODEV; + } + if (!platform->sclk_g3d) { + pr_info("%s: clkout not 3d\n", __func__); + return -ENODEV; + } + + /* TODO(dianders) need to be more careful fiddling voltage+clock */ + freq = simple_strtoul(buf, NULL, 10); + if (!freq) + return -EINVAL; + + level = kbase_platform_dvfs_get_level(freq); + if (level < 0) { + pr_err("%s: invalid value\n", __func__); + return -ENOENT; + } + + kbase_platform_dvfs_set_level(kbdev, level); + + /* Waiting for clock is stable */ + do { + tmp = __raw_readl(EXYNOS5_CLKDIV_STAT_TOP0); + } while (tmp & 0x1000000); +#endif /* CONFIG_MALI_T6XX_DVFS */ + return count; +} +DEVICE_ATTR(clock, S_IRUGO|S_IWUSR, mali_sysfs_show_clock, + mali_sysfs_set_clock); + +static ssize_t mali_sysfs_available_frequencies(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int i; + ssize_t ret = 0; + + for (i = 0; i < MALI_DVFS_STEP; i++) { + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%u\n", + mali_dvfs_infotbl[i].clock); + } + + return ret; +} +DEVICE_ATTR(available_frequencies, S_IRUGO, mali_sysfs_available_frequencies, + NULL); + +static ssize_t mali_sysfs_show_fbdev(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kbase_device *kbdev; + ssize_t ret = 0; + int i; + + kbdev = dev_get_drvdata(dev); + + if (!kbdev) + return -ENODEV; + + for(i = 0 ; i < num_registered_fb ; i++) { + ret += snprintf(buf+ret, PAGE_SIZE-ret, "fb[%d] xres=%d, yres=%d, addr=0x%lx\n", i, registered_fb[i]->var.xres, registered_fb[i]->var.yres, registered_fb[i]->fix.smem_start); + } + + if (ret < PAGE_SIZE - 1) + ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n"); + else + { + buf[PAGE_SIZE-2] = '\n'; + buf[PAGE_SIZE-1] = '\0'; + ret = PAGE_SIZE-1; + } + + return ret; +} +DEVICE_ATTR(fbdev, S_IRUGO, mali_sysfs_show_fbdev, NULL); + +static ssize_t mali_sysfs_show_memory(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kbase_device *kbdev; + int ret; + + kbdev = dev_get_drvdata(dev); + + if (!kbdev) + return -ENODEV; + + return ret; +} +DEVICE_ATTR(memory, S_IRUGO, mali_sysfs_show_memory, NULL); + +typedef enum { + L1_I_tag_RAM = 0x00, + L1_I_data_RAM = 0x01, + L1_I_BTB_RAM = 0x02, + L1_I_GHB_RAM = 0x03, + L1_I_TLB_RAM = 0x04, + L1_I_indirect_predictor_RAM = 0x05, + L1_D_tag_RAM = 0x08, + L1_D_data_RAM = 0x09, + L1_D_load_TLB_array = 0x0A, + L1_D_store_TLB_array = 0x0B, + L2_tag_RAM = 0x10, + L2_data_RAM = 0x11, + L2_snoop_tag_RAM = 0x12, + L2_data_ECC_RAM = 0x13, + L2_dirty_RAM = 0x14, + L2_TLB_RAM = 0x18 +} RAMID_type; + +static inline void asm_ramindex_mrc(u32 *DL1Data0, u32 *DL1Data1, + u32 *DL1Data2, u32 *DL1Data3) +{ + u32 val; + + if(DL1Data0) + { + asm volatile("mrc p15, 0, %0, c15, c1, 0" : "=r" (val)); + *DL1Data0 = val; + } + if(DL1Data1) + { + asm volatile("mrc p15, 0, %0, c15, c1, 1" : "=r" (val)); + *DL1Data1 = val; + } + if(DL1Data2) + { + asm volatile("mrc p15, 0, %0, c15, c1, 2" : "=r" (val)); + *DL1Data2 = val; + } + if(DL1Data3) + { + asm volatile("mrc p15, 0, %0, c15, c1, 3" : "=r" (val)); + *DL1Data3 = val; + } +} + +static inline void asm_ramindex_mcr(u32 val) +{ + asm volatile("mcr p15, 0, %0, c15, c4, 0" : : "r" (val)); + asm volatile("dsb"); + asm volatile("isb"); +} + +static void get_tlb_array(u32 val, u32 *DL1Data0, u32 *DL1Data1, + u32 *DL1Data2, u32 *DL1Data3) +{ + asm_ramindex_mcr(val); + asm_ramindex_mrc(DL1Data0, DL1Data1, DL1Data2, DL1Data3); +} + +static RAMID_type ramindex = L1_D_load_TLB_array; +static ssize_t mali_sysfs_show_dtlb(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kbase_device *kbdev; + ssize_t ret = 0; + int entries, ways; + u32 DL1Data0 = 0, DL1Data1 = 0, DL1Data2 = 0, DL1Data3 = 0; + + kbdev = dev_get_drvdata(dev); + + if (!kbdev) + return -ENODEV; + + /* L1-I tag RAM */ + if(ramindex == L1_I_tag_RAM) + { + printk("Not implemented yet\n"); + } + /* L1-I data RAM */ + else if(ramindex == L1_I_data_RAM) + { + printk("Not implemented yet\n"); + } + /* L1-I BTB RAM */ + else if(ramindex == L1_I_BTB_RAM) + { + printk("Not implemented yet\n"); + } + /* L1-I GHB RAM */ + else if(ramindex == L1_I_GHB_RAM) + { + printk("Not implemented yet\n"); + } + /* L1-I TLB RAM */ + else if(ramindex == L1_I_TLB_RAM) + { + printk("L1-I TLB RAM\n"); + for(entries = 0 ; entries < 32 ; entries++) + { + get_tlb_array((((u8)ramindex) << 24) + entries, &DL1Data0, &DL1Data1, &DL1Data2, NULL); + printk("entries[%d], DL1Data0=%08x, DL1Data1=%08x DL1Data2=%08x\n", entries, DL1Data0, DL1Data1 & 0xffff, 0x0); + } + } + /* L1-I indirect predictor RAM */ + else if(ramindex == L1_I_indirect_predictor_RAM) + { + printk("Not implemented yet\n"); + } + /* L1-D tag RAM */ + else if(ramindex == L1_D_tag_RAM) + { + printk("Not implemented yet\n"); + } + /* L1-D data RAM */ + else if(ramindex == L1_D_data_RAM) + { + printk("Not implemented yet\n"); + } + /* L1-D load TLB array */ + else if(ramindex == L1_D_load_TLB_array) + { + printk("L1-D load TLB array\n"); + for(entries = 0 ; entries < 32 ; entries++) + { + get_tlb_array((((u8)ramindex) << 24) + entries, &DL1Data0, &DL1Data1, &DL1Data2, &DL1Data3); + printk("entries[%d], DL1Data0=%08x, DL1Data1=%08x, DL1Data2=%08x, DL1Data3=%08x\n", entries, DL1Data0, DL1Data1, DL1Data2, DL1Data3 & 0x3f); + } + } + /* L1-D store TLB array */ + else if(ramindex == L1_D_store_TLB_array) + { + printk("\nL1-D store TLB array\n"); + for(entries = 0 ; entries < 32 ; entries++) + { + get_tlb_array((((u8)ramindex) << 24) + entries, &DL1Data0, &DL1Data1, &DL1Data2, &DL1Data3); + printk("entries[%d], DL1Data0=%08x, DL1Data1=%08x, DL1Data2=%08x, DL1Data3=%08x\n", entries, DL1Data0, DL1Data1, DL1Data2, DL1Data3 & 0x3f); + } + } + /* L2 tag RAM */ + else if(ramindex == L2_tag_RAM) + { + printk("Not implemented yet\n"); + } + /* L2 data RAM */ + else if(ramindex == L2_data_RAM) + { + printk("Not implemented yet\n"); + } + /* L2 snoop tag RAM */ + else if(ramindex == L2_snoop_tag_RAM) + { + printk("Not implemented yet\n"); + } + /* L2 data ECC RAM */ + else if(ramindex == L2_data_ECC_RAM) + { + printk("Not implemented yet\n"); + } + /* L2 dirty RAM */ + else if(ramindex == L2_dirty_RAM) + { + printk("Not implemented yet\n"); + } + /* L2 TLB array */ + else if(ramindex == L2_TLB_RAM) + { + printk("\nL2 TLB array\n"); + for(ways = 0 ; ways < 4 ; ways++) + { + for(entries = 0 ; entries < 512 ; entries++) + { + get_tlb_array((ramindex << 24) + (ways << 18) + entries, &DL1Data0, &DL1Data1, &DL1Data2, &DL1Data3); + printk("ways[%d]:entries[%d], DL1Data0=%08x, DL1Data1=%08x, DL1Data2=%08x, DL1Data3=%08x\n", ways, entries, DL1Data0, DL1Data1, DL1Data2, DL1Data3); + } + } + } + + ret += snprintf(buf+ret, PAGE_SIZE-ret, "Succeeded...\n"); + + if (ret < PAGE_SIZE - 1) + ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n"); + else + { + buf[PAGE_SIZE-2] = '\n'; + buf[PAGE_SIZE-1] = '\0'; + ret = PAGE_SIZE-1; + } + return ret; +} + +static ssize_t mali_sysfs_set_dtlb(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct kbase_device *kbdev; + kbdev = dev_get_drvdata(dev); + + if (!kbdev) + return -ENODEV; + + if (sysfs_streq("L1_I_tag_RAM", buf)) { + ramindex = L1_I_tag_RAM; + } else if (sysfs_streq("L1_I_data_RAM", buf)) { + ramindex = L1_I_data_RAM; + } else if (sysfs_streq("L1_I_BTB_RAM", buf)) { + ramindex = L1_I_BTB_RAM; + } else if (sysfs_streq("L1_I_GHB_RAM", buf)) { + ramindex = L1_I_GHB_RAM; + } else if (sysfs_streq("L1_I_TLB_RAM", buf)) { + ramindex = L1_I_TLB_RAM; + } else if (sysfs_streq("L1_I_indirect_predictor_RAM", buf)) { + ramindex = L1_I_indirect_predictor_RAM; + } else if (sysfs_streq("L1_D_tag_RAM", buf)) { + ramindex = L1_D_tag_RAM; + } else if (sysfs_streq("L1_D_data_RAM", buf)) { + ramindex = L1_D_data_RAM; + } else if (sysfs_streq("L1_D_load_TLB_array", buf)) { + ramindex = L1_D_load_TLB_array; + } else if (sysfs_streq("L1_D_store_TLB_array", buf)) { + ramindex = L1_D_store_TLB_array; + } else if (sysfs_streq("L2_tag_RAM", buf)) { + ramindex = L2_tag_RAM; + } else if (sysfs_streq("L2_data_RAM", buf)) { + ramindex = L2_data_RAM; + } else if (sysfs_streq("L2_snoop_tag_RAM", buf)) { + ramindex = L2_snoop_tag_RAM; + } else if (sysfs_streq("L2_data_ECC_RAM", buf)) { + ramindex = L2_data_ECC_RAM; + } else if (sysfs_streq("L2_dirty_RAM", buf)) { + ramindex = L2_dirty_RAM; + } else if (sysfs_streq("L2_TLB_RAM", buf)) { + ramindex = L2_TLB_RAM; + } else { + printk("Invalid value....\n\n"); + printk("Available options are one of below\n"); + printk("L1_I_tag_RAM, L1_I_data_RAM, L1_I_BTB_RAM\n"); + printk("L1_I_GHB_RAM, L1_I_TLB_RAM, L1_I_indirect_predictor_RAM\n"); + printk("L1_D_tag_RAM, L1_D_data_RAM, L1_D_load_TLB_array, L1_D_store_TLB_array\n"); + printk("L2_tag_RAM, L2_data_RAM, L2_snoop_tag_RAM, L2_data_ECC_RAM\n"); + printk("L2_dirty_RAM, L2_TLB_RAM\n"); + } + + return count; +} +DEVICE_ATTR(dtlb, S_IRUGO|S_IWUSR, mali_sysfs_show_dtlb, mali_sysfs_set_dtlb); + +static ssize_t mali_sysfs_show_vol(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kbase_device *kbdev; + ssize_t ret = 0; + int vol; + + kbdev = dev_get_drvdata(dev); + + if (!kbdev) + return -ENODEV; + + kbase_platform_get_voltage(dev, &vol); + ret += snprintf(buf+ret, PAGE_SIZE-ret, "Current operating voltage for mali t6xx = %d", vol); + + if (ret < PAGE_SIZE - 1) + ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n"); + else + { + buf[PAGE_SIZE-2] = '\n'; + buf[PAGE_SIZE-1] = '\0'; + ret = PAGE_SIZE-1; + } + + return ret; +} +DEVICE_ATTR(vol, S_IRUGO|S_IWUSR, mali_sysfs_show_vol, NULL); + +static int get_clkout_cmu_top(int *val) +{ + *val = __raw_readl(/*EXYNOS5_CLKOUT_CMU_TOP*/EXYNOS_CLKREG(0x10A00)); + if((*val & 0x1f) == 0xB) /* CLKOUT is ACLK_400 in CLKOUT_CMU_TOP */ + return 1; + else + return 0; +} + +static void set_clkout_for_3d(void) +{ + int tmp; + + tmp = 0x0; + tmp |= 0x1000B; /* ACLK_400 selected */ + tmp |= 9 << 8; /* divided by (9 + 1) */ + __raw_writel(tmp, /*EXYNOS5_CLKOUT_CMU_TOP*/EXYNOS_CLKREG(0x10A00)); + +#ifdef PMU_XCLKOUT_SET + exynos5_pmu_xclkout_set(1, XCLKOUT_CMU_TOP); +#else /* PMU_XCLKOUT_SET */ + tmp = 0x0; + tmp |= 7 << 8; /* CLKOUT_CMU_TOP selected */ + __raw_writel(tmp, /*S5P_PMU_DEBUG*/S5P_PMUREG(0x0A00)); +#endif /* PMU_XCLKOUT_SET */ +} + +static ssize_t mali_sysfs_show_clkout(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kbase_device *kbdev; + ssize_t ret = 0; + int val; + + kbdev = dev_get_drvdata(dev); + + if (!kbdev) + return -ENODEV; + + if(get_clkout_cmu_top(&val)) + ret += snprintf(buf+ret, PAGE_SIZE-ret, "Current CLKOUT is g3d divided by 10, CLKOUT_CMU_TOP=0x%x", val); + else + ret += snprintf(buf+ret, PAGE_SIZE-ret, "Current CLKOUT is not g3d, CLKOUT_CMU_TOP=0x%x", val); + + if (ret < PAGE_SIZE - 1) + ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n"); + else + { + buf[PAGE_SIZE-2] = '\n'; + buf[PAGE_SIZE-1] = '\0'; + ret = PAGE_SIZE-1; + } + + return ret; +} + +static ssize_t mali_sysfs_set_clkout(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct kbase_device *kbdev = dev_get_drvdata(dev); + + if (!kbdev) + return -ENODEV; + + set_clkout_for_3d(); + pr_info("clkout set to 3d\n"); + return count; +} +DEVICE_ATTR(clkout, S_IRUGO|S_IWUSR, mali_sysfs_show_clkout, + mali_sysfs_set_clkout); + +#ifdef CONFIG_MALI_T6XX_DVFS +static ssize_t mali_sysfs_show_dvfs(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kbase_device *kbdev; + ssize_t ret = 0; + + kbdev = dev_get_drvdata(dev); + + if (!kbdev) + return -ENODEV; + + if (!kbase_pm_metrics_is_active(kbdev)) + ret += snprintf(buf+ret, PAGE_SIZE-ret, "off\n"); + else + ret += snprintf(buf+ret, PAGE_SIZE-ret, "on\n"); + + return ret; +} + +static ssize_t mali_sysfs_set_dvfs(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + mali_error ret; + struct kbase_device *kbdev; + struct exynos_context *platform; + kbdev = dev_get_drvdata(dev); + + if (!kbdev) + return -ENODEV; + + platform = kbdev->platform_context; + if (!platform) + return -ENODEV; + + if (sysfs_streq("off", buf)) { + if (kbase_pm_metrics_is_active(kbdev)) { + kbasep_pm_metrics_term(kbdev); + kbase_platform_dvfs_set_level(kbdev, + kbase_platform_dvfs_get_level(platform->t6xx_default_clock)); + pr_info("G3D DVFS is disabled\n"); + } + } else if (sysfs_streq("on", buf)) { + if (!kbase_pm_metrics_is_active(kbdev)) { + ret = kbasep_pm_metrics_init(kbdev); + if (ret != MALI_ERROR_NONE) + pr_warning("kbase_pm_metrics_init failed," + " error %u\n", ret); + else + pr_info("G3D DVFS is enabled\n"); + } + } else { + pr_info("%s: invalid, only [on, off] is accepted\n", buf); + return -EINVAL; + } + + return count; +} +DEVICE_ATTR(dvfs, S_IRUGO|S_IWUSR, mali_sysfs_show_dvfs, mali_sysfs_set_dvfs); +#endif /* CONFIG_MALI_T6XX_DVFS */ + +#ifdef MALI_DVFS_ASV_ENABLE +static ssize_t mali_sysfs_show_asv(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + struct kbase_device *kbdev; + ssize_t ret = 0; + int i; + kbdev = dev_get_drvdata(dev); + + if (!kbdev) + return -ENODEV; + if (!buf) + return -EINVAL; + + ret += scnprintf(buf, PAGE_SIZE, "asv group:%d exynos_lot_id:%d\n", + exynos_result_of_asv & 0xf, exynos_lot_id); + for (i = MALI_DVFS_STEP - 1; i >= 0; i--) { + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%u:%d\n", + mali_dvfs_infotbl[i].clock, + mali_dvfs_infotbl[i].voltage); + } + return ret; +} + +static ssize_t mali_sysfs_set_asv(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + if (sysfs_streq("off", buf)) + kbase_platform_asv_set(0); + else if (sysfs_streq("on", buf)) + kbase_platform_asv_set(1); + else { + printk(KERN_ERR "invalid val -only [on, off] is accepted\n"); + return -EINVAL; + } + + return count; +} +DEVICE_ATTR(asv, S_IRUGO|S_IWUSR, mali_sysfs_show_asv, mali_sysfs_set_asv); +#endif + +static int kbase_platform_create_sysfs_file(struct device *dev) +{ + if (device_create_file(dev, &dev_attr_clock)) + { + dev_err(dev, "Couldn't create sysfs file [clock]\n"); + goto out; + } + + if (device_create_file(dev, &dev_attr_available_frequencies)) { + dev_err(dev, "Couldn't create sysfs file [available_frequencies]\n"); + goto out; + } + + if (device_create_file(dev, &dev_attr_fbdev)) + { + dev_err(dev, "Couldn't create sysfs file [fbdev]\n"); + goto out; + } + + if (device_create_file(dev, &dev_attr_memory)) + { + dev_err(dev, "Couldn't create sysfs file [memory]\n"); + goto out; + } + + if (device_create_file(dev, &dev_attr_dtlb)) + { + dev_err(dev, "Couldn't create sysfs file [dtlb]\n"); + goto out; + } + + if (device_create_file(dev, &dev_attr_vol)) + { + dev_err(dev, "Couldn't create sysfs file [vol]\n"); + goto out; + } + + if (device_create_file(dev, &dev_attr_clkout)) + { + dev_err(dev, "Couldn't create sysfs file [clkout]\n"); + goto out; + } +#ifdef CONFIG_MALI_T6XX_DVFS + if (device_create_file(dev, &dev_attr_dvfs)) + { + dev_err(dev, "Couldn't create sysfs file [dvfs]\n"); + goto out; + } +#ifdef MALI_DVFS_ASV_ENABLE + if (device_create_file(dev, &dev_attr_asv)) { + dev_err(dev, "Couldn't create sysfs file [asv]\n"); + goto out; + } +#endif +#endif /* CONFIG_MALI_T6XX_DVFS */ +#ifdef CONFIG_MALI_HWC_TRACE + if (!mali_setup_system_tracing(dev)) + goto out; +#endif /* CONFIG_MALI_HWC_TRACE */ + + return 0; +out: + return -ENOENT; +} + +void kbase_platform_remove_sysfs_file(struct device *dev) +{ + device_remove_file(dev, &dev_attr_clock); + device_remove_file(dev, &dev_attr_available_frequencies); + device_remove_file(dev, &dev_attr_fbdev); + device_remove_file(dev, &dev_attr_dtlb); + device_remove_file(dev, &dev_attr_vol); + device_remove_file(dev, &dev_attr_clkout); +#ifdef CONFIG_MALI_T6XX_DVFS + device_remove_file(dev, &dev_attr_dvfs); +#ifdef MALI_DVFS_ASV_ENABLE + device_remove_file(dev, &dev_attr_asv); +#endif +#endif /* CONFIG_MALI_T6XX_DVFS */ +#ifdef CONFIG_MALI_HWC_TRACE + mali_cleanup_system_tracing(dev); +#endif /* CONFIG_MALI_HWC_TRACE */ +} +#endif /* CONFIG_MALI_T6XX_DEBUG_SYS */ + +mali_error kbase_platform_init(kbase_device *kbdev) +{ + struct exynos_context *platform; + + platform = kmalloc(sizeof(struct exynos_context), GFP_KERNEL); + + if(NULL == platform) + { + return MALI_ERROR_OUT_OF_MEMORY; + } + + kbdev->platform_context = (void *) platform; + + platform->t6xx_default_clock = 533000000; + + platform->cmu_pmu_status = 0; + spin_lock_init(&platform->cmu_pmu_lock); + + if(kbase_platform_power_clock_init(kbdev)) + { + goto clock_init_fail; + } + +#ifdef CONFIG_REGULATOR + if(kbase_platform_regulator_init()) + { + goto regulator_init_fail; + } +#endif /* CONFIG_REGULATOR */ + +#ifdef CONFIG_MALI_T6XX_DVFS + if (!kbase_platform_dvfs_init(kbdev)) + goto dvfs_init_fail; +#endif /* CONFIG_MALI_T6XX_DVFS */ + + /* Enable power */ + kbase_platform_cmu_pmu_control(kbdev, 1); + return MALI_ERROR_NONE; + +#ifdef CONFIG_MALI_T6XX_DVFS +dvfs_init_fail: +#endif /* CONFIG_MALI_T6XX_DVFS */ +#ifdef CONFIG_REGULATOR + kbase_platform_regulator_disable(); +regulator_init_fail: +#endif /* CONFIG_REGULATOR */ +clock_init_fail: + kfree(platform); + kbdev->platform_context = NULL; + return MALI_ERROR_FUNCTION_FAILED; +} + +void kbase_platform_term(kbase_device *kbdev) +{ + struct exynos_context *platform; + + platform = (struct exynos_context *) kbdev->platform_context; + +#ifdef CONFIG_MALI_T6XX_DVFS + kbase_platform_dvfs_term(); +#endif /* CONFIG_MALI_T6XX_DVFS */ + + /* Disable power */ + kbase_platform_cmu_pmu_control(kbdev, 0); +#ifdef CONFIG_REGULATOR + kbase_platform_regulator_disable(); +#endif /* CONFIG_REGULATOR */ + kfree(kbdev->platform_context); + kbdev->platform_context = 0; + return; +} + +#ifdef CONFIG_REGULATOR +static struct regulator *g3d_regulator=NULL; +#ifdef CONFIG_T6XX_HWVER_R0P0 +static int mali_gpu_vol = 1250000; /* 1.25V @ 533 MHz */ +#else +static int mali_gpu_vol = 1050000; /* 1.05V @ 266 MHz */ +#endif /* CONFIG_T6XX_HWVER_R0P0 */ +#endif /* CONFIG_REGULATOR */ + +#ifdef CONFIG_MALI_T6XX_DVFS +/* + * Weighted moving average support for signed integer data + * with 7-bits of precision (not currently used; all data + * are integers). + */ +#define DVFS_AVG_DUMMY_MARKER (~0) +#define DVFS_AVG_LPF_LEN 4 /* NB: best to be pow2 */ +#define DVFS_AVG_EP_MULTIPLIER (1<<7) /* 7 fractional bits */ + +#define DVFS_AVG_RESET(x) ((x) = DVFS_AVG_DUMMY_MARKER) +#define _DVFS_AVG_IN(x) ((x) * DVFS_AVG_EP_MULTIPLIER) +#define _DVFS_LPF_UTIL(x, y, len) \ + ((x != DVFS_AVG_DUMMY_MARKER) ? \ + (((x) * ((len) - 1) + (y)) / (len)) : (y)) +#define DVFS_AVG_LPF(x, y) do { \ + x = _DVFS_LPF_UTIL((x), _DVFS_AVG_IN((y)), DVFS_AVG_LPF_LEN); \ +} while (0) +#define DVFS_TO_AVG(x) DIV_ROUND_CLOSEST(x, DVFS_AVG_EP_MULTIPLIER) + +#ifdef MALI_DVFS_ASV_ENABLE +enum asv_update_val { + DVFS_NOT_UPDATE_ASV_TBL = 0, + DVFS_UPDATE_ASV_TBL = 1, + DVFS_UPDATE_ASV_DEFAULT_TBL = 2, +}; +#endif /* MALI_DVFS_ASV_ENABLE */ + +struct mali_dvfs_status { + kbase_device *kbdev; + int step; + int utilisation; + uint nsamples; + u32 avg_utilisation; +#ifdef MALI_DVFS_ASV_ENABLE + enum asv_update_val asv_need_update; + int asv_group; +#endif +}; + +static struct workqueue_struct *mali_dvfs_wq = 0; +int mali_dvfs_control=0; +spinlock_t mali_dvfs_spinlock; + +#ifdef MALI_DVFS_ASV_ENABLE +static int mali_dvfs_update_asv(int group) +{ + int i; + + /* TODO(Shariq): Replace exynos_lot_id with api call once ASV code is rebased */ + if (exynos_lot_id && group == 0) { + /* wrong group: Use default table to keep the system running smoothly */ + for (i = 0; i < MALI_DVFS_STEP; i++) + mali_dvfs_infotbl[i].voltage = mali_dvfs_vol_default[i]; + pr_err("exynos_lot_id has group 0. Using default gpu asv table\n"); + return 1; + } + + if (group == -1) { + for (i = 0; i < MALI_DVFS_STEP; i++) + mali_dvfs_infotbl[i].voltage = mali_dvfs_vol_default[i]; + pr_err("mali_dvfs_update_asv use default table\n"); + return 1; + } + if (group > MALI_DVFS_ASV_GROUP_NUM) { + /* unknown group: Use default table to keep the system running smoothly */ + for (i = 0; i < MALI_DVFS_STEP; i++) + mali_dvfs_infotbl[i].voltage = mali_dvfs_vol_default[i]; + printk(KERN_ERR "invalid asv group (%d)\n", group); + return 1; + } + for (i = 0; i < MALI_DVFS_STEP; i++) { + if (exynos_lot_id) + mali_dvfs_infotbl[i].voltage = + mali_dvfs_asv_vol_tbl_special[group-1][i]; + else + mali_dvfs_infotbl[i].voltage = + mali_dvfs_asv_vol_tbl[group][i]; + } + + return 0; +} +#endif /* MALI_DVFS_ASV_ENABLE */ + +static void mali_dvfs_event_proc(struct work_struct *w) +{ + struct mali_dvfs_status dvfs_status; + const struct mali_dvfs_info *info; + int avg_utilisation; + unsigned long irqflags; + + spin_lock_irqsave(&mali_dvfs_spinlock, irqflags); + dvfs_status = mali_dvfs_status_current; + + BUG_ON(dvfs_status.step >= MALI_DVFS_STEP); +#ifdef MALI_DVFS_ASV_ENABLE + if (soc_is_exynos5250()) { + if (dvfs_status.asv_need_update == + DVFS_UPDATE_ASV_DEFAULT_TBL) { + mali_dvfs_update_asv(-1); + dvfs_status.asv_need_update = DVFS_NOT_UPDATE_ASV_TBL; + } else if (dvfs_status.asv_need_update == DVFS_UPDATE_ASV_TBL) { + if (!mali_dvfs_update_asv(exynos_result_of_asv & 0xf)) + dvfs_status.asv_group = + (exynos_result_of_asv & 0xf); + dvfs_status.asv_need_update = DVFS_NOT_UPDATE_ASV_TBL; + } + } else if (soc_is_exynos5420()) { +#ifdef CONFIG_ARM_EXYNOS5420_ASV + int i; + unsigned int asv_volt; + + for (i = 0; i < MALI_DVFS_STEP; i++) { + asv_volt = get_match_volt(ID_G3D, + mali_dvfs_infotbl_exynos5420[i].clock + / 1000); + if (asv_volt) + mali_dvfs_infotbl[i].voltage = asv_volt; + } +#endif + } +#endif + spin_unlock_irqrestore(&mali_dvfs_spinlock, irqflags); + + info = &mali_dvfs_infotbl[dvfs_status.step]; + + BUG_ON(dvfs_status.utilisation > 100); + dvfs_status.nsamples++; + DVFS_AVG_LPF(dvfs_status.avg_utilisation, dvfs_status.utilisation); + BUG_ON(dvfs_status.nsamples <= 0); + avg_utilisation = DVFS_TO_AVG(dvfs_status.avg_utilisation); +#if MALI_DVFS_DEBUG + pr_debug("%s: step %d utilisation %d avg %d max %d min %d " + "nsamples %u up_cnt %d down_cnt %d\n", __func__, + dvfs_status.step, dvfs_status.utilisation, + avg_utilisation, info->max_threshold, info->min_threshold, + dvfs_status.nsamples, allow_up_cnt, allow_down_cnt); +#endif + trace_mali_dvfs_event(dvfs_status.utilisation, avg_utilisation); + + if (avg_utilisation > info->max_threshold && + dvfs_status.nsamples >= info->up_cnt_threshold) { + dvfs_status.step++; + /* + * NB: max clock should have max_threshold of 100 + * so this should never trip. + */ + BUG_ON(dvfs_status.step >= MALI_DVFS_STEP); + DVFS_AVG_RESET(dvfs_status.avg_utilisation); + dvfs_status.nsamples = 0; + } else if (dvfs_status.step > 0 && + avg_utilisation < info->min_threshold && + dvfs_status.nsamples >= info->down_cnt_threshold) { + BUG_ON(dvfs_status.step <= 0); + dvfs_status.step--; + DVFS_AVG_RESET(dvfs_status.avg_utilisation); + dvfs_status.nsamples = 0; + } + + if (kbase_pm_metrics_is_active(dvfs_status.kbdev)) + kbase_platform_dvfs_set_level(dvfs_status.kbdev, + dvfs_status.step); + + spin_lock_irqsave(&mali_dvfs_spinlock, irqflags); + mali_dvfs_status_current = dvfs_status; + spin_unlock_irqrestore(&mali_dvfs_spinlock, irqflags); + +} + +static DECLARE_WORK(mali_dvfs_work, mali_dvfs_event_proc); + +/** + * Exynos5 alternative dvfs_callback imlpementation. + * instead of: + * action = kbase_pm_get_dvfs_action(kbdev); + * use this: + * kbase_platform_dvfs_event(kbdev); + */ + +int kbase_platform_dvfs_get_control_status(void) +{ + return mali_dvfs_control; +} + +int kbase_platform_dvfs_init(kbase_device *kbdev) +{ + unsigned long irqflags; + + /*default status + add here with the right function to get initilization value. + */ + mali_dvfs_wq = create_singlethread_workqueue("mali_dvfs"); + if (!mali_dvfs_wq) + return MALI_FALSE; + + spin_lock_init(&mali_dvfs_spinlock); + + /*add a error handling here*/ + spin_lock_irqsave(&mali_dvfs_spinlock, irqflags); + mali_dvfs_status_current.kbdev = kbdev; + mali_dvfs_status_current.step = MALI_DVFS_STEP-1; + mali_dvfs_status_current.utilisation = 100; + DVFS_AVG_RESET(mali_dvfs_status_current.avg_utilisation); +#ifdef MALI_DVFS_ASV_ENABLE + mali_dvfs_status_current.asv_need_update = DVFS_UPDATE_ASV_TBL; + mali_dvfs_status_current.asv_group = -1; +#endif + mali_dvfs_control = 1; + + if (soc_is_exynos5250()) { + mali_dvfs_infotbl = mali_dvfs_infotbl_exynos5250; +#ifdef MALI_DVFS_ASV_ENABLE + mali_dvfs_vol_default = mali_dvfs_vol_default_exynos5250; + mali_dvfs_asv_vol_tbl_special = + mali_dvfs_asv_vol_tbl_special_exynos5250; + mali_dvfs_asv_vol_tbl = mali_dvfs_asv_vol_tbl_exynos5250; +#endif + } else if (soc_is_exynos5420()) + mali_dvfs_infotbl = mali_dvfs_infotbl_exynos5420; + + spin_unlock_irqrestore(&mali_dvfs_spinlock, irqflags); + + return MALI_TRUE; +} + +void kbase_platform_dvfs_term(void) +{ + if (mali_dvfs_wq) + destroy_workqueue(mali_dvfs_wq); + + mali_dvfs_wq = NULL; +} +#endif /* CONFIG_MALI_T6XX_DVFS */ + + +int kbase_platform_dvfs_event(struct kbase_device *kbdev, u32 utilisation) +{ +#ifdef CONFIG_MALI_T6XX_DVFS + unsigned long irqflags; + + spin_lock_irqsave(&mali_dvfs_spinlock, irqflags); + mali_dvfs_status_current.utilisation = utilisation; + spin_unlock_irqrestore(&mali_dvfs_spinlock, irqflags); + queue_work_on(0, mali_dvfs_wq, &mali_dvfs_work); + + /*add error handle here*/ + return MALI_TRUE; +#else + return MALI_FALSE; +#endif +} + +int kbase_platform_regulator_init(void) +{ +#ifdef CONFIG_REGULATOR + g3d_regulator = regulator_get(NULL, "vdd_g3d"); + if(IS_ERR(g3d_regulator)) + { + printk("[kbase_platform_regulator_init] failed to get mali t6xx regulator\n"); + return -1; + } + + if(regulator_enable(g3d_regulator) != 0) + { + printk("[kbase_platform_regulator_init] failed to enable mali t6xx regulator\n"); + return -1; + } + + if(regulator_set_voltage(g3d_regulator, mali_gpu_vol, mali_gpu_vol) != 0) + { + kbase_platform_regulator_disable(); + printk("[kbase_platform_regulator_init] failed to set mali t6xx operating voltage [%d]\n", mali_gpu_vol); + return -1; + } +#endif /* CONFIG_REGULATOR */ + + return 0; +} + +int kbase_platform_regulator_disable(void) +{ +#ifdef CONFIG_REGULATOR + if(!g3d_regulator) + { + printk("[kbase_platform_regulator_disable] g3d_regulator is not initialized\n"); + return -1; + } + + if(regulator_disable(g3d_regulator) != 0) + { + printk("[kbase_platform_regulator_disable] failed to disable g3d regulator\n"); + return -1; + } +#endif /* CONFIG_REGULATOR */ + return 0; +} + +int kbase_platform_regulator_enable(void) +{ +#ifdef CONFIG_REGULATOR + if(!g3d_regulator) + { + printk("[kbase_platform_regulator_enable] g3d_regulator is not initialized\n"); + return -1; + } + + if(regulator_enable(g3d_regulator) != 0) + { + printk("[kbase_platform_regulator_enable] failed to enable g3d regulator\n"); + return -1; + } +#endif /* CONFIG_REGULATOR */ + return 0; +} + +int kbase_platform_get_default_voltage(struct device *dev, int *vol) +{ +#ifdef CONFIG_REGULATOR + *vol = mali_gpu_vol; +#else /* CONFIG_REGULATOR */ + *vol = 0; +#endif /* CONFIG_REGULATOR */ + return 0; +} + +#ifdef CONFIG_MALI_T6XX_DEBUG_SYS +int kbase_platform_get_voltage(struct device *dev, int *vol) +{ +#ifdef CONFIG_REGULATOR + if(!g3d_regulator) + { + printk("[kbase_platform_get_voltage] g3d_regulator is not initialized\n"); + return -1; + } + + *vol = regulator_get_voltage(g3d_regulator); +#else /* CONFIG_REGULATOR */ + *vol = 0; +#endif /* CONFIG_REGULATOR */ + return 0; +} +#endif /* CONFIG_MALI_T6XX_DEBUG_SYS */ + +#ifdef CONFIG_MALI_T6XX_DVFS +static int kbase_platform_set_voltage(struct device *dev, int vol) +{ +#ifdef CONFIG_REGULATOR + if(!g3d_regulator) + { + printk("[kbase_platform_set_voltage] g3d_regulator is not initialized\n"); + return -1; + } + + if(regulator_set_voltage(g3d_regulator, vol, vol) != 0) + { + printk("[kbase_platform_set_voltage] failed to set voltage\n"); + return -1; + } +#endif /* CONFIG_REGULATOR */ + return 0; +} + +static void kbase_platform_dvfs_set_clock(kbase_device *kbdev, int freq) +{ + static struct clk * mout_gpll = NULL; + static struct clk * fin_gpll = NULL; + static struct clk * fout_gpll = NULL; + static int _freq = -1; + static unsigned long gpll_rate_prev = 0; + unsigned long gpll_rate = 0, aclk_400_rate = 0; + unsigned long tmp = 0; + struct exynos_context *platform; + unsigned int i = MALI_DVFS_STEP; + + if (!kbdev) + panic("no kbdev"); + + platform = (struct exynos_context *) kbdev->platform_context; + if (NULL == platform) + panic("no platform"); + + if (platform->sclk_g3d == 0) + return; + + if (mout_gpll == NULL) { + if (soc_is_exynos5250()) { + mout_gpll = clk_get(kbdev->osdev.dev, "mout_gpll"); + fin_gpll = clk_get(kbdev->osdev.dev, "ext_xtal"); + fout_gpll = clk_get(kbdev->osdev.dev, "fout_gpll"); + } else if (soc_is_exynos5420()) { + mout_gpll = clk_get(kbdev->osdev.dev, "mout_vpll"); + fin_gpll = clk_get(kbdev->osdev.dev, "ext_xtal"); + fout_gpll = clk_get(kbdev->osdev.dev, "fout_vpll"); + } + if (IS_ERR(mout_gpll) || IS_ERR(fin_gpll) || IS_ERR(fout_gpll)) + panic("clk_get ERROR"); + } + + if (freq == _freq) + return; + + trace_mali_dvfs_set_clock(freq); + + for (i = 0; i < MALI_DVFS_STEP; i++) + if (freq == mali_dvfs_infotbl[i].clock) { + gpll_rate = freq; + aclk_400_rate = freq; + break; + } + if (i == MALI_DVFS_STEP) + return; + + /* if changed the GPLL rate, set rate for GPLL and wait for lock time */ + if( gpll_rate != gpll_rate_prev) { + /*for stable clock input.*/ + if (soc_is_exynos5250()) + clk_set_rate(platform->sclk_g3d, 100000000); + else if (soc_is_exynos5420()) + clk_set_rate(platform->sclk_g3d, 100000000); + clk_set_parent(mout_gpll, fin_gpll); + + /*change gpll*/ + clk_set_rate( fout_gpll, gpll_rate ); + + /*restore parent*/ + clk_set_parent(mout_gpll, fout_gpll); + gpll_rate_prev = gpll_rate; + } + + _freq = freq; + clk_set_rate(platform->sclk_g3d, aclk_400_rate); + + /* Waiting for clock is stable */ + do { + tmp = __raw_readl(/*EXYNOS5_CLKDIV_STAT_TOP0*/EXYNOS_CLKREG(0x10610)); + } while (tmp & 0x1000000); +#if MALI_DVFS_DEBUG + printk(KERN_DEBUG "dvfs_set_clock GPLL : %lu, ACLK_400 : %luMhz\n", + gpll_rate, aclk_400_rate); +#endif /* MALI_DVFS_DEBUG */ + return; +} + +static void kbase_platform_dvfs_set_vol(unsigned int vol) +{ + static int _vol = -1; + + if (_vol == vol) + return; + trace_mali_dvfs_set_voltage(vol); + + kbase_platform_set_voltage(NULL, vol); + + _vol = vol; +#if MALI_DVFS_DEBUG + printk(KERN_DEBUG "dvfs_set_vol %dmV\n", vol); +#endif + return; +} + +static int kbase_platform_dvfs_get_level(int freq) +{ + int i; + for (i = 0; i < MALI_DVFS_STEP; i++) { + if (mali_dvfs_infotbl[i].clock == freq) + return i; + } + return -ENOENT; +} + +static void kbase_platform_dvfs_set_level(kbase_device *kbdev, int level) +{ + static int level_prev = -1; + + if (level == level_prev) + return; + if (WARN_ON((level >= MALI_DVFS_STEP) || (level < 0))) + panic("invalid level"); + + if (level > level_prev) { + kbase_platform_dvfs_set_vol(mali_dvfs_infotbl[level].voltage); + kbase_platform_dvfs_set_clock(kbdev, + mali_dvfs_infotbl[level].clock); + } else{ + kbase_platform_dvfs_set_clock(kbdev, + mali_dvfs_infotbl[level].clock); + kbase_platform_dvfs_set_vol(mali_dvfs_infotbl[level].voltage); + } + level_prev = level; +} +#endif /* CONFIG_MALI_T6XX_DVFS */ + +#ifdef MALI_DVFS_ASV_ENABLE +static int kbase_platform_asv_set(int enable) +{ + unsigned long irqflags; + + spin_lock_irqsave(&mali_dvfs_spinlock, irqflags); + if (enable) { + mali_dvfs_status_current.asv_need_update = DVFS_UPDATE_ASV_TBL; + mali_dvfs_status_current.asv_group = -1; + } else{ + mali_dvfs_status_current.asv_need_update = DVFS_UPDATE_ASV_DEFAULT_TBL; + } + spin_unlock_irqrestore(&mali_dvfs_spinlock, irqflags); + return 0; +} +#endif /* MALI_DVFS_ASV_ENABLE */ + +#if defined (CONFIG_MALI_HWC_TRACE) && defined (CONFIG_MALI_T6XX_DEBUG_SYS) +/* + * Mali hardware performance counter trace support. Each counter + * has a corresponding trace event. To use, enable events and write + * 1 to the hwc_enable sysfs file to start polling for counter data + * at vblank. An event is dispatched each time a counter's value + * changes. Note system event tracing must be enabled to get the + * events; otherwise the polling will not generate events. When done + * turn off polling. Note also that the GPU_ACTIVE counter causes + * the GPU to never be idle; this causes the governor to push the + * clock to max (since it sees 100% utilization). + * + * This code is derived from ARM's gator driver. + */ +#include +#include + +/* + * Mali hw counters by block. Note that each hw counter enable bit + * covers 4 counters. There are 64 counters / block for 256 total + * counters. + */ +#define MALI_HWC_TOTAL (4*64) /* total # hw counters */ + +#define hwc_off(x) ((x) & 0x3f) /* offset in block */ +#define hwc_bit(x) (hwc_off(x) >> 2) /* block bm enable bit */ + +#define BLOCK_OFF(b) ((b) << 6) + +/* Job Manager (Block 0) */ +#define BLOCK_JM_OFF BLOCK_OFF(0) +#define MALI_HW_MESSAGES_SENT (BLOCK_JM_OFF + 4) +#define MALI_HW_MESSAGES_RECEIVED (BLOCK_JM_OFF + 5) +/* NB: if GPU_ACTIVE is enabled the GPU will stay active when idle */ +#define MALI_HW_GPU_ACTIVE (BLOCK_JM_OFF + 6) +#define MALI_HW_IRQ_ACTIVE (BLOCK_JM_OFF + 7) + +#define MALI_HW_JS0_JOBS (BLOCK_JM_OFF + 8*0 + 8) +#define MALI_HW_JS0_TASKS (BLOCK_JM_OFF + 8*0 + 9) +#define MALI_HW_JS0_ACTIVE (BLOCK_JM_OFF + 8*0 + 10) +#define MALI_HW_JS0_WAIT_READ (BLOCK_JM_OFF + 8*0 + 11) +#define MALI_HW_JS0_WAIT_ISSUE (BLOCK_JM_OFF + 8*0 + 12) +#define MALI_HW_JS0_WAIT_DEPEND (BLOCK_JM_OFF + 8*0 + 13) +#define MALI_HW_JS0_WAIT_FINISH (BLOCK_JM_OFF + 8*0 + 14) + +#define MALI_HW_JS1_JOBS (BLOCK_JM_OFF + 8*1 + 8) +#define MALI_HW_JS1_TASKS (BLOCK_JM_OFF + 8*1 + 9) +#define MALI_HW_JS1_ACTIVE (BLOCK_JM_OFF + 8*1 + 10) +#define MALI_HW_JS1_WAIT_READ (BLOCK_JM_OFF + 8*1 + 11) +#define MALI_HW_JS1_WAIT_ISSUE (BLOCK_JM_OFF + 8*1 + 12) +#define MALI_HW_JS1_WAIT_DEPEND (BLOCK_JM_OFF + 8*1 + 13) +#define MALI_HW_JS1_WAIT_FINISH (BLOCK_JM_OFF + 8*1 + 14) + +#define MALI_HW_JS2_JOBS (BLOCK_JM_OFF + 8*2 + 8) +#define MALI_HW_JS2_TASKS (BLOCK_JM_OFF + 8*2 + 9) +#define MALI_HW_JS2_ACTIVE (BLOCK_JM_OFF + 8*2 + 10) +#define MALI_HW_JS2_WAIT_READ (BLOCK_JM_OFF + 8*2 + 11) +#define MALI_HW_JS2_WAIT_ISSUE (BLOCK_JM_OFF + 8*2 + 12) +#define MALI_HW_JS2_WAIT_DEPEND (BLOCK_JM_OFF + 8*2 + 13) +#define MALI_HW_JS2_WAIT_FINISH (BLOCK_JM_OFF + 8*2 + 14) + +#define MALI_HW_JS3_JOBS (BLOCK_JM_OFF + 8*3 + 8) +#define MALI_HW_JS3_TASKS (BLOCK_JM_OFF + 8*3 + 9) +#define MALI_HW_JS3_ACTIVE (BLOCK_JM_OFF + 8*3 + 10) +#define MALI_HW_JS3_WAIT_READ (BLOCK_JM_OFF + 8*3 + 11) +#define MALI_HW_JS3_WAIT_ISSUE (BLOCK_JM_OFF + 8*3 + 12) +#define MALI_HW_JS3_WAIT_DEPEND (BLOCK_JM_OFF + 8*3 + 13) +#define MALI_HW_JS3_WAIT_FINISH (BLOCK_JM_OFF + 8*3 + 14) + +#define MALI_HW_JS4_JOBS (BLOCK_JM_OFF + 8*4 + 8) +#define MALI_HW_JS4_TASKS (BLOCK_JM_OFF + 8*4 + 9) +#define MALI_HW_JS4_ACTIVE (BLOCK_JM_OFF + 8*4 + 10) +#define MALI_HW_JS4_WAIT_READ (BLOCK_JM_OFF + 8*4 + 11) +#define MALI_HW_JS4_WAIT_ISSUE (BLOCK_JM_OFF + 8*4 + 12) +#define MALI_HW_JS4_WAIT_DEPEND (BLOCK_JM_OFF + 8*4 + 13) +#define MALI_HW_JS4_WAIT_FINISH (BLOCK_JM_OFF + 8*4 + 14) + +#define MALI_HW_JS5_JOBS (BLOCK_JM_OFF + 8*5 + 8) +#define MALI_HW_JS5_TASKS (BLOCK_JM_OFF + 8*5 + 9) +#define MALI_HW_JS5_ACTIVE (BLOCK_JM_OFF + 8*5 + 10) +#define MALI_HW_JS5_WAIT_READ (BLOCK_JM_OFF + 8*5 + 11) +#define MALI_HW_JS5_WAIT_ISSUE (BLOCK_JM_OFF + 8*5 + 12) +#define MALI_HW_JS5_WAIT_DEPEND (BLOCK_JM_OFF + 8*5 + 13) +#define MALI_HW_JS5_WAIT_FINISH (BLOCK_JM_OFF + 8*5 + 14) + +#define MALI_HW_JS6_JOBS (BLOCK_JM_OFF + 8*6 + 8) +#define MALI_HW_JS6_TASKS (BLOCK_JM_OFF + 8*6 + 9) +#define MALI_HW_JS6_ACTIVE (BLOCK_JM_OFF + 8*6 + 10) +#define MALI_HW_JS6_WAIT_READ (BLOCK_JM_OFF + 8*6 + 11) +#define MALI_HW_JS6_WAIT_ISSUE (BLOCK_JM_OFF + 8*6 + 12) +#define MALI_HW_JS6_WAIT_DEPEND (BLOCK_JM_OFF + 8*6 + 13) +#define MALI_HW_JS6_WAIT_FINISH (BLOCK_JM_OFF + 8*6 + 14) + +#define MALI_HW_JM_FIRST MALI_HW_GPU_ACTIVE +#define MALI_HW_JM_LAST MALI_HW_JS6_WAIT_FINISH + +/* Tiler (Block 1) */ +#define BLOCK_TILER_OFF BLOCK_OFF(1) +#define MALI_HW_JOBS_PROCESSED (BLOCK_TILER_OFF + 3) +#define MALI_HW_TRIANGLES (BLOCK_TILER_OFF + 4) +#define MALI_HW_QUADS (BLOCK_TILER_OFF + 5) +#define MALI_HW_POLYGONS (BLOCK_TILER_OFF + 6) +#define MALI_HW_POINTS (BLOCK_TILER_OFF + 7) +#define MALI_HW_LINES (BLOCK_TILER_OFF + 8) +#define MALI_HW_VCACHE_HIT (BLOCK_TILER_OFF + 9) +#define MALI_HW_VCACHE_MISS (BLOCK_TILER_OFF + 10) +#define MALI_HW_FRONT_FACING (BLOCK_TILER_OFF + 11) +#define MALI_HW_BACK_FACING (BLOCK_TILER_OFF + 12) +#define MALI_HW_PRIM_VISIBLE (BLOCK_TILER_OFF + 13) +#define MALI_HW_PRIM_CULLED (BLOCK_TILER_OFF + 14) +#define MALI_HW_PRIM_CLIPPED (BLOCK_TILER_OFF + 15) + +#define MALI_HW_COMPRESS_IN (BLOCK_TILER_OFF + 32) +#define MALI_HW_COMPRESS_OUT (BLOCK_TILER_OFF + 33) +#define MALI_HW_COMPRESS_FLUSH (BLOCK_TILER_OFF + 34) +#define MALI_HW_TIMESTAMPS (BLOCK_TILER_OFF + 35) +#define MALI_HW_PCACHE_HIT (BLOCK_TILER_OFF + 36) +#define MALI_HW_PCACHE_MISS (BLOCK_TILER_OFF + 37) +#define MALI_HW_PCACHE_LINE (BLOCK_TILER_OFF + 38) +#define MALI_HW_PCACHE_STALL (BLOCK_TILER_OFF + 39) +#define MALI_HW_WRBUF_HIT (BLOCK_TILER_OFF + 40) +#define MALI_HW_WRBUF_MISS (BLOCK_TILER_OFF + 41) +#define MALI_HW_WRBUF_LINE (BLOCK_TILER_OFF + 42) +#define MALI_HW_WRBUF_PARTIAL (BLOCK_TILER_OFF + 43) +#define MALI_HW_WRBUF_STALL (BLOCK_TILER_OFF + 44) +#define MALI_HW_ACTIVE (BLOCK_TILER_OFF + 45) +#define MALI_HW_LOADING_DESC (BLOCK_TILER_OFF + 46) +#define MALI_HW_INDEX_WAIT (BLOCK_TILER_OFF + 47) +#define MALI_HW_INDEX_RANGE_WAIT (BLOCK_TILER_OFF + 48) +#define MALI_HW_VERTEX_WAIT (BLOCK_TILER_OFF + 49) +#define MALI_HW_PCACHE_WAIT (BLOCK_TILER_OFF + 50) +#define MALI_HW_WRBUF_WAIT (BLOCK_TILER_OFF + 51) +#define MALI_HW_BUS_READ (BLOCK_TILER_OFF + 52) +#define MALI_HW_BUS_WRITE (BLOCK_TILER_OFF + 53) + +#define MALI_HW_TILER_UTLB_STALL (BLOCK_TILER_OFF + 59) +#define MALI_HW_TILER_UTLB_REPLAY_MISS (BLOCK_TILER_OFF + 60) +#define MALI_HW_TILER_UTLB_REPLAY_FULL (BLOCK_TILER_OFF + 61) +#define MALI_HW_TILER_UTLB_NEW_MISS (BLOCK_TILER_OFF + 62) +#define MALI_HW_TILER_UTLB_HIT (BLOCK_TILER_OFF + 63) + +#define MALI_HW_TILER_FIRST MALI_HW_JOBS_PROCESSED +#define MALI_HW_TILER_LAST MALI_HW_TILER_UTLB_HIT + +/* Shader Core (Block 2) */ +#define BLOCK_SHADER_OFF BLOCK_OFF(2) +#define MALI_HW_SHADER_CORE_ACTIVE (BLOCK_SHADER_OFF + 3) +#define MALI_HW_FRAG_ACTIVE (BLOCK_SHADER_OFF + 4) +#define MALI_HW_FRAG_PRIMATIVES (BLOCK_SHADER_OFF + 5) +#define MALI_HW_FRAG_PRIMATIVES_DROPPED (BLOCK_SHADER_OFF + 6) +#define MALI_HW_FRAG_CYCLE_DESC (BLOCK_SHADER_OFF + 7) +#define MALI_HW_FRAG_CYCLES_PLR (BLOCK_SHADER_OFF + 8) +#define MALI_HW_FRAG_CYCLES_VERT (BLOCK_SHADER_OFF + 9) +#define MALI_HW_FRAG_CYCLES_TRISETUP (BLOCK_SHADER_OFF + 10) +#define MALI_HW_FRAG_CYCLES_RAST (BLOCK_SHADER_OFF + 11) +#define MALI_HW_FRAG_THREADS (BLOCK_SHADER_OFF + 12) +#define MALI_HW_FRAG_DUMMY_THREADS (BLOCK_SHADER_OFF + 13) +#define MALI_HW_FRAG_QUADS_RAST (BLOCK_SHADER_OFF + 14) +#define MALI_HW_FRAG_QUADS_EZS_TEST (BLOCK_SHADER_OFF + 15) +#define MALI_HW_FRAG_QUADS_EZS_KILLED (BLOCK_SHADER_OFF + 16) +#define MALI_HW_FRAG_QUADS_LZS_TEST (BLOCK_SHADER_OFF + 17) +#define MALI_HW_FRAG_QUADS_LZS_KILLED (BLOCK_SHADER_OFF + 18) +#define MALI_HW_FRAG_CYCLE_NO_TILE (BLOCK_SHADER_OFF + 19) +#define MALI_HW_FRAG_NUM_TILES (BLOCK_SHADER_OFF + 20) +#define MALI_HW_FRAG_TRANS_ELIM (BLOCK_SHADER_OFF + 21) +#define MALI_HW_COMPUTE_ACTIVE (BLOCK_SHADER_OFF + 22) +#define MALI_HW_COMPUTE_TASKS (BLOCK_SHADER_OFF + 23) +#define MALI_HW_COMPUTE_THREADS (BLOCK_SHADER_OFF + 24) +#define MALI_HW_COMPUTE_CYCLES_DESC (BLOCK_SHADER_OFF + 25) +#define MALI_HW_TRIPIPE_ACTIVE (BLOCK_SHADER_OFF + 26) +#define MALI_HW_ARITH_WORDS (BLOCK_SHADER_OFF + 27) +#define MALI_HW_ARITH_CYCLES_REG (BLOCK_SHADER_OFF + 28) +#define MALI_HW_ARITH_CYCLES_L0 (BLOCK_SHADER_OFF + 29) +#define MALI_HW_ARITH_FRAG_DEPEND (BLOCK_SHADER_OFF + 30) +#define MALI_HW_LS_WORDS (BLOCK_SHADER_OFF + 31) +#define MALI_HW_LS_ISSUES (BLOCK_SHADER_OFF + 32) +#define MALI_HW_LS_RESTARTS (BLOCK_SHADER_OFF + 33) +#define MALI_HW_LS_REISSUES_MISS (BLOCK_SHADER_OFF + 34) +#define MALI_HW_LS_REISSUES_VD (BLOCK_SHADER_OFF + 35) +#define MALI_HW_LS_REISSUE_ATTRIB_MISS (BLOCK_SHADER_OFF + 36) +#define MALI_HW_LS_NO_WB (BLOCK_SHADER_OFF + 37) +#define MALI_HW_TEX_WORDS (BLOCK_SHADER_OFF + 38) +#define MALI_HW_TEX_BUBBLES (BLOCK_SHADER_OFF + 39) +#define MALI_HW_TEX_WORDS_L0 (BLOCK_SHADER_OFF + 40) +#define MALI_HW_TEX_WORDS_DESC (BLOCK_SHADER_OFF + 41) +#define MALI_HW_TEX_THREADS (BLOCK_SHADER_OFF + 42) +#define MALI_HW_TEX_RECIRC_FMISS (BLOCK_SHADER_OFF + 43) +#define MALI_HW_TEX_RECIRC_DESC (BLOCK_SHADER_OFF + 44) +#define MALI_HW_TEX_RECIRC_MULTI (BLOCK_SHADER_OFF + 45) +#define MALI_HW_TEX_RECIRC_PMISS (BLOCK_SHADER_OFF + 46) +#define MALI_HW_TEX_RECIRC_CONF (BLOCK_SHADER_OFF + 47) +#define MALI_HW_LSC_READ_HITS (BLOCK_SHADER_OFF + 48) +#define MALI_HW_LSC_READ_MISSES (BLOCK_SHADER_OFF + 49) +#define MALI_HW_LSC_WRITE_HITS (BLOCK_SHADER_OFF + 50) +#define MALI_HW_LSC_WRITE_MISSES (BLOCK_SHADER_OFF + 51) +#define MALI_HW_LSC_ATOMIC_HITS (BLOCK_SHADER_OFF + 52) +#define MALI_HW_LSC_ATOMIC_MISSES (BLOCK_SHADER_OFF + 53) +#define MALI_HW_LSC_LINE_FETCHES (BLOCK_SHADER_OFF + 54) +#define MALI_HW_LSC_DIRTY_LINE (BLOCK_SHADER_OFF + 55) +#define MALI_HW_LSC_SNOOPS (BLOCK_SHADER_OFF + 56) +#define MALI_HW_AXI_TLB_STALL (BLOCK_SHADER_OFF + 57) +#define MALI_HW_AXI_TLB_MISS (BLOCK_SHADER_OFF + 58) +#define MALI_HW_AXI_TLB_TRANSACTION (BLOCK_SHADER_OFF + 59) +#define MALI_HW_LS_TLB_MISS (BLOCK_SHADER_OFF + 60) +#define MALI_HW_LS_TLB_HIT (BLOCK_SHADER_OFF + 61) +#define MALI_HW_AXI_BEATS_READ (BLOCK_SHADER_OFF + 62) +#define MALI_HW_AXI_BEATS_WRITE (BLOCK_SHADER_OFF + 63) + +#define MALI_HW_SHADER_FIRST MALI_HW_SHADER_CORE_ACTIVE +#define MALI_HW_SHADER_LAST MALI_HW_AXI_BEATS_WRITE + +/* L2 and MMU (Block 3) */ +#define BLOCK_MMU_OFF BLOCK_OFF(3) +#define MALI_HW_MMU_TABLE_WALK (BLOCK_MMU_OFF + 4) +#define MALI_HW_MMU_REPLAY_MISS (BLOCK_MMU_OFF + 5) +#define MALI_HW_MMU_REPLAY_FULL (BLOCK_MMU_OFF + 6) +#define MALI_HW_MMU_NEW_MISS (BLOCK_MMU_OFF + 7) +#define MALI_HW_MMU_HIT (BLOCK_MMU_OFF + 8) + +#define MALI_HW_UTLB_STALL (BLOCK_MMU_OFF + 16) +#define MALI_HW_UTLB_REPLAY_MISS (BLOCK_MMU_OFF + 17) +#define MALI_HW_UTLB_REPLAY_FULL (BLOCK_MMU_OFF + 18) +#define MALI_HW_UTLB_NEW_MISS (BLOCK_MMU_OFF + 19) +#define MALI_HW_UTLB_HIT (BLOCK_MMU_OFF + 20) + +#define MALI_HW_L2_WRITE_BEATS (BLOCK_MMU_OFF + 30) +#define MALI_HW_L2_READ_BEATS (BLOCK_MMU_OFF + 31) +#define MALI_HW_L2_ANY_LOOKUP (BLOCK_MMU_OFF + 32) +#define MALI_HW_L2_READ_LOOKUP (BLOCK_MMU_OFF + 33) +#define MALI_HW_L2_SREAD_LOOKUP (BLOCK_MMU_OFF + 34) +#define MALI_HW_L2_READ_REPLAY (BLOCK_MMU_OFF + 35) +#define MALI_HW_L2_READ_SNOOP (BLOCK_MMU_OFF + 36) +#define MALI_HW_L2_READ_HIT (BLOCK_MMU_OFF + 37) +#define MALI_HW_L2_CLEAN_MISS (BLOCK_MMU_OFF + 38) +#define MALI_HW_L2_WRITE_LOOKUP (BLOCK_MMU_OFF + 39) +#define MALI_HW_L2_SWRITE_LOOKUP (BLOCK_MMU_OFF + 40) +#define MALI_HW_L2_WRITE_REPLAY (BLOCK_MMU_OFF + 41) +#define MALI_HW_L2_WRITE_SNOOP (BLOCK_MMU_OFF + 42) +#define MALI_HW_L2_WRITE_HIT (BLOCK_MMU_OFF + 43) +#define MALI_HW_L2_EXT_READ_FULL (BLOCK_MMU_OFF + 44) +#define MALI_HW_L2_EXT_READ_HALF (BLOCK_MMU_OFF + 45) +#define MALI_HW_L2_EXT_WRITE_FULL (BLOCK_MMU_OFF + 46) +#define MALI_HW_L2_EXT_WRITE_HALF (BLOCK_MMU_OFF + 47) +#define MALI_HW_L2_EXT_READ (BLOCK_MMU_OFF + 48) +#define MALI_HW_L2_EXT_READ_LINE (BLOCK_MMU_OFF + 49) +#define MALI_HW_L2_EXT_WRITE (BLOCK_MMU_OFF + 50) +#define MALI_HW_L2_EXT_WRITE_LINE (BLOCK_MMU_OFF + 51) +#define MALI_HW_L2_EXT_WRITE_SMALL (BLOCK_MMU_OFF + 52) +#define MALI_HW_L2_EXT_BARRIER (BLOCK_MMU_OFF + 53) +#define MALI_HW_L2_EXT_AR_STALL (BLOCK_MMU_OFF + 54) +#define MALI_HW_L2_EXT_R_BUF_FULL (BLOCK_MMU_OFF + 55) +#define MALI_HW_L2_EXT_RD_BUF_FULL (BLOCK_MMU_OFF + 56) +#define MALI_HW_L2_EXT_R_RAW (BLOCK_MMU_OFF + 57) +#define MALI_HW_L2_EXT_W_STALL (BLOCK_MMU_OFF + 58) +#define MALI_HW_L2_EXT_W_BUF_FULL (BLOCK_MMU_OFF + 59) +#define MALI_HW_L2_EXT_R_W_HAZARD (BLOCK_MMU_OFF + 60) +#define MALI_HW_L2_TAG_HAZARD (BLOCK_MMU_OFF + 61) +#define MALI_HW_L2_SNOOP_FULL (BLOCK_MMU_OFF + 62) +#define MALI_HW_L2_REPLAY_FULL (BLOCK_MMU_OFF + 63) + +#define MALI_HW_MMU_FIRST MALI_HW_MMU_TABLE_WALK +#define MALI_HW_MMU_LAST MALI_HW_L2_REPLAY_FULL + +/* + * The amount of memory required to store a hwc dump is: + * # "core groups" (1) + * x # blocks (always 8 for midgard arch) + * x # counters / block (always 64) + * x # bytes / counter (4 for 32-bit counters) + */ +#define MALI_HWC_DUMP_SIZE (1*8*64*4) + +struct mali_hwcounter_state { + struct workqueue_struct *wq; /* collection context */ + struct kbase_context *ctx; /* kbase device context */ + void *buf; /* counter data buffer */ + kbase_uk_hwcnt_setup setup; /* hwcounter setup block */ + bool active; /* collecting data */ + u32 last_read[MALI_HWC_TOTAL]; /* last counter value read */ +}; +static struct mali_hwcounter_state mali_hwcs; +static struct mutex mali_hwcounter_mutex; + +/* + * Support for mapping between hw counters and trace events. + */ +struct mali_hwcounter_trace_map { + void (*do_trace)(unsigned int val); /* NB: all the same prototype */ + struct static_key *key; +}; +#define HWC_EVENT_MAP(event) \ + [MALI_HW_##event] = { \ + .do_trace = &trace_mali_hwc_##event, \ + .key = &__tracepoint_mali_hwc_##event.key \ + } + +static struct mali_hwcounter_trace_map mali_hwcounter_map[256] = { + /* Job Manager */ + HWC_EVENT_MAP(MESSAGES_SENT), + HWC_EVENT_MAP(MESSAGES_RECEIVED), + + HWC_EVENT_MAP(GPU_ACTIVE), + HWC_EVENT_MAP(IRQ_ACTIVE), + + HWC_EVENT_MAP(JS0_JOBS), + HWC_EVENT_MAP(JS0_TASKS), + HWC_EVENT_MAP(JS0_ACTIVE), + HWC_EVENT_MAP(JS0_WAIT_READ), + HWC_EVENT_MAP(JS0_WAIT_ISSUE), + HWC_EVENT_MAP(JS0_WAIT_DEPEND), + HWC_EVENT_MAP(JS0_WAIT_FINISH), + HWC_EVENT_MAP(JS1_JOBS), + HWC_EVENT_MAP(JS1_TASKS), + HWC_EVENT_MAP(JS1_ACTIVE), + HWC_EVENT_MAP(JS1_WAIT_READ), + HWC_EVENT_MAP(JS1_WAIT_ISSUE), + HWC_EVENT_MAP(JS1_WAIT_DEPEND), + HWC_EVENT_MAP(JS1_WAIT_FINISH), + HWC_EVENT_MAP(JS2_JOBS), + HWC_EVENT_MAP(JS2_TASKS), + HWC_EVENT_MAP(JS2_ACTIVE), + HWC_EVENT_MAP(JS2_WAIT_READ), + HWC_EVENT_MAP(JS2_WAIT_ISSUE), + HWC_EVENT_MAP(JS2_WAIT_DEPEND), + HWC_EVENT_MAP(JS2_WAIT_FINISH), + HWC_EVENT_MAP(JS3_JOBS), + HWC_EVENT_MAP(JS3_TASKS), + HWC_EVENT_MAP(JS3_ACTIVE), + HWC_EVENT_MAP(JS3_WAIT_READ), + HWC_EVENT_MAP(JS3_WAIT_ISSUE), + HWC_EVENT_MAP(JS3_WAIT_DEPEND), + HWC_EVENT_MAP(JS3_WAIT_FINISH), + HWC_EVENT_MAP(JS4_JOBS), + HWC_EVENT_MAP(JS4_TASKS), + HWC_EVENT_MAP(JS4_ACTIVE), + HWC_EVENT_MAP(JS4_WAIT_READ), + HWC_EVENT_MAP(JS4_WAIT_ISSUE), + HWC_EVENT_MAP(JS4_WAIT_DEPEND), + HWC_EVENT_MAP(JS4_WAIT_FINISH), + HWC_EVENT_MAP(JS5_JOBS), + HWC_EVENT_MAP(JS5_TASKS), + HWC_EVENT_MAP(JS5_ACTIVE), + HWC_EVENT_MAP(JS5_WAIT_READ), + HWC_EVENT_MAP(JS5_WAIT_ISSUE), + HWC_EVENT_MAP(JS5_WAIT_DEPEND), + HWC_EVENT_MAP(JS5_WAIT_FINISH), + HWC_EVENT_MAP(JS6_JOBS), + HWC_EVENT_MAP(JS6_TASKS), + HWC_EVENT_MAP(JS6_ACTIVE), + HWC_EVENT_MAP(JS6_WAIT_READ), + HWC_EVENT_MAP(JS6_WAIT_ISSUE), + HWC_EVENT_MAP(JS6_WAIT_DEPEND), + HWC_EVENT_MAP(JS6_WAIT_FINISH), + + /* Tiler */ + HWC_EVENT_MAP(JOBS_PROCESSED), + HWC_EVENT_MAP(TRIANGLES), + HWC_EVENT_MAP(QUADS), + HWC_EVENT_MAP(POLYGONS), + HWC_EVENT_MAP(POINTS), + HWC_EVENT_MAP(LINES), + HWC_EVENT_MAP(VCACHE_HIT), + HWC_EVENT_MAP(VCACHE_MISS), + HWC_EVENT_MAP(FRONT_FACING), + HWC_EVENT_MAP(BACK_FACING), + HWC_EVENT_MAP(PRIM_VISIBLE), + HWC_EVENT_MAP(PRIM_CULLED), + HWC_EVENT_MAP(PRIM_CLIPPED), + + HWC_EVENT_MAP(COMPRESS_IN), + HWC_EVENT_MAP(COMPRESS_OUT), + HWC_EVENT_MAP(COMPRESS_FLUSH), + HWC_EVENT_MAP(TIMESTAMPS), + HWC_EVENT_MAP(PCACHE_HIT), + HWC_EVENT_MAP(PCACHE_MISS), + HWC_EVENT_MAP(PCACHE_LINE), + HWC_EVENT_MAP(PCACHE_STALL), + HWC_EVENT_MAP(WRBUF_HIT), + HWC_EVENT_MAP(WRBUF_MISS), + HWC_EVENT_MAP(WRBUF_LINE), + HWC_EVENT_MAP(WRBUF_PARTIAL), + HWC_EVENT_MAP(WRBUF_STALL), + HWC_EVENT_MAP(ACTIVE), + HWC_EVENT_MAP(LOADING_DESC), + HWC_EVENT_MAP(INDEX_WAIT), + HWC_EVENT_MAP(INDEX_RANGE_WAIT), + HWC_EVENT_MAP(VERTEX_WAIT), + HWC_EVENT_MAP(PCACHE_WAIT), + HWC_EVENT_MAP(WRBUF_WAIT), + HWC_EVENT_MAP(BUS_READ), + HWC_EVENT_MAP(BUS_WRITE), + + HWC_EVENT_MAP(TILER_UTLB_STALL), + HWC_EVENT_MAP(TILER_UTLB_REPLAY_MISS), + HWC_EVENT_MAP(TILER_UTLB_REPLAY_FULL), + HWC_EVENT_MAP(TILER_UTLB_NEW_MISS), + HWC_EVENT_MAP(TILER_UTLB_HIT), + + /* Shader */ + HWC_EVENT_MAP(SHADER_CORE_ACTIVE), + HWC_EVENT_MAP(FRAG_ACTIVE), + HWC_EVENT_MAP(FRAG_PRIMATIVES), + HWC_EVENT_MAP(FRAG_PRIMATIVES_DROPPED), + HWC_EVENT_MAP(FRAG_CYCLE_DESC), + HWC_EVENT_MAP(FRAG_CYCLES_PLR), + HWC_EVENT_MAP(FRAG_CYCLES_VERT), + HWC_EVENT_MAP(FRAG_CYCLES_TRISETUP), + HWC_EVENT_MAP(FRAG_CYCLES_RAST), + HWC_EVENT_MAP(FRAG_THREADS), + HWC_EVENT_MAP(FRAG_DUMMY_THREADS), + HWC_EVENT_MAP(FRAG_QUADS_RAST), + HWC_EVENT_MAP(FRAG_QUADS_EZS_TEST), + HWC_EVENT_MAP(FRAG_QUADS_EZS_KILLED), + HWC_EVENT_MAP(FRAG_QUADS_LZS_TEST), + HWC_EVENT_MAP(FRAG_QUADS_LZS_KILLED), + HWC_EVENT_MAP(FRAG_CYCLE_NO_TILE), + HWC_EVENT_MAP(FRAG_NUM_TILES), + HWC_EVENT_MAP(FRAG_TRANS_ELIM), + HWC_EVENT_MAP(COMPUTE_ACTIVE), + HWC_EVENT_MAP(COMPUTE_TASKS), + HWC_EVENT_MAP(COMPUTE_THREADS), + HWC_EVENT_MAP(COMPUTE_CYCLES_DESC), + HWC_EVENT_MAP(TRIPIPE_ACTIVE), + HWC_EVENT_MAP(ARITH_WORDS), + HWC_EVENT_MAP(ARITH_CYCLES_REG), + HWC_EVENT_MAP(ARITH_CYCLES_L0), + HWC_EVENT_MAP(ARITH_FRAG_DEPEND), + HWC_EVENT_MAP(LS_WORDS), + HWC_EVENT_MAP(LS_ISSUES), + HWC_EVENT_MAP(LS_RESTARTS), + HWC_EVENT_MAP(LS_REISSUES_MISS), + HWC_EVENT_MAP(LS_REISSUES_VD), + HWC_EVENT_MAP(LS_REISSUE_ATTRIB_MISS), + HWC_EVENT_MAP(LS_NO_WB), + HWC_EVENT_MAP(TEX_WORDS), + HWC_EVENT_MAP(TEX_BUBBLES), + HWC_EVENT_MAP(TEX_WORDS_L0), + HWC_EVENT_MAP(TEX_WORDS_DESC), + HWC_EVENT_MAP(TEX_THREADS), + HWC_EVENT_MAP(TEX_RECIRC_FMISS), + HWC_EVENT_MAP(TEX_RECIRC_DESC), + HWC_EVENT_MAP(TEX_RECIRC_MULTI), + HWC_EVENT_MAP(TEX_RECIRC_PMISS), + HWC_EVENT_MAP(TEX_RECIRC_CONF), + HWC_EVENT_MAP(LSC_READ_HITS), + HWC_EVENT_MAP(LSC_READ_MISSES), + HWC_EVENT_MAP(LSC_WRITE_HITS), + HWC_EVENT_MAP(LSC_WRITE_MISSES), + HWC_EVENT_MAP(LSC_ATOMIC_HITS), + HWC_EVENT_MAP(LSC_ATOMIC_MISSES), + HWC_EVENT_MAP(LSC_LINE_FETCHES), + HWC_EVENT_MAP(LSC_DIRTY_LINE), + HWC_EVENT_MAP(LSC_SNOOPS), + HWC_EVENT_MAP(AXI_TLB_STALL), + HWC_EVENT_MAP(AXI_TLB_MISS), + HWC_EVENT_MAP(AXI_TLB_TRANSACTION), + HWC_EVENT_MAP(LS_TLB_MISS), + HWC_EVENT_MAP(LS_TLB_HIT), + HWC_EVENT_MAP(AXI_BEATS_READ), + HWC_EVENT_MAP(AXI_BEATS_WRITE), + + /* MMU */ + HWC_EVENT_MAP(MMU_TABLE_WALK), + HWC_EVENT_MAP(MMU_REPLAY_MISS), + HWC_EVENT_MAP(MMU_REPLAY_FULL), + HWC_EVENT_MAP(MMU_NEW_MISS), + HWC_EVENT_MAP(MMU_HIT), + + HWC_EVENT_MAP(UTLB_STALL), + HWC_EVENT_MAP(UTLB_REPLAY_MISS), + HWC_EVENT_MAP(UTLB_REPLAY_FULL), + HWC_EVENT_MAP(UTLB_NEW_MISS), + HWC_EVENT_MAP(UTLB_HIT), + + HWC_EVENT_MAP(L2_WRITE_BEATS), + HWC_EVENT_MAP(L2_READ_BEATS), + HWC_EVENT_MAP(L2_ANY_LOOKUP), + HWC_EVENT_MAP(L2_READ_LOOKUP), + HWC_EVENT_MAP(L2_SREAD_LOOKUP), + HWC_EVENT_MAP(L2_READ_REPLAY), + HWC_EVENT_MAP(L2_READ_SNOOP), + HWC_EVENT_MAP(L2_READ_HIT), + HWC_EVENT_MAP(L2_CLEAN_MISS), + HWC_EVENT_MAP(L2_WRITE_LOOKUP), + HWC_EVENT_MAP(L2_SWRITE_LOOKUP), + HWC_EVENT_MAP(L2_WRITE_REPLAY), + HWC_EVENT_MAP(L2_WRITE_SNOOP), + HWC_EVENT_MAP(L2_WRITE_HIT), + HWC_EVENT_MAP(L2_EXT_READ_FULL), + HWC_EVENT_MAP(L2_EXT_READ_HALF), + HWC_EVENT_MAP(L2_EXT_WRITE_FULL), + HWC_EVENT_MAP(L2_EXT_WRITE_HALF), + HWC_EVENT_MAP(L2_EXT_READ), + HWC_EVENT_MAP(L2_EXT_READ_LINE), + HWC_EVENT_MAP(L2_EXT_WRITE), + HWC_EVENT_MAP(L2_EXT_WRITE_LINE), + HWC_EVENT_MAP(L2_EXT_WRITE_SMALL), + HWC_EVENT_MAP(L2_EXT_BARRIER), + HWC_EVENT_MAP(L2_EXT_AR_STALL), + HWC_EVENT_MAP(L2_EXT_R_BUF_FULL), + HWC_EVENT_MAP(L2_EXT_RD_BUF_FULL), + HWC_EVENT_MAP(L2_EXT_R_RAW), + HWC_EVENT_MAP(L2_EXT_W_STALL), + HWC_EVENT_MAP(L2_EXT_W_BUF_FULL), + HWC_EVENT_MAP(L2_EXT_R_W_HAZARD), + HWC_EVENT_MAP(L2_TAG_HAZARD), + HWC_EVENT_MAP(L2_SNOOP_FULL), + HWC_EVENT_MAP(L2_REPLAY_FULL), +}; + +/* + * Support for building hw counter enable bitmaps from enabled trace events. + */ +#define __BLOCK_CHECK_ENABLED(block, bm_name) do { \ + int ev; \ + for (ev = block##_FIRST; ev <= block##_LAST; ev++) { \ + const struct mali_hwcounter_trace_map *map = \ + &mali_hwcounter_map[ev]; \ + if (map->key != NULL && static_key_false(map->key)) { \ + mali_hwcs.setup.bm_name |= 1<key != NULL && static_key_false(map->key) && \ + block_update(boff, ev)) \ + map->do_trace(mali_hwcs.last_read[ev]); \ + } \ +} while (0) +#define JM_DISPATCH_EVENTS() \ + __BLOCK_DISPATCH_EVENTS(MALI_HW_JM, jm_bm, 0x700) +#define TILER_DISPATCH_EVENTS() \ + __BLOCK_DISPATCH_EVENTS(MALI_HW_TILER, tiler_bm, 0x400) +#define MMU_DISPATCH_EVENTS() \ + __BLOCK_DISPATCH_EVENTS(MALI_HW_MMU, mmu_l2_bm, 0x500) + +static int shader_block_update(const int event_num) +{ + const u32 *block = ((const u32 *)((uintptr_t)mali_hwcs.buf + 0x000)); + u32 value = block[hwc_off(event_num)] + + block[hwc_off(event_num) + 0x100] + + block[hwc_off(event_num) + 0x200] + + block[hwc_off(event_num) + 0x300] + ; + if (value != mali_hwcs.last_read[event_num]) { + mali_hwcs.last_read[event_num] = value; + return true; + } else + return false; +} + +#define SHADER_DISPATCH_EVENTS() do { \ + int ev; \ + for (ev = MALI_HW_SHADER_FIRST; ev <= MALI_HW_SHADER_LAST; ev++) {\ + const struct mali_hwcounter_trace_map *map = \ + &mali_hwcounter_map[ev]; \ + /* NB: each enable bit covers 4 counters */ \ + if ((mali_hwcs.setup.shader_bm & (1<key != NULL && static_key_false(map->key) && \ + shader_block_update(ev)) \ + map->do_trace(mali_hwcs.last_read[ev]); \ + } \ +} while (0) + +/* + * Collect hw counter data and dispatch trace events. + * This runs from the workqueue so it can block when + * fetching hw counter data. + */ +static void mali_hwcounter_collect(struct work_struct *w) +{ + mali_error error; + + mutex_lock(&mali_hwcounter_mutex); + if (mali_hwcs.active) { + /* NB: dumping the counters can block */ + error = kbase_instr_hwcnt_dump(mali_hwcs.ctx); + if (error == MALI_ERROR_NONE) { + /* extract data and generate trace events */ + JM_DISPATCH_EVENTS(); + TILER_DISPATCH_EVENTS(); + SHADER_DISPATCH_EVENTS(); + MMU_DISPATCH_EVENTS(); + } else + pr_err("%s: failed to dump hw counters\n", __func__); + } + mutex_unlock(&mali_hwcounter_mutex); +} +static DECLARE_WORK(mali_hwcounter_work, mali_hwcounter_collect); + +/* + * drm vblank notifier; used to trigger hw counter polling. + */ +static int mali_hwcounter_vblank(struct notifier_block *nb, + unsigned long unused, void *data) +{ + /* punt to work queue where we can block */ + queue_work_on(0, mali_hwcs.wq, &mali_hwcounter_work); + return 0; +} +static struct notifier_block mali_vblank_notifier = { + .notifier_call = mali_hwcounter_vblank, +}; + +/* + * Start hw counter polling. Construct the counter enable bitmaps + * based on the enabled trace events, call kbase to turn on counters, + * and arrange polling at vblank. + */ +static int mali_hwcounter_polling_start(struct kbase_device *kbdev) +{ + int ncounters = 0; + + mutex_lock(&mali_hwcounter_mutex); + if (mali_hwcs.active) { + mutex_unlock(&mali_hwcounter_mutex); + return -EALREADY; + } + + /* Construct hw counter bitmaps from enabled trace events */ + memset(&mali_hwcs.setup, 0, sizeof(mali_hwcs.setup)); + + JM_CHECK_ENABLED(); + TILER_CHECK_ENABLED(); + SHADER_CHECK_ENABLED(); + MMU_CHECK_ENABLED(); + + if (ncounters > 0) { + mali_error error; + + mali_hwcs.ctx = kbase_create_context(kbdev); + if (mali_hwcs.ctx == NULL) { + pr_err("%s: cannot create context\n", __func__); + mutex_unlock(&mali_hwcounter_mutex); + return -ENOSPC; + } + mali_hwcs.buf = kbase_va_alloc(mali_hwcs.ctx, + MALI_HWC_DUMP_SIZE); + mali_hwcs.setup.dump_buffer = (uintptr_t) mali_hwcs.buf; + + error = kbase_instr_hwcnt_enable(mali_hwcs.ctx, + &mali_hwcs.setup); + if (error != MALI_ERROR_NONE) { + pr_err("%s: cannot enable hw counters\n", __func__); + + kbase_va_free(mali_hwcs.ctx, mali_hwcs.buf); + mali_hwcs.buf = NULL; + + kbase_destroy_context(mali_hwcs.ctx); + mali_hwcs.ctx = NULL; + + mutex_unlock(&mali_hwcounter_mutex); + return -EIO; + } + kbase_instr_hwcnt_clear(mali_hwcs.ctx); + mali_hwcs.active = true; + /* NB: use 0 to minimize meaningless events */ + memset(mali_hwcs.last_read, 0, sizeof(mali_hwcs.last_read)); + + drm_vblank_register_notifier(&mali_vblank_notifier); + } + mutex_unlock(&mali_hwcounter_mutex); + + return 0; +} + +/* + * Stop hw counter polling. Disable polling, turn off hw counters, + * and release our resources. + */ +static void mali_hwcounter_polling_stop(struct kbase_device *kbdev) +{ + mutex_lock(&mali_hwcounter_mutex); + if (mali_hwcs.active) { + drm_vblank_unregister_notifier(&mali_vblank_notifier); + + kbase_instr_hwcnt_disable(mali_hwcs.ctx); + + kbase_va_free(mali_hwcs.ctx, mali_hwcs.buf); + mali_hwcs.buf = NULL; + + kbase_destroy_context(mali_hwcs.ctx); + mali_hwcs.ctx = NULL; + + mali_hwcs.active = false; + } + mutex_unlock(&mali_hwcounter_mutex); +} + +static ssize_t mali_sysfs_show_hwc_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", (mali_hwcs.active == true)); +} + +static ssize_t mali_sysfs_set_hwc_enable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct kbase_device *kbdev = dev_get_drvdata(dev); + int error; + bool enable; + + if (strtobool(buf, &enable) < 0) + return -EINVAL; + if (enable) { + error = mali_hwcounter_polling_start(kbdev); + if (error < 0) + return error; + } else + mali_hwcounter_polling_stop(kbdev); + return count; +} +DEVICE_ATTR(hwc_enable, S_IRUGO|S_IWUSR, mali_sysfs_show_hwc_enable, + mali_sysfs_set_hwc_enable); + +static int mali_setup_system_tracing(struct device *dev) +{ + mutex_init(&mali_hwcounter_mutex); + mali_hwcs.wq = create_singlethread_workqueue("mali_hwc"); + mali_hwcs.active = false; + + if (device_create_file(dev, &dev_attr_hwc_enable)) { + dev_err(dev, "Couldn't create sysfs file [hwc_enable]\n"); + return -ENOENT; + } + return 0; +} + +static void mali_cleanup_system_tracing(struct device *dev) +{ + struct kbase_device *kbdev = dev_get_drvdata(dev); + + mali_hwcounter_polling_stop(kbdev); + destroy_workqueue(mali_hwcs.wq); + device_remove_file(dev, &dev_attr_hwc_enable); + mutex_destroy(&mali_hwcounter_mutex); +} +#endif /* CONFIG_MALI_HWC_TRACE && CONFIG_MALI_T6XX_DEBUG_SYS */ diff --git a/drivers/gpu/arm/midgard/platform/arndale/mali_linux_dvfs_trace.h b/drivers/gpu/arm/midgard/platform/arndale/mali_linux_dvfs_trace.h new file mode 100644 index 00000000000..eba94a35f1d --- /dev/null +++ b/drivers/gpu/arm/midgard/platform/arndale/mali_linux_dvfs_trace.h @@ -0,0 +1,69 @@ +/* + * + * (C) COPYRIGHT 2011-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. + * + */ + +#if !defined(_TRACE_MALI_DVFS_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_MALI_DVFS_H + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM mali_dvfs + +#include + +TRACE_EVENT(mali_dvfs_event, + TP_PROTO(unsigned int util, int avg), + TP_ARGS(util, avg), + TP_STRUCT__entry( + __field(unsigned int, utilization) + __field(int, avg_utilization) + ), + TP_fast_assign( + __entry->utilization = util; + __entry->avg_utilization = avg; + ), + TP_printk("utilization=%u avg=%d", + __entry->utilization, __entry->avg_utilization) +); + +TRACE_EVENT(mali_dvfs_set_voltage, + TP_PROTO(unsigned int vol), + TP_ARGS(vol), + TP_STRUCT__entry( + __field(unsigned int, voltage) + ), + TP_fast_assign( + __entry->voltage = vol; + ), + TP_printk("voltage=%u", __entry->voltage) +); + +TRACE_EVENT(mali_dvfs_set_clock, + TP_PROTO(int freq), + TP_ARGS(freq), + TP_STRUCT__entry( + __field(int, frequency) + ), + TP_fast_assign( + __entry->frequency = freq; + ), + TP_printk("frequency=%d", __entry->frequency) +); + +#endif /* _TRACE_MALI_DVFS_H */ + +#undef TRACE_INCLUDE_PATH +#undef linux +#define TRACE_INCLUDE_PATH MALI_KBASE_THIRDPARTY_PATH +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE mali_linux_dvfs_trace + +/* This part must be outside protection */ +#include diff --git a/drivers/gpu/arm/midgard/platform/arndale/mali_linux_hwc_trace.h b/drivers/gpu/arm/midgard/platform/arndale/mali_linux_hwc_trace.h new file mode 100644 index 00000000000..4c6bd4b5ad0 --- /dev/null +++ b/drivers/gpu/arm/midgard/platform/arndale/mali_linux_hwc_trace.h @@ -0,0 +1,262 @@ +/* + * + * (C) COPYRIGHT 2011-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. + * + */ + +#if !defined(_TRACE_MALI_HWC_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_MALI_HWC_H + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM mali_hwc + +#include + +DECLARE_EVENT_CLASS(mali_hw_counter_template, + TP_PROTO(unsigned int val), + TP_ARGS(val), + TP_STRUCT__entry( + __field( unsigned int, val ) + ), + TP_fast_assign( + __entry->val = val; + ), + TP_printk("val=%u", __entry->val) +); + +#define DEFINE_MALI_HW_COUNTER_EVENT(name) \ +DEFINE_EVENT(mali_hw_counter_template, mali_hwc_##name, \ + TP_PROTO(unsigned int info_val), \ + TP_ARGS(info_val)) +DEFINE_MALI_HW_COUNTER_EVENT(MESSAGES_SENT); +DEFINE_MALI_HW_COUNTER_EVENT(MESSAGES_RECEIVED); +DEFINE_MALI_HW_COUNTER_EVENT(GPU_ACTIVE); +DEFINE_MALI_HW_COUNTER_EVENT(IRQ_ACTIVE); +DEFINE_MALI_HW_COUNTER_EVENT(JS0_JOBS); +DEFINE_MALI_HW_COUNTER_EVENT(JS0_TASKS); +DEFINE_MALI_HW_COUNTER_EVENT(JS0_ACTIVE); +DEFINE_MALI_HW_COUNTER_EVENT(JS0_WAIT_READ); +DEFINE_MALI_HW_COUNTER_EVENT(JS0_WAIT_ISSUE); +DEFINE_MALI_HW_COUNTER_EVENT(JS0_WAIT_DEPEND); +DEFINE_MALI_HW_COUNTER_EVENT(JS0_WAIT_FINISH); +DEFINE_MALI_HW_COUNTER_EVENT(JS1_JOBS); +DEFINE_MALI_HW_COUNTER_EVENT(JS1_TASKS); +DEFINE_MALI_HW_COUNTER_EVENT(JS1_ACTIVE); +DEFINE_MALI_HW_COUNTER_EVENT(JS1_WAIT_READ); +DEFINE_MALI_HW_COUNTER_EVENT(JS1_WAIT_ISSUE); +DEFINE_MALI_HW_COUNTER_EVENT(JS1_WAIT_DEPEND); +DEFINE_MALI_HW_COUNTER_EVENT(JS1_WAIT_FINISH); +DEFINE_MALI_HW_COUNTER_EVENT(JS2_JOBS); +DEFINE_MALI_HW_COUNTER_EVENT(JS2_TASKS); +DEFINE_MALI_HW_COUNTER_EVENT(JS2_ACTIVE); +DEFINE_MALI_HW_COUNTER_EVENT(JS2_WAIT_READ); +DEFINE_MALI_HW_COUNTER_EVENT(JS2_WAIT_ISSUE); +DEFINE_MALI_HW_COUNTER_EVENT(JS2_WAIT_DEPEND); +DEFINE_MALI_HW_COUNTER_EVENT(JS2_WAIT_FINISH); +DEFINE_MALI_HW_COUNTER_EVENT(JS3_JOBS); +DEFINE_MALI_HW_COUNTER_EVENT(JS3_TASKS); +DEFINE_MALI_HW_COUNTER_EVENT(JS3_ACTIVE); +DEFINE_MALI_HW_COUNTER_EVENT(JS3_WAIT_READ); +DEFINE_MALI_HW_COUNTER_EVENT(JS3_WAIT_ISSUE); +DEFINE_MALI_HW_COUNTER_EVENT(JS3_WAIT_DEPEND); +DEFINE_MALI_HW_COUNTER_EVENT(JS3_WAIT_FINISH); +DEFINE_MALI_HW_COUNTER_EVENT(JS4_JOBS); +DEFINE_MALI_HW_COUNTER_EVENT(JS4_TASKS); +DEFINE_MALI_HW_COUNTER_EVENT(JS4_ACTIVE); +DEFINE_MALI_HW_COUNTER_EVENT(JS4_WAIT_READ); +DEFINE_MALI_HW_COUNTER_EVENT(JS4_WAIT_ISSUE); +DEFINE_MALI_HW_COUNTER_EVENT(JS4_WAIT_DEPEND); +DEFINE_MALI_HW_COUNTER_EVENT(JS4_WAIT_FINISH); +DEFINE_MALI_HW_COUNTER_EVENT(JS5_JOBS); +DEFINE_MALI_HW_COUNTER_EVENT(JS5_TASKS); +DEFINE_MALI_HW_COUNTER_EVENT(JS5_ACTIVE); +DEFINE_MALI_HW_COUNTER_EVENT(JS5_WAIT_READ); +DEFINE_MALI_HW_COUNTER_EVENT(JS5_WAIT_ISSUE); +DEFINE_MALI_HW_COUNTER_EVENT(JS5_WAIT_DEPEND); +DEFINE_MALI_HW_COUNTER_EVENT(JS5_WAIT_FINISH); +DEFINE_MALI_HW_COUNTER_EVENT(JS6_JOBS); +DEFINE_MALI_HW_COUNTER_EVENT(JS6_TASKS); +DEFINE_MALI_HW_COUNTER_EVENT(JS6_ACTIVE); +DEFINE_MALI_HW_COUNTER_EVENT(JS6_WAIT_READ); +DEFINE_MALI_HW_COUNTER_EVENT(JS6_WAIT_ISSUE); +DEFINE_MALI_HW_COUNTER_EVENT(JS6_WAIT_DEPEND); +DEFINE_MALI_HW_COUNTER_EVENT(JS6_WAIT_FINISH); +DEFINE_MALI_HW_COUNTER_EVENT(JOBS_PROCESSED); +DEFINE_MALI_HW_COUNTER_EVENT(TRIANGLES); +DEFINE_MALI_HW_COUNTER_EVENT(QUADS); +DEFINE_MALI_HW_COUNTER_EVENT(POLYGONS); +DEFINE_MALI_HW_COUNTER_EVENT(POINTS); +DEFINE_MALI_HW_COUNTER_EVENT(LINES); +DEFINE_MALI_HW_COUNTER_EVENT(VCACHE_HIT); +DEFINE_MALI_HW_COUNTER_EVENT(VCACHE_MISS); +DEFINE_MALI_HW_COUNTER_EVENT(FRONT_FACING); +DEFINE_MALI_HW_COUNTER_EVENT(BACK_FACING); +DEFINE_MALI_HW_COUNTER_EVENT(PRIM_VISIBLE); +DEFINE_MALI_HW_COUNTER_EVENT(PRIM_CULLED); +DEFINE_MALI_HW_COUNTER_EVENT(PRIM_CLIPPED); +DEFINE_MALI_HW_COUNTER_EVENT(LEVEL0); +DEFINE_MALI_HW_COUNTER_EVENT(LEVEL1); +DEFINE_MALI_HW_COUNTER_EVENT(LEVEL2); +DEFINE_MALI_HW_COUNTER_EVENT(LEVEL3); +DEFINE_MALI_HW_COUNTER_EVENT(LEVEL4); +DEFINE_MALI_HW_COUNTER_EVENT(LEVEL5); +DEFINE_MALI_HW_COUNTER_EVENT(LEVEL6); +DEFINE_MALI_HW_COUNTER_EVENT(LEVEL7); +DEFINE_MALI_HW_COUNTER_EVENT(COMMAND_1); +DEFINE_MALI_HW_COUNTER_EVENT(COMMAND_2); +DEFINE_MALI_HW_COUNTER_EVENT(COMMAND_3); +DEFINE_MALI_HW_COUNTER_EVENT(COMMAND_4); +DEFINE_MALI_HW_COUNTER_EVENT(COMMAND_4_7); +DEFINE_MALI_HW_COUNTER_EVENT(COMMAND_8_15); +DEFINE_MALI_HW_COUNTER_EVENT(COMMAND_16_63); +DEFINE_MALI_HW_COUNTER_EVENT(COMMAND_64); +DEFINE_MALI_HW_COUNTER_EVENT(COMPRESS_IN); +DEFINE_MALI_HW_COUNTER_EVENT(COMPRESS_OUT); +DEFINE_MALI_HW_COUNTER_EVENT(COMPRESS_FLUSH); +DEFINE_MALI_HW_COUNTER_EVENT(TIMESTAMPS); +DEFINE_MALI_HW_COUNTER_EVENT(PCACHE_HIT); +DEFINE_MALI_HW_COUNTER_EVENT(PCACHE_MISS); +DEFINE_MALI_HW_COUNTER_EVENT(PCACHE_LINE); +DEFINE_MALI_HW_COUNTER_EVENT(PCACHE_STALL); +DEFINE_MALI_HW_COUNTER_EVENT(WRBUF_HIT); +DEFINE_MALI_HW_COUNTER_EVENT(WRBUF_MISS); +DEFINE_MALI_HW_COUNTER_EVENT(WRBUF_LINE); +DEFINE_MALI_HW_COUNTER_EVENT(WRBUF_PARTIAL); +DEFINE_MALI_HW_COUNTER_EVENT(WRBUF_STALL); +DEFINE_MALI_HW_COUNTER_EVENT(ACTIVE); +DEFINE_MALI_HW_COUNTER_EVENT(LOADING_DESC); +DEFINE_MALI_HW_COUNTER_EVENT(INDEX_WAIT); +DEFINE_MALI_HW_COUNTER_EVENT(INDEX_RANGE_WAIT); +DEFINE_MALI_HW_COUNTER_EVENT(VERTEX_WAIT); +DEFINE_MALI_HW_COUNTER_EVENT(PCACHE_WAIT); +DEFINE_MALI_HW_COUNTER_EVENT(WRBUF_WAIT); +DEFINE_MALI_HW_COUNTER_EVENT(BUS_READ); +DEFINE_MALI_HW_COUNTER_EVENT(BUS_WRITE); +DEFINE_MALI_HW_COUNTER_EVENT(TILER_UTLB_STALL); +DEFINE_MALI_HW_COUNTER_EVENT(TILER_UTLB_REPLAY_MISS); +DEFINE_MALI_HW_COUNTER_EVENT(TILER_UTLB_REPLAY_FULL); +DEFINE_MALI_HW_COUNTER_EVENT(TILER_UTLB_NEW_MISS); +DEFINE_MALI_HW_COUNTER_EVENT(TILER_UTLB_HIT); +DEFINE_MALI_HW_COUNTER_EVENT(SHADER_CORE_ACTIVE); +DEFINE_MALI_HW_COUNTER_EVENT(FRAG_ACTIVE); +DEFINE_MALI_HW_COUNTER_EVENT(FRAG_PRIMATIVES); +DEFINE_MALI_HW_COUNTER_EVENT(FRAG_PRIMATIVES_DROPPED); +DEFINE_MALI_HW_COUNTER_EVENT(FRAG_CYCLE_DESC); +DEFINE_MALI_HW_COUNTER_EVENT(FRAG_CYCLES_PLR); +DEFINE_MALI_HW_COUNTER_EVENT(FRAG_CYCLES_VERT); +DEFINE_MALI_HW_COUNTER_EVENT(FRAG_CYCLES_TRISETUP); +DEFINE_MALI_HW_COUNTER_EVENT(FRAG_CYCLES_RAST); +DEFINE_MALI_HW_COUNTER_EVENT(FRAG_THREADS); +DEFINE_MALI_HW_COUNTER_EVENT(FRAG_DUMMY_THREADS); +DEFINE_MALI_HW_COUNTER_EVENT(FRAG_QUADS_RAST); +DEFINE_MALI_HW_COUNTER_EVENT(FRAG_QUADS_EZS_TEST); +DEFINE_MALI_HW_COUNTER_EVENT(FRAG_QUADS_EZS_KILLED); +DEFINE_MALI_HW_COUNTER_EVENT(FRAG_QUADS_LZS_TEST); +DEFINE_MALI_HW_COUNTER_EVENT(FRAG_QUADS_LZS_KILLED); +DEFINE_MALI_HW_COUNTER_EVENT(FRAG_CYCLE_NO_TILE); +DEFINE_MALI_HW_COUNTER_EVENT(FRAG_NUM_TILES); +DEFINE_MALI_HW_COUNTER_EVENT(FRAG_TRANS_ELIM); +DEFINE_MALI_HW_COUNTER_EVENT(COMPUTE_ACTIVE); +DEFINE_MALI_HW_COUNTER_EVENT(COMPUTE_TASKS); +DEFINE_MALI_HW_COUNTER_EVENT(COMPUTE_THREADS); +DEFINE_MALI_HW_COUNTER_EVENT(COMPUTE_CYCLES_DESC); +DEFINE_MALI_HW_COUNTER_EVENT(TRIPIPE_ACTIVE); +DEFINE_MALI_HW_COUNTER_EVENT(ARITH_WORDS); +DEFINE_MALI_HW_COUNTER_EVENT(ARITH_CYCLES_REG); +DEFINE_MALI_HW_COUNTER_EVENT(ARITH_CYCLES_L0); +DEFINE_MALI_HW_COUNTER_EVENT(ARITH_FRAG_DEPEND); +DEFINE_MALI_HW_COUNTER_EVENT(LS_WORDS); +DEFINE_MALI_HW_COUNTER_EVENT(LS_ISSUES); +DEFINE_MALI_HW_COUNTER_EVENT(LS_RESTARTS); +DEFINE_MALI_HW_COUNTER_EVENT(LS_REISSUES_MISS); +DEFINE_MALI_HW_COUNTER_EVENT(LS_REISSUES_VD); +DEFINE_MALI_HW_COUNTER_EVENT(LS_REISSUE_ATTRIB_MISS); +DEFINE_MALI_HW_COUNTER_EVENT(LS_NO_WB); +DEFINE_MALI_HW_COUNTER_EVENT(TEX_WORDS); +DEFINE_MALI_HW_COUNTER_EVENT(TEX_BUBBLES); +DEFINE_MALI_HW_COUNTER_EVENT(TEX_WORDS_L0); +DEFINE_MALI_HW_COUNTER_EVENT(TEX_WORDS_DESC); +DEFINE_MALI_HW_COUNTER_EVENT(TEX_THREADS); +DEFINE_MALI_HW_COUNTER_EVENT(TEX_RECIRC_FMISS); +DEFINE_MALI_HW_COUNTER_EVENT(TEX_RECIRC_DESC); +DEFINE_MALI_HW_COUNTER_EVENT(TEX_RECIRC_MULTI); +DEFINE_MALI_HW_COUNTER_EVENT(TEX_RECIRC_PMISS); +DEFINE_MALI_HW_COUNTER_EVENT(TEX_RECIRC_CONF); +DEFINE_MALI_HW_COUNTER_EVENT(LSC_READ_HITS); +DEFINE_MALI_HW_COUNTER_EVENT(LSC_READ_MISSES); +DEFINE_MALI_HW_COUNTER_EVENT(LSC_WRITE_HITS); +DEFINE_MALI_HW_COUNTER_EVENT(LSC_WRITE_MISSES); +DEFINE_MALI_HW_COUNTER_EVENT(LSC_ATOMIC_HITS); +DEFINE_MALI_HW_COUNTER_EVENT(LSC_ATOMIC_MISSES); +DEFINE_MALI_HW_COUNTER_EVENT(LSC_LINE_FETCHES); +DEFINE_MALI_HW_COUNTER_EVENT(LSC_DIRTY_LINE); +DEFINE_MALI_HW_COUNTER_EVENT(LSC_SNOOPS); +DEFINE_MALI_HW_COUNTER_EVENT(AXI_TLB_STALL); +DEFINE_MALI_HW_COUNTER_EVENT(AXI_TLB_MISS); +DEFINE_MALI_HW_COUNTER_EVENT(AXI_TLB_TRANSACTION); +DEFINE_MALI_HW_COUNTER_EVENT(LS_TLB_MISS); +DEFINE_MALI_HW_COUNTER_EVENT(LS_TLB_HIT); +DEFINE_MALI_HW_COUNTER_EVENT(AXI_BEATS_READ); +DEFINE_MALI_HW_COUNTER_EVENT(AXI_BEATS_WRITE); +DEFINE_MALI_HW_COUNTER_EVENT(MMU_TABLE_WALK); +DEFINE_MALI_HW_COUNTER_EVENT(MMU_REPLAY_MISS); +DEFINE_MALI_HW_COUNTER_EVENT(MMU_REPLAY_FULL); +DEFINE_MALI_HW_COUNTER_EVENT(MMU_NEW_MISS); +DEFINE_MALI_HW_COUNTER_EVENT(MMU_HIT); +DEFINE_MALI_HW_COUNTER_EVENT(UTLB_STALL); +DEFINE_MALI_HW_COUNTER_EVENT(UTLB_REPLAY_MISS); +DEFINE_MALI_HW_COUNTER_EVENT(UTLB_REPLAY_FULL); +DEFINE_MALI_HW_COUNTER_EVENT(UTLB_NEW_MISS); +DEFINE_MALI_HW_COUNTER_EVENT(UTLB_HIT); +DEFINE_MALI_HW_COUNTER_EVENT(L2_WRITE_BEATS); +DEFINE_MALI_HW_COUNTER_EVENT(L2_READ_BEATS); +DEFINE_MALI_HW_COUNTER_EVENT(L2_ANY_LOOKUP); +DEFINE_MALI_HW_COUNTER_EVENT(L2_READ_LOOKUP); +DEFINE_MALI_HW_COUNTER_EVENT(L2_SREAD_LOOKUP); +DEFINE_MALI_HW_COUNTER_EVENT(L2_READ_REPLAY); +DEFINE_MALI_HW_COUNTER_EVENT(L2_READ_SNOOP); +DEFINE_MALI_HW_COUNTER_EVENT(L2_READ_HIT); +DEFINE_MALI_HW_COUNTER_EVENT(L2_CLEAN_MISS); +DEFINE_MALI_HW_COUNTER_EVENT(L2_WRITE_LOOKUP); +DEFINE_MALI_HW_COUNTER_EVENT(L2_SWRITE_LOOKUP); +DEFINE_MALI_HW_COUNTER_EVENT(L2_WRITE_REPLAY); +DEFINE_MALI_HW_COUNTER_EVENT(L2_WRITE_SNOOP); +DEFINE_MALI_HW_COUNTER_EVENT(L2_WRITE_HIT); +DEFINE_MALI_HW_COUNTER_EVENT(L2_EXT_READ_FULL); +DEFINE_MALI_HW_COUNTER_EVENT(L2_EXT_READ_HALF); +DEFINE_MALI_HW_COUNTER_EVENT(L2_EXT_WRITE_FULL); +DEFINE_MALI_HW_COUNTER_EVENT(L2_EXT_WRITE_HALF); +DEFINE_MALI_HW_COUNTER_EVENT(L2_EXT_READ); +DEFINE_MALI_HW_COUNTER_EVENT(L2_EXT_READ_LINE); +DEFINE_MALI_HW_COUNTER_EVENT(L2_EXT_WRITE); +DEFINE_MALI_HW_COUNTER_EVENT(L2_EXT_WRITE_LINE); +DEFINE_MALI_HW_COUNTER_EVENT(L2_EXT_WRITE_SMALL); +DEFINE_MALI_HW_COUNTER_EVENT(L2_EXT_BARRIER); +DEFINE_MALI_HW_COUNTER_EVENT(L2_EXT_AR_STALL); +DEFINE_MALI_HW_COUNTER_EVENT(L2_EXT_R_BUF_FULL); +DEFINE_MALI_HW_COUNTER_EVENT(L2_EXT_RD_BUF_FULL); +DEFINE_MALI_HW_COUNTER_EVENT(L2_EXT_R_RAW); +DEFINE_MALI_HW_COUNTER_EVENT(L2_EXT_W_STALL); +DEFINE_MALI_HW_COUNTER_EVENT(L2_EXT_W_BUF_FULL); +DEFINE_MALI_HW_COUNTER_EVENT(L2_EXT_R_W_HAZARD); +DEFINE_MALI_HW_COUNTER_EVENT(L2_TAG_HAZARD); +DEFINE_MALI_HW_COUNTER_EVENT(L2_SNOOP_FULL); +DEFINE_MALI_HW_COUNTER_EVENT(L2_REPLAY_FULL); +#undef DEFINE_MALI_HW_COUNTER_EVENT + +#endif /* _TRACE_MALI_HWC_H */ + +#undef TRACE_INCLUDE_PATH +#undef linux +#define TRACE_INCLUDE_PATH MALI_KBASE_THIRDPARTY_PATH +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE mali_linux_hwc_trace + +/* This part must be outside protection */ +#include -- cgit v1.2.3