summaryrefslogtreecommitdiff
path: root/drivers/gpu/arm/utgard/platform
diff options
context:
space:
mode:
authorLinaro CI <ci_notify@linaro.org>2017-09-24 20:35:18 +0000
committerLinaro CI <ci_notify@linaro.org>2017-09-24 20:35:18 +0000
commitc03adb6848aa7e80ad0c0e46b9f6d96ba0a91822 (patch)
tree05de08cd2d77fc5697e9e6fc1fae5ef23a1d0a85 /drivers/gpu/arm/utgard/platform
parent6ce85a78b6151e8ab2eac57e1447d90d3efb551d (diff)
parent357fdc8959dc79696d9c43c2a3f7a93e3a503d87 (diff)
Merge remote-tracking branch 'sumit-lts/lts-4.4.y-hikey' into linux-4.4.y4.4.89-rc1-hikey-20170924
Diffstat (limited to 'drivers/gpu/arm/utgard/platform')
-rw-r--r--drivers/gpu/arm/utgard/platform/arm/arm.c439
-rw-r--r--drivers/gpu/arm/utgard/platform/arm/arm_core_scaling.c122
-rw-r--r--drivers/gpu/arm/utgard/platform/arm/arm_core_scaling.h44
-rw-r--r--drivers/gpu/arm/utgard/platform/hikey/mali_hikey.c683
-rw-r--r--drivers/gpu/arm/utgard/platform/hikey/mali_hikey_hi6220_registers_gpu.h66
5 files changed, 1354 insertions, 0 deletions
diff --git a/drivers/gpu/arm/utgard/platform/arm/arm.c b/drivers/gpu/arm/utgard/platform/arm/arm.c
new file mode 100644
index 000000000000..41ad63c0793b
--- /dev/null
+++ b/drivers/gpu/arm/utgard/platform/arm/arm.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2010, 2012-2015 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * @file mali_platform.c
+ * Platform specific Mali driver functions for:
+ * - Realview Versatile platforms with ARM11 Mpcore and virtex 5.
+ * - Versatile Express platforms with ARM Cortex-A9 and virtex 6.
+ */
+#include <linux/platform_device.h>
+#include <linux/version.h>
+#include <linux/pm.h>
+#ifdef CONFIG_PM_RUNTIME
+#include <linux/pm_runtime.h>
+#endif
+#include <asm/io.h>
+#include <linux/mali/mali_utgard.h>
+#include "mali_kernel_common.h"
+#include <linux/dma-mapping.h>
+#include <linux/moduleparam.h>
+
+#include "arm_core_scaling.h"
+#include "mali_executor.h"
+
+
+static int mali_core_scaling_enable = 0;
+
+void mali_gpu_utilization_callback(struct mali_gpu_utilization_data *data);
+static u32 mali_read_phys(u32 phys_addr);
+#if defined(CONFIG_ARCH_REALVIEW)
+static void mali_write_phys(u32 phys_addr, u32 value);
+#endif
+
+#ifndef CONFIG_MALI_DT
+static void mali_platform_device_release(struct device *device);
+
+#if defined(CONFIG_ARCH_VEXPRESS)
+
+#if defined(CONFIG_ARM64)
+/* Juno + Mali-450 MP6 in V7 FPGA */
+static struct resource mali_gpu_resources_m450_mp6[] = {
+ MALI_GPU_RESOURCES_MALI450_MP6_PMU(0x6F040000, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200)
+};
+
+static struct resource mali_gpu_resources_m470_mp4[] = {
+ MALI_GPU_RESOURCES_MALI470_MP4_PMU(0x6F040000, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200)
+};
+
+static struct resource mali_gpu_resources_m470_mp3[] = {
+ MALI_GPU_RESOURCES_MALI470_MP3_PMU(0x6F040000, 200, 200, 200, 200, 200, 200, 200, 200, 200)
+};
+
+static struct resource mali_gpu_resources_m470_mp2[] = {
+ MALI_GPU_RESOURCES_MALI470_MP2_PMU(0x6F040000, 200, 200, 200, 200, 200, 200, 200)
+};
+
+static struct resource mali_gpu_resources_m470_mp1[] = {
+ MALI_GPU_RESOURCES_MALI470_MP1_PMU(0x6F040000, 200, 200, 200, 200, 200)
+};
+
+#else
+static struct resource mali_gpu_resources_m450_mp8[] = {
+ MALI_GPU_RESOURCES_MALI450_MP8_PMU(0xFC040000, -1, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 68)
+};
+
+static struct resource mali_gpu_resources_m450_mp6[] = {
+ MALI_GPU_RESOURCES_MALI450_MP6_PMU(0xFC040000, -1, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 68)
+};
+
+static struct resource mali_gpu_resources_m450_mp4[] = {
+ MALI_GPU_RESOURCES_MALI450_MP4_PMU(0xFC040000, -1, 70, 70, 70, 70, 70, 70, 70, 70, 70, 68)
+};
+
+static struct resource mali_gpu_resources_m470_mp4[] = {
+ MALI_GPU_RESOURCES_MALI470_MP4_PMU(0xFC040000, -1, 70, 70, 70, 70, 70, 70, 70, 70, 70, 68)
+};
+#endif /* CONFIG_ARM64 */
+
+#elif defined(CONFIG_ARCH_REALVIEW)
+
+static struct resource mali_gpu_resources_m300[] = {
+ MALI_GPU_RESOURCES_MALI300_PMU(0xC0000000, -1, -1, -1, -1)
+};
+
+static struct resource mali_gpu_resources_m400_mp1[] = {
+ MALI_GPU_RESOURCES_MALI400_MP1_PMU(0xC0000000, -1, -1, -1, -1)
+};
+
+static struct resource mali_gpu_resources_m400_mp2[] = {
+ MALI_GPU_RESOURCES_MALI400_MP2_PMU(0xC0000000, -1, -1, -1, -1, -1, -1)
+};
+
+#endif
+#endif
+
+static struct mali_gpu_device_data mali_gpu_data = {
+#ifndef CONFIG_MALI_DT
+ .pmu_switch_delay = 0xFF, /* do not have to be this high on FPGA, but it is good for testing to have a delay */
+ .max_job_runtime = 60000, /* 60 seconds */
+#if defined(CONFIG_ARCH_VEXPRESS)
+ .shared_mem_size = 256 * 1024 * 1024, /* 256MB */
+#endif
+#endif
+
+#if defined(CONFIG_ARCH_REALVIEW)
+ .dedicated_mem_start = 0x80000000, /* Physical start address (use 0xD0000000 for old indirect setup) */
+ .dedicated_mem_size = 0x10000000, /* 256MB */
+#endif
+#if defined(CONFIG_ARM64)
+ /* Some framebuffer drivers get the framebuffer dynamically, such as through GEM,
+ * in which the memory resource can't be predicted in advance.
+ */
+ .fb_start = 0x0,
+ .fb_size = 0xFFFFF000,
+#else
+ .fb_start = 0xe0000000,
+ .fb_size = 0x01000000,
+#endif
+ .control_interval = 1000, /* 1000ms */
+ .utilization_callback = mali_gpu_utilization_callback,
+ .get_clock_info = NULL,
+ .get_freq = NULL,
+ .set_freq = NULL,
+};
+
+#ifndef CONFIG_MALI_DT
+static struct platform_device mali_gpu_device = {
+ .name = MALI_GPU_NAME_UTGARD,
+ .id = 0,
+ .dev.release = mali_platform_device_release,
+ .dev.dma_mask = &mali_gpu_device.dev.coherent_dma_mask,
+ .dev.coherent_dma_mask = DMA_BIT_MASK(32),
+
+ .dev.platform_data = &mali_gpu_data,
+};
+
+int mali_platform_device_register(void)
+{
+ int err = -1;
+ int num_pp_cores = 0;
+#if defined(CONFIG_ARCH_REALVIEW)
+ u32 m400_gp_version;
+#endif
+
+ MALI_DEBUG_PRINT(4, ("mali_platform_device_register() called\n"));
+
+ /* Detect present Mali GPU and connect the correct resources to the device */
+#if defined(CONFIG_ARCH_VEXPRESS)
+
+#if defined(CONFIG_ARM64)
+ mali_gpu_device.dev.archdata.dma_ops = dma_ops;
+ if ((mali_read_phys(0x6F000000) & 0x00600450) == 0x00600450) {
+ MALI_DEBUG_PRINT(4, ("Registering Mali-450 MP6 device\n"));
+ num_pp_cores = 6;
+ mali_gpu_device.num_resources = ARRAY_SIZE(mali_gpu_resources_m450_mp6);
+ mali_gpu_device.resource = mali_gpu_resources_m450_mp6;
+ } else if ((mali_read_phys(0x6F000000) & 0x00F00430) == 0x00400430) {
+ MALI_DEBUG_PRINT(4, ("Registering Mali-470 MP4 device\n"));
+ num_pp_cores = 4;
+ mali_gpu_device.num_resources = ARRAY_SIZE(mali_gpu_resources_m470_mp4);
+ mali_gpu_device.resource = mali_gpu_resources_m470_mp4;
+ } else if ((mali_read_phys(0x6F000000) & 0x00F00430) == 0x00300430) {
+ MALI_DEBUG_PRINT(4, ("Registering Mali-470 MP3 device\n"));
+ num_pp_cores = 3;
+ mali_gpu_device.num_resources = ARRAY_SIZE(mali_gpu_resources_m470_mp3);
+ mali_gpu_device.resource = mali_gpu_resources_m470_mp3;
+ } else if ((mali_read_phys(0x6F000000) & 0x00F00430) == 0x00200430) {
+ MALI_DEBUG_PRINT(4, ("Registering Mali-470 MP2 device\n"));
+ num_pp_cores = 2;
+ mali_gpu_device.num_resources = ARRAY_SIZE(mali_gpu_resources_m470_mp2);
+ mali_gpu_device.resource = mali_gpu_resources_m470_mp2;
+ } else if ((mali_read_phys(0x6F000000) & 0x00F00430) == 0x00100430) {
+ MALI_DEBUG_PRINT(4, ("Registering Mali-470 MP1 device\n"));
+ num_pp_cores = 1;
+ mali_gpu_device.num_resources = ARRAY_SIZE(mali_gpu_resources_m470_mp1);
+ mali_gpu_device.resource = mali_gpu_resources_m470_mp1;
+ }
+#else
+ if (mali_read_phys(0xFC000000) == 0x00000450) {
+ MALI_DEBUG_PRINT(4, ("Registering Mali-450 MP8 device\n"));
+ num_pp_cores = 8;
+ mali_gpu_device.num_resources = ARRAY_SIZE(mali_gpu_resources_m450_mp8);
+ mali_gpu_device.resource = mali_gpu_resources_m450_mp8;
+ } else if (mali_read_phys(0xFC000000) == 0x40600450) {
+ MALI_DEBUG_PRINT(4, ("Registering Mali-450 MP6 device\n"));
+ num_pp_cores = 6;
+ mali_gpu_device.num_resources = ARRAY_SIZE(mali_gpu_resources_m450_mp6);
+ mali_gpu_device.resource = mali_gpu_resources_m450_mp6;
+ } else if (mali_read_phys(0xFC000000) == 0x40400450) {
+ MALI_DEBUG_PRINT(4, ("Registering Mali-450 MP4 device\n"));
+ num_pp_cores = 4;
+ mali_gpu_device.num_resources = ARRAY_SIZE(mali_gpu_resources_m450_mp4);
+ mali_gpu_device.resource = mali_gpu_resources_m450_mp4;
+ } else if (mali_read_phys(0xFC000000) == 0xFFFFFFFF) {
+ MALI_DEBUG_PRINT(4, ("Registering Mali-470 MP4 device\n"));
+ num_pp_cores = 4;
+ mali_gpu_device.num_resources = ARRAY_SIZE(mali_gpu_resources_m470_mp4);
+ mali_gpu_device.resource = mali_gpu_resources_m470_mp4;
+ }
+#endif /* CONFIG_ARM64 */
+
+#elif defined(CONFIG_ARCH_REALVIEW)
+
+ m400_gp_version = mali_read_phys(0xC000006C);
+ if ((m400_gp_version & 0xFFFF0000) == 0x0C070000) {
+ MALI_DEBUG_PRINT(4, ("Registering Mali-300 device\n"));
+ num_pp_cores = 1;
+ mali_gpu_device.num_resources = ARRAY_SIZE(mali_gpu_resources_m300);
+ mali_gpu_device.resource = mali_gpu_resources_m300;
+ mali_write_phys(0xC0010020, 0xA); /* Enable direct memory mapping for FPGA */
+ } else if ((m400_gp_version & 0xFFFF0000) == 0x0B070000) {
+ u32 fpga_fw_version = mali_read_phys(0xC0010000);
+ if (fpga_fw_version == 0x130C008F || fpga_fw_version == 0x110C008F) {
+ /* Mali-400 MP1 r1p0 or r1p1 */
+ MALI_DEBUG_PRINT(4, ("Registering Mali-400 MP1 device\n"));
+ num_pp_cores = 1;
+ mali_gpu_device.num_resources = ARRAY_SIZE(mali_gpu_resources_m400_mp1);
+ mali_gpu_device.resource = mali_gpu_resources_m400_mp1;
+ mali_write_phys(0xC0010020, 0xA); /* Enable direct memory mapping for FPGA */
+ } else if (fpga_fw_version == 0x130C000F) {
+ /* Mali-400 MP2 r1p1 */
+ MALI_DEBUG_PRINT(4, ("Registering Mali-400 MP2 device\n"));
+ num_pp_cores = 2;
+ mali_gpu_device.num_resources = ARRAY_SIZE(mali_gpu_resources_m400_mp2);
+ mali_gpu_device.resource = mali_gpu_resources_m400_mp2;
+ mali_write_phys(0xC0010020, 0xA); /* Enable direct memory mapping for FPGA */
+ }
+ }
+
+#endif
+ /* Register the platform device */
+ err = platform_device_register(&mali_gpu_device);
+ if (0 == err) {
+#ifdef CONFIG_PM_RUNTIME
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
+ pm_runtime_set_autosuspend_delay(&(mali_gpu_device.dev), 1000);
+ pm_runtime_use_autosuspend(&(mali_gpu_device.dev));
+#endif
+ pm_runtime_enable(&(mali_gpu_device.dev));
+#endif
+ MALI_DEBUG_ASSERT(0 < num_pp_cores);
+ mali_core_scaling_init(num_pp_cores);
+
+ return 0;
+ }
+
+ return err;
+}
+
+void mali_platform_device_unregister(void)
+{
+ MALI_DEBUG_PRINT(4, ("mali_platform_device_unregister() called\n"));
+
+ mali_core_scaling_term();
+ platform_device_unregister(&mali_gpu_device);
+
+ platform_device_put(&mali_gpu_device);
+
+#if defined(CONFIG_ARCH_REALVIEW)
+ mali_write_phys(0xC0010020, 0x9); /* Restore default (legacy) memory mapping */
+#endif
+}
+
+static void mali_platform_device_release(struct device *device)
+{
+ MALI_DEBUG_PRINT(4, ("mali_platform_device_release() called\n"));
+}
+
+#else /* CONFIG_MALI_DT */
+int mali_platform_device_init(struct platform_device *device)
+{
+ int num_pp_cores = 0;
+ int err = -1;
+#if defined(CONFIG_ARCH_REALVIEW)
+ u32 m400_gp_version;
+#endif
+
+ /* Detect present Mali GPU and connect the correct resources to the device */
+#if defined(CONFIG_ARCH_VEXPRESS)
+
+#if defined(CONFIG_ARM64)
+ if ((mali_read_phys(0x6F000000) & 0x00600450) == 0x00600450) {
+ MALI_DEBUG_PRINT(4, ("Registering Mali-450 MP6 device\n"));
+ num_pp_cores = 6;
+ } else if ((mali_read_phys(0x6F000000) & 0x00F00430) == 0x00400430) {
+ MALI_DEBUG_PRINT(4, ("Registering Mali-470 MP4 device\n"));
+ num_pp_cores = 4;
+ } else if ((mali_read_phys(0x6F000000) & 0x00F00430) == 0x00300430) {
+ MALI_DEBUG_PRINT(4, ("Registering Mali-470 MP3 device\n"));
+ num_pp_cores = 3;
+ } else if ((mali_read_phys(0x6F000000) & 0x00F00430) == 0x00200430) {
+ MALI_DEBUG_PRINT(4, ("Registering Mali-470 MP2 device\n"));
+ num_pp_cores = 2;
+ } else if ((mali_read_phys(0x6F000000) & 0x00F00430) == 0x00100430) {
+ MALI_DEBUG_PRINT(4, ("Registering Mali-470 MP1 device\n"));
+ num_pp_cores = 1;
+ }
+#else
+ if (mali_read_phys(0xFC000000) == 0x00000450) {
+ MALI_DEBUG_PRINT(4, ("Registering Mali-450 MP8 device\n"));
+ num_pp_cores = 8;
+ } else if (mali_read_phys(0xFC000000) == 0x40400450) {
+ MALI_DEBUG_PRINT(4, ("Registering Mali-450 MP4 device\n"));
+ num_pp_cores = 4;
+ } else if (mali_read_phys(0xFC000000) == 0xFFFFFFFF) {
+ MALI_DEBUG_PRINT(4, ("Registering Mali-470 MP4 device\n"));
+ num_pp_cores = 4;
+ }
+#endif
+
+#elif defined(CONFIG_ARCH_REALVIEW)
+
+ m400_gp_version = mali_read_phys(0xC000006C);
+ if ((m400_gp_version & 0xFFFF0000) == 0x0C070000) {
+ MALI_DEBUG_PRINT(4, ("Registering Mali-300 device\n"));
+ num_pp_cores = 1;
+ mali_write_phys(0xC0010020, 0xA); /* Enable direct memory mapping for FPGA */
+ } else if ((m400_gp_version & 0xFFFF0000) == 0x0B070000) {
+ u32 fpga_fw_version = mali_read_phys(0xC0010000);
+ if (fpga_fw_version == 0x130C008F || fpga_fw_version == 0x110C008F) {
+ /* Mali-400 MP1 r1p0 or r1p1 */
+ MALI_DEBUG_PRINT(4, ("Registering Mali-400 MP1 device\n"));
+ num_pp_cores = 1;
+ mali_write_phys(0xC0010020, 0xA); /* Enable direct memory mapping for FPGA */
+ } else if (fpga_fw_version == 0x130C000F) {
+ /* Mali-400 MP2 r1p1 */
+ MALI_DEBUG_PRINT(4, ("Registering Mali-400 MP2 device\n"));
+ num_pp_cores = 2;
+ mali_write_phys(0xC0010020, 0xA); /* Enable direct memory mapping for FPGA */
+ }
+ }
+#endif
+
+ /* After kernel 3.15 device tree will default set dev
+ * related parameters in of_platform_device_create_pdata.
+ * But kernel changes from version to version,
+ * For example 3.10 didn't include device->dev.dma_mask parameter setting,
+ * if we didn't include here will cause dma_mapping error,
+ * but in kernel 3.15 it include device->dev.dma_mask parameter setting,
+ * so it's better to set must need paramter by DDK itself.
+ */
+ if (!device->dev.dma_mask)
+ device->dev.dma_mask = &device->dev.coherent_dma_mask;
+ device->dev.archdata.dma_ops = dma_ops;
+
+ err = platform_device_add_data(device, &mali_gpu_data, sizeof(mali_gpu_data));
+
+ if (0 == err) {
+#ifdef CONFIG_PM_RUNTIME
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
+ pm_runtime_set_autosuspend_delay(&(device->dev), 1000);
+ pm_runtime_use_autosuspend(&(device->dev));
+#endif
+ pm_runtime_enable(&(device->dev));
+#endif
+ MALI_DEBUG_ASSERT(0 < num_pp_cores);
+ mali_core_scaling_init(num_pp_cores);
+ }
+
+ return err;
+}
+
+int mali_platform_device_deinit(struct platform_device *device)
+{
+ MALI_IGNORE(device);
+
+ MALI_DEBUG_PRINT(4, ("mali_platform_device_deinit() called\n"));
+
+ mali_core_scaling_term();
+
+#if defined(CONFIG_ARCH_REALVIEW)
+ mali_write_phys(0xC0010020, 0x9); /* Restore default (legacy) memory mapping */
+#endif
+
+ return 0;
+}
+
+#endif /* CONFIG_MALI_DT */
+
+static u32 mali_read_phys(u32 phys_addr)
+{
+ u32 phys_addr_page = phys_addr & 0xFFFFE000;
+ u32 phys_offset = phys_addr & 0x00001FFF;
+ u32 map_size = phys_offset + sizeof(u32);
+ u32 ret = 0xDEADBEEF;
+ void *mem_mapped = ioremap_nocache(phys_addr_page, map_size);
+ if (NULL != mem_mapped) {
+ ret = (u32)ioread32(((u8 *)mem_mapped) + phys_offset);
+ iounmap(mem_mapped);
+ }
+
+ return ret;
+}
+
+#if defined(CONFIG_ARCH_REALVIEW)
+static void mali_write_phys(u32 phys_addr, u32 value)
+{
+ u32 phys_addr_page = phys_addr & 0xFFFFE000;
+ u32 phys_offset = phys_addr & 0x00001FFF;
+ u32 map_size = phys_offset + sizeof(u32);
+ void *mem_mapped = ioremap_nocache(phys_addr_page, map_size);
+ if (NULL != mem_mapped) {
+ iowrite32(value, ((u8 *)mem_mapped) + phys_offset);
+ iounmap(mem_mapped);
+ }
+}
+#endif
+
+static int param_set_core_scaling(const char *val, const struct kernel_param *kp)
+{
+ int ret = param_set_int(val, kp);
+
+ if (1 == mali_core_scaling_enable) {
+ mali_core_scaling_sync(mali_executor_get_num_cores_enabled());
+ }
+ return ret;
+}
+
+static struct kernel_param_ops param_ops_core_scaling = {
+ .set = param_set_core_scaling,
+ .get = param_get_int,
+};
+
+module_param_cb(mali_core_scaling_enable, &param_ops_core_scaling, &mali_core_scaling_enable, 0644);
+MODULE_PARM_DESC(mali_core_scaling_enable, "1 means to enable core scaling policy, 0 means to disable core scaling policy");
+
+void mali_gpu_utilization_callback(struct mali_gpu_utilization_data *data)
+{
+ if (1 == mali_core_scaling_enable) {
+ mali_core_scaling_update(data);
+ }
+}
diff --git a/drivers/gpu/arm/utgard/platform/arm/arm_core_scaling.c b/drivers/gpu/arm/utgard/platform/arm/arm_core_scaling.c
new file mode 100644
index 000000000000..2c24742eb4de
--- /dev/null
+++ b/drivers/gpu/arm/utgard/platform/arm/arm_core_scaling.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2013-2015 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * @file arm_core_scaling.c
+ * Example core scaling policy.
+ */
+
+#include "arm_core_scaling.h"
+
+#include <linux/mali/mali_utgard.h>
+#include "mali_kernel_common.h"
+
+#include <linux/workqueue.h>
+
+static int num_cores_total;
+static int num_cores_enabled;
+
+static struct work_struct wq_work;
+
+static void set_num_cores(struct work_struct *work)
+{
+ int err = mali_perf_set_num_pp_cores(num_cores_enabled);
+ MALI_DEBUG_ASSERT(0 == err);
+ MALI_IGNORE(err);
+}
+
+static void enable_one_core(void)
+{
+ if (num_cores_enabled < num_cores_total) {
+ ++num_cores_enabled;
+ schedule_work(&wq_work);
+ MALI_DEBUG_PRINT(3, ("Core scaling: Enabling one more core\n"));
+ }
+
+ MALI_DEBUG_ASSERT(1 <= num_cores_enabled);
+ MALI_DEBUG_ASSERT(num_cores_total >= num_cores_enabled);
+}
+
+static void disable_one_core(void)
+{
+ if (1 < num_cores_enabled) {
+ --num_cores_enabled;
+ schedule_work(&wq_work);
+ MALI_DEBUG_PRINT(3, ("Core scaling: Disabling one core\n"));
+ }
+
+ MALI_DEBUG_ASSERT(1 <= num_cores_enabled);
+ MALI_DEBUG_ASSERT(num_cores_total >= num_cores_enabled);
+}
+
+static void enable_max_num_cores(void)
+{
+ if (num_cores_enabled < num_cores_total) {
+ num_cores_enabled = num_cores_total;
+ schedule_work(&wq_work);
+ MALI_DEBUG_PRINT(3, ("Core scaling: Enabling maximum number of cores\n"));
+ }
+
+ MALI_DEBUG_ASSERT(num_cores_total == num_cores_enabled);
+}
+
+void mali_core_scaling_init(int num_pp_cores)
+{
+ INIT_WORK(&wq_work, set_num_cores);
+
+ num_cores_total = num_pp_cores;
+ num_cores_enabled = num_pp_cores;
+
+ /* NOTE: Mali is not fully initialized at this point. */
+}
+
+void mali_core_scaling_sync(int num_cores)
+{
+ num_cores_enabled = num_cores;
+}
+
+void mali_core_scaling_term(void)
+{
+ flush_scheduled_work();
+}
+
+#define PERCENT_OF(percent, max) ((int) ((percent)*(max)/100.0 + 0.5))
+
+void mali_core_scaling_update(struct mali_gpu_utilization_data *data)
+{
+ /*
+ * This function implements a very trivial PP core scaling algorithm.
+ *
+ * It is _NOT_ of production quality.
+ * The only intention behind this algorithm is to exercise and test the
+ * core scaling functionality of the driver.
+ * It is _NOT_ tuned for neither power saving nor performance!
+ *
+ * Other metrics than PP utilization need to be considered as well
+ * in order to make a good core scaling algorithm.
+ */
+
+ MALI_DEBUG_PRINT(3, ("Utilization: (%3d, %3d, %3d), cores enabled: %d/%d\n", data->utilization_gpu, data->utilization_gp, data->utilization_pp, num_cores_enabled, num_cores_total));
+
+ /* NOTE: this function is normally called directly from the utilization callback which is in
+ * timer context. */
+
+ if (PERCENT_OF(90, 256) < data->utilization_pp) {
+ enable_max_num_cores();
+ } else if (PERCENT_OF(50, 256) < data->utilization_pp) {
+ enable_one_core();
+ } else if (PERCENT_OF(40, 256) < data->utilization_pp) {
+ /* do nothing */
+ } else if (PERCENT_OF(0, 256) < data->utilization_pp) {
+ disable_one_core();
+ } else {
+ /* do nothing */
+ }
+}
diff --git a/drivers/gpu/arm/utgard/platform/arm/arm_core_scaling.h b/drivers/gpu/arm/utgard/platform/arm/arm_core_scaling.h
new file mode 100644
index 000000000000..325b5b1c6894
--- /dev/null
+++ b/drivers/gpu/arm/utgard/platform/arm/arm_core_scaling.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2013, 2015 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * @file arm_core_scaling.h
+ * Example core scaling policy.
+ */
+
+#ifndef __ARM_CORE_SCALING_H__
+#define __ARM_CORE_SCALING_H__
+
+struct mali_gpu_utilization_data;
+
+/**
+ * Initialize core scaling policy.
+ *
+ * @note The core scaling policy will assume that all PP cores are on initially.
+ *
+ * @param num_pp_cores Total number of PP cores.
+ */
+void mali_core_scaling_init(int num_pp_cores);
+
+/**
+ * Terminate core scaling policy.
+ */
+void mali_core_scaling_term(void);
+
+/**
+ * Update core scaling policy with new utilization data.
+ *
+ * @param data Utilization data.
+ */
+void mali_core_scaling_update(struct mali_gpu_utilization_data *data);
+
+void mali_core_scaling_sync(int num_cores);
+
+#endif /* __ARM_CORE_SCALING_H__ */
diff --git a/drivers/gpu/arm/utgard/platform/hikey/mali_hikey.c b/drivers/gpu/arm/utgard/platform/hikey/mali_hikey.c
new file mode 100644
index 000000000000..cc556b2656fe
--- /dev/null
+++ b/drivers/gpu/arm/utgard/platform/hikey/mali_hikey.c
@@ -0,0 +1,683 @@
+/*
+ * Copyright (C) 2014 Hisilicon Co. Ltd.
+ * Copyright (C) 2015 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+/**
+ * @file mali_hikey.c
+ * HiKey platform specific Mali driver functions.
+ */
+
+/* Set to 1 to enable ION (not tested yet). */
+#define HISI6220_USE_ION 0
+
+#define pr_fmt(fmt) "Mali: HiKey: " fmt
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+#include <linux/pm.h>
+#include <linux/mm.h>
+#include <linux/of.h>
+
+#ifdef CONFIG_PM_RUNTIME
+#include <linux/pm_runtime.h>
+#endif
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/dma-mapping.h>
+#if HISI6220_USE_ION
+#include <linux/hisi/hisi_ion.h>
+#endif
+#include <linux/byteorder/generic.h>
+
+#include <linux/mali/mali_utgard.h>
+
+#include "mali_kernel_common.h"
+#include "mali_osk.h"
+#include "mali_hikey_hi6220_registers_gpu.h"
+
+#define MALI_GPU_MHZ 1000000
+#define MALI_IRQ_ID 142
+#define MALI_FRAME_BUFFER_ADDR 0x3F100000
+#define MALI_FRAME_BUFFER_SIZE 0x00708000
+
+#define MALI_CALC_REG_MASK(bit_start, bit_end) \
+ (((0x1 << (bit_end - bit_start + 1)) - 1) << bit_start)
+
+enum mali_core_type {
+ MALI_CORE_400_MP1 = 0,
+ MALI_CORE_400_MP2 = 1,
+ MALI_CORE_450_MP4 = 2,
+ MALI_CORE_TYPE_MAX
+};
+
+enum mali_power_mode {
+ MALI_POWER_MODE_ON, /**< Power on */
+ MALI_POWER_MODE_LIGHT_SLEEP, /**< Idle for a short or PM suspend */
+ MALI_POWER_MODE_DEEP_SLEEP, /**< Idle for a long or OS suspend */
+};
+
+struct mali_soc_remap_addr_table {
+ u8 *soc_media_sctrl_base_addr;
+ u8 *soc_ao_sctrl_base_addr;
+ u8 *soc_peri_sctrl_base_addr;
+ u8 *soc_pmctl_base_addr;
+};
+
+static struct clk *mali_clk_g3d;
+static struct clk *mali_pclk_g3d;
+static struct regulator *mali_regulator;
+static struct device_node *mali_np;
+static bool mali_gpu_power_status;
+
+static struct resource mali_gpu_resources_m450_mp4[] = {
+ MALI_GPU_RESOURCES_MALI450_MP4(
+ SOC_G3D_S_BASE_ADDR, MALI_IRQ_ID, MALI_IRQ_ID, MALI_IRQ_ID,
+ MALI_IRQ_ID, MALI_IRQ_ID, MALI_IRQ_ID, MALI_IRQ_ID,
+ MALI_IRQ_ID, MALI_IRQ_ID, MALI_IRQ_ID, MALI_IRQ_ID)
+};
+
+static struct mali_soc_remap_addr_table *mali_soc_addr_table;
+
+static void mali_reg_writel(u8 *base_addr, unsigned int reg_offset,
+ unsigned char start_bit, unsigned char end_bit,
+ unsigned int val)
+{
+ int read_val;
+ unsigned long flags;
+ static DEFINE_SPINLOCK(reg_lock);
+ void __iomem *addr;
+
+ WARN_ON(!base_addr);
+
+ addr = base_addr + reg_offset;
+ spin_lock_irqsave(&reg_lock, flags);
+ read_val = readl(addr) & ~(MALI_CALC_REG_MASK(start_bit, end_bit));
+ read_val |= (MALI_CALC_REG_MASK(start_bit, end_bit)
+ & (val << start_bit));
+ writel(read_val, addr);
+ spin_unlock_irqrestore(&reg_lock, flags);
+}
+
+static unsigned int mali_reg_readl(u8 *base_addr, unsigned int reg_offset,
+ unsigned char start_bit,
+ unsigned char end_bit)
+{
+ unsigned int val;
+
+ WARN_ON(!base_addr);
+
+ val = readl((void __iomem *)(base_addr + reg_offset));
+ val &= MALI_CALC_REG_MASK(start_bit, end_bit);
+
+ return val >> start_bit;
+}
+
+static int mali_clock_on(void)
+{
+ u32 core_freq = 0;
+ u32 pclk_freq = 0;
+ int stat;
+
+ stat = clk_prepare_enable(mali_pclk_g3d);
+ if (stat)
+ return stat;
+
+ stat = of_property_read_u32(mali_np, "pclk_freq", &pclk_freq);
+ if (stat)
+ return stat;
+
+ stat = clk_set_rate(mali_pclk_g3d, pclk_freq * MALI_GPU_MHZ);
+ if (stat)
+ return stat;
+
+ stat = of_property_read_u32(mali_np, "mali_def_freq", &core_freq);
+ if (stat)
+ return stat;
+
+ stat = clk_set_rate(mali_clk_g3d, core_freq * MALI_GPU_MHZ);
+ if (stat)
+ return stat;
+
+ stat = clk_prepare_enable(mali_clk_g3d);
+ if (stat)
+ return stat;
+
+ mali_reg_writel(mali_soc_addr_table->soc_media_sctrl_base_addr,
+ SOC_MEDIA_SCTRL_SC_MEDIA_CLKDIS_ADDR(0), 17, 17, 1);
+
+ return 0;
+}
+
+static void mali_clock_off(void)
+{
+ clk_disable_unprepare(mali_clk_g3d);
+ clk_disable_unprepare(mali_pclk_g3d);
+}
+
+static int mali_domain_powerup_finish(void)
+{
+ unsigned int ret;
+
+ mali_reg_writel(mali_soc_addr_table->soc_ao_sctrl_base_addr,
+ SOC_AO_SCTRL_SC_PW_RSTDIS0_ADDR(0), 1, 1, 1);
+ ret = mali_reg_readl(mali_soc_addr_table->soc_ao_sctrl_base_addr,
+ SOC_AO_SCTRL_SC_PW_RST_STAT0_ADDR(0), 1, 1);
+ if (ret != 0) {
+ pr_err("SET SC_PW_RSTDIS0 failed!\n");
+ return -EFAULT;
+ }
+
+ mali_reg_writel(mali_soc_addr_table->soc_ao_sctrl_base_addr,
+ SOC_AO_SCTRL_SC_PW_ISODIS0_ADDR(0), 1, 1, 1);
+ ret = mali_reg_readl(mali_soc_addr_table->soc_ao_sctrl_base_addr,
+ SOC_AO_SCTRL_SC_PW_ISO_STAT0_ADDR(0), 1, 1);
+ if (ret != 0) {
+ pr_err("SET SC_PW_ISODIS0 failed!\n");
+ return -EFAULT;
+ }
+
+ mali_reg_writel(mali_soc_addr_table->soc_ao_sctrl_base_addr,
+ SOC_AO_SCTRL_SC_PW_CLKEN0_ADDR(0), 1, 1, 1);
+ ret = mali_reg_readl(mali_soc_addr_table->soc_ao_sctrl_base_addr,
+ SOC_AO_SCTRL_SC_PW_CLK_STAT0_ADDR(0), 1, 1);
+ if (ret != 1) {
+ pr_err("SET SC_PW_CLKEN0 failed!\n");
+ return -EFAULT;
+ }
+
+ mali_reg_writel(mali_soc_addr_table->soc_media_sctrl_base_addr,
+ SOC_MEDIA_SCTRL_SC_MEDIA_RSTDIS_ADDR(0), 0, 0, 1);
+ ret = mali_reg_readl(mali_soc_addr_table->soc_media_sctrl_base_addr,
+ SOC_MEDIA_SCTRL_SC_MEDIA_RST_STAT_ADDR(0), 0, 0);
+ if (ret != 0) {
+ pr_err("SET SC_MEDIA_RSTDIS failed!\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int mali_regulator_enable(void)
+{
+ int i, stat;
+
+ stat = regulator_enable(mali_regulator);
+ if (stat)
+ return stat;
+
+ for (i = 0; i < 50; i++) {
+ stat = regulator_is_enabled(mali_regulator);
+ if (stat > 0)
+ break;
+ udelay(1);
+ }
+
+ if (50 == i) {
+ pr_err("regulator enable timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int mali_platform_powerup(void)
+{
+ int stat;
+
+ if (mali_gpu_power_status)
+ return 0;
+
+ stat = mali_regulator_enable();
+ if (stat)
+ return stat;
+
+ stat = mali_clock_on();
+ if (stat)
+ return stat;
+
+ stat = mali_domain_powerup_finish();
+ if (stat)
+ return stat;
+
+ mali_gpu_power_status = true;
+
+ return 0;
+}
+
+static int mali_regulator_disable(void)
+{
+ mali_reg_writel(mali_soc_addr_table->soc_media_sctrl_base_addr,
+ SOC_MEDIA_SCTRL_SC_MEDIA_RSTEN_ADDR(0), 0, 0, 1);
+ mali_reg_writel(mali_soc_addr_table->soc_ao_sctrl_base_addr,
+ SOC_AO_SCTRL_SC_PW_CLKDIS0_ADDR(0), 1, 1, 1);
+ mali_reg_writel(mali_soc_addr_table->soc_ao_sctrl_base_addr,
+ SOC_AO_SCTRL_SC_PW_ISOEN0_ADDR(0), 1, 1, 1);
+ mali_reg_writel(mali_soc_addr_table->soc_ao_sctrl_base_addr,
+ SOC_AO_SCTRL_SC_PW_RSTEN0_ADDR(0), 1, 1, 1);
+
+ return regulator_disable(mali_regulator);
+}
+
+static int mali_platform_powerdown(void)
+{
+ int stat;
+
+ if (!mali_gpu_power_status)
+ return 0;
+
+ stat = mali_regulator_disable();
+ if (stat)
+ return stat;
+
+ mali_clock_off();
+ mali_gpu_power_status = false;
+
+ return 0;
+}
+
+static int mali_platform_power_mode_change(enum mali_power_mode power_mode)
+{
+ int stat;
+
+ switch (power_mode) {
+ case MALI_POWER_MODE_ON:
+ stat = mali_platform_powerup();
+ break;
+ case MALI_POWER_MODE_LIGHT_SLEEP:
+ case MALI_POWER_MODE_DEEP_SLEEP:
+ stat = mali_platform_powerdown();
+ break;
+ default:
+ pr_err("Invalid power mode\n");
+ stat = -EINVAL;
+ break;
+ }
+
+ return stat;
+}
+
+static int mali_os_suspend(struct device *device)
+{
+ int stat;
+
+ if (device->driver &&
+ device->driver->pm &&
+ device->driver->pm->suspend) {
+ stat = device->driver->pm->suspend(device);
+ } else {
+ stat = 0;
+ }
+
+ if (stat)
+ return stat;
+
+ return mali_platform_power_mode_change(MALI_POWER_MODE_DEEP_SLEEP);
+}
+
+static int mali_os_resume(struct device *device)
+{
+ int stat;
+
+ stat = mali_platform_power_mode_change(MALI_POWER_MODE_ON);
+ if (stat)
+ return stat;
+
+ if (device->driver &&
+ device->driver->pm &&
+ device->driver->pm->resume) {
+ stat = device->driver->pm->resume(device);
+ }
+
+ return stat;
+}
+
+static int mali_os_freeze(struct device *device)
+{
+ int stat;
+
+ if (device->driver &&
+ device->driver->pm &&
+ device->driver->pm->freeze) {
+ stat = device->driver->pm->freeze(device);
+ } else {
+ stat = 0;
+ }
+
+ return stat;
+}
+
+static int mali_os_thaw(struct device *device)
+{
+ int stat;
+
+ if (device->driver &&
+ device->driver->pm &&
+ device->driver->pm->thaw) {
+ stat = device->driver->pm->thaw(device);
+ } else {
+ stat = 0;
+ }
+
+ return stat;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int mali_runtime_suspend(struct device *device)
+{
+ int stat;
+
+ if (device->driver &&
+ device->driver->pm &&
+ device->driver->pm->runtime_suspend) {
+ stat = device->driver->pm->runtime_suspend(device);
+ } else {
+ stat = 0;
+ }
+
+ if (stat)
+ return stat;
+
+ return mali_platform_power_mode_change(MALI_POWER_MODE_LIGHT_SLEEP);
+}
+
+static int mali_runtime_resume(struct device *device)
+{
+ int stat;
+
+ stat = mali_platform_power_mode_change(MALI_POWER_MODE_ON);
+ if (stat)
+ return stat;
+
+ if (device->driver &&
+ device->driver->pm &&
+ device->driver->pm->runtime_resume) {
+ stat = device->driver->pm->runtime_resume(device);
+ }
+
+ return stat;
+}
+
+static int mali_runtime_idle(struct device *device)
+{
+ int stat;
+
+ if (device->driver &&
+ device->driver->pm &&
+ device->driver->pm->runtime_idle) {
+ stat = device->driver->pm->runtime_idle(device);
+ } else {
+ stat = 0;
+ }
+
+ if (stat)
+ return stat;
+
+ return pm_runtime_suspend(device);
+}
+#endif
+
+static int init_mali_clock_regulator(struct platform_device *pdev)
+{
+ int stat, ret;
+
+ BUG_ON(mali_regulator || mali_clk_g3d || mali_pclk_g3d);
+
+ /* regulator init */
+
+ mali_regulator = regulator_get(&pdev->dev, "G3D_PD_VDD");
+ if (IS_ERR(mali_regulator)) {
+ pr_err("failed to get G3D_PD_VDD\n");
+ return -ENODEV;
+ }
+
+ stat = mali_regulator_enable();
+ if (stat)
+ return stat;
+
+ mali_gpu_power_status = true;
+
+ /* clk init */
+
+ mali_clk_g3d = clk_get(&pdev->dev, "clk_g3d");
+ if (IS_ERR(mali_clk_g3d)) {
+ pr_err("failed to get source CLK_G3D\n");
+ return -ENODEV;
+ }
+
+ mali_pclk_g3d = clk_get(&pdev->dev, "pclk_g3d");
+ if (IS_ERR(mali_pclk_g3d)) {
+ pr_err("failed to get source PCLK_G3D\n");
+ return -ENODEV;
+ }
+
+ ret = mali_reg_readl(mali_soc_addr_table->soc_peri_sctrl_base_addr,
+ SOC_PERI_SCTRL_SC_PERIPH_CLKSTAT12_ADDR(0),
+ 10, 10);
+ if (ret != 1) {
+ mali_reg_writel(mali_soc_addr_table->soc_peri_sctrl_base_addr,
+ SOC_PERI_SCTRL_SC_PERIPH_CLKEN12_ADDR(0),
+ 10, 10, 1);
+ ret = mali_reg_readl(
+ mali_soc_addr_table->soc_peri_sctrl_base_addr,
+ SOC_PERI_SCTRL_SC_PERIPH_CLKSTAT12_ADDR(0), 10, 10);
+ if (ret != 1) {
+ pr_err("SET SC_PERIPH_CLKEN12 failed!\n");
+ return -EFAULT;
+ }
+ }
+
+ stat = mali_clock_on();
+ if (stat)
+ return stat;
+
+ mali_reg_writel(mali_soc_addr_table->soc_media_sctrl_base_addr,
+ SOC_MEDIA_SCTRL_SC_MEDIA_CLKCFG2_ADDR(0), 15, 15, 1);
+ ret = mali_reg_readl(mali_soc_addr_table->soc_media_sctrl_base_addr,
+ SOC_MEDIA_SCTRL_SC_MEDIA_CLKCFG2_ADDR(0), 15, 15);
+ if (ret != 1) {
+ pr_err("SET SC_MEDIA_CLKCFG2 failed!\n");
+ return -EFAULT;
+ }
+
+ return mali_domain_powerup_finish();
+}
+
+static int deinit_mali_clock_regulator(void)
+{
+ int stat;
+
+ BUG_ON(!mali_regulator || !mali_clk_g3d || !mali_pclk_g3d);
+
+ stat = mali_platform_powerdown();
+ if (stat)
+ return stat;
+
+ clk_put(mali_clk_g3d);
+ mali_clk_g3d = NULL;
+ clk_put(mali_pclk_g3d);
+ mali_pclk_g3d = NULL;
+ regulator_put(mali_regulator);
+ mali_regulator = NULL;
+
+ return 0;
+}
+
+static struct mali_gpu_device_data mali_gpu_data = {
+ .shared_mem_size = 1024 * 1024 * 1024, /* 1024MB */
+ .fb_start = MALI_FRAME_BUFFER_ADDR,
+ .fb_size = MALI_FRAME_BUFFER_SIZE,
+ .max_job_runtime = 2000, /* 2 seconds time out */
+ .control_interval = 50, /* 50ms */
+#ifdef CONFIG_MALI_DVFS
+ .utilization_callback = mali_gpu_utilization_proc,
+#endif
+};
+
+static const struct dev_pm_ops mali_gpu_device_type_pm_ops = {
+ .suspend = mali_os_suspend,
+ .resume = mali_os_resume,
+ .freeze = mali_os_freeze,
+ .thaw = mali_os_thaw,
+#ifdef CONFIG_PM_RUNTIME
+ .runtime_suspend = mali_runtime_suspend,
+ .runtime_resume = mali_runtime_resume,
+ .runtime_idle = mali_runtime_idle,
+#endif
+};
+
+static struct device_type mali_gpu_device_device_type = {
+ .pm = &mali_gpu_device_type_pm_ops,
+};
+
+static enum mali_core_type mali_get_gpu_type(void)
+{
+ u32 gpu_type = MALI_CORE_TYPE_MAX;
+ int err = of_property_read_u32(mali_np, "mali_type", &gpu_type);
+
+ if (err) {
+ pr_err("failed to read mali_type from device tree\n");
+ return -EFAULT;
+ }
+
+ return gpu_type;
+}
+
+#if HISI6220_USE_ION
+static int mali_ion_mem_init(void)
+{
+ struct ion_heap_info_data mem_data;
+
+ if (hisi_ion_get_heap_info(ION_FB_HEAP_ID, &mem_data)) {
+ pr_err("Failed to get ION_FB_HEAP_ID\n");
+ return -EFAULT;
+ }
+
+ if (mem_data.heap_size == 0) {
+ pr_err("fb size is 0\n");
+ return -EINVAL;
+ }
+
+ mali_gpu_data.fb_size = mem_data.heap_size;
+ mali_gpu_data.fb_start = (unsigned long)(mem_data.heap_phy);
+ pr_debug("fb_size=0x%x, fb_start=0x%x\n",
+ mali_gpu_data.fb_size, mali_gpu_data.fb_start);
+
+ return 0;
+}
+#endif
+
+static int mali_remap_soc_addr(void)
+{
+ BUG_ON(mali_soc_addr_table);
+
+ mali_soc_addr_table = kmalloc(sizeof(struct mali_soc_remap_addr_table),
+ GFP_KERNEL);
+ if (!mali_soc_addr_table)
+ return -ENOMEM;
+
+ mali_soc_addr_table->soc_media_sctrl_base_addr =
+ ioremap(SOC_MEDIA_SCTRL_BASE_ADDR, REG_MEDIA_SC_IOSIZE);
+ mali_soc_addr_table->soc_ao_sctrl_base_addr =
+ ioremap(SOC_AO_SCTRL_BASE_ADDR, REG_SC_ON_IOSIZE);
+ mali_soc_addr_table->soc_peri_sctrl_base_addr =
+ ioremap(SOC_PERI_SCTRL_BASE_ADDR, REG_SC_OFF_IOSIZE);
+ mali_soc_addr_table->soc_pmctl_base_addr =
+ ioremap(SOC_PMCTRL_BASE_ADDR, REG_PMCTRL_IOSIZE);
+
+ if (!mali_soc_addr_table->soc_media_sctrl_base_addr
+ || !mali_soc_addr_table->soc_ao_sctrl_base_addr
+ || !mali_soc_addr_table->soc_peri_sctrl_base_addr
+ || !mali_soc_addr_table->soc_pmctl_base_addr) {
+ pr_err("Failed to remap SoC addresses\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void mali_unmap_soc_addr(void)
+{
+ iounmap((void __iomem *)mali_soc_addr_table->soc_media_sctrl_base_addr);
+ iounmap((void __iomem *)mali_soc_addr_table->soc_ao_sctrl_base_addr);
+ iounmap((void __iomem *)mali_soc_addr_table->soc_peri_sctrl_base_addr);
+ iounmap((void __iomem *)mali_soc_addr_table->soc_pmctl_base_addr);
+ kfree(mali_soc_addr_table);
+ mali_soc_addr_table = NULL;
+}
+
+int mali_platform_device_init(struct platform_device *pdev)
+{
+ int stat;
+ int irq, i;
+
+#if HISI6220_USE_ION
+ stat = mali_ion_mem_init();
+ if (stat)
+ return stat;
+#endif
+
+ stat = mali_remap_soc_addr();
+ if (stat)
+ return stat;
+
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+ pdev->dev.type = &mali_gpu_device_device_type;
+ pdev->dev.platform_data = &mali_gpu_data;
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+ mali_np = pdev->dev.of_node;
+
+ if (mali_get_gpu_type() != MALI_CORE_450_MP4) {
+ pr_err("Unexpected GPU type\n");
+ return -EINVAL;
+ }
+
+ /*
+ * We need to use DT to get the irq domain, so rewrite the static
+ * table with the irq given from platform_get_irq().
+ */
+ irq = platform_get_irq(pdev, 0);
+ for (i = 0; i < ARRAY_SIZE(mali_gpu_resources_m450_mp4); i++) {
+ if (IORESOURCE_IRQ & mali_gpu_resources_m450_mp4[i].flags) {
+ mali_gpu_resources_m450_mp4[i].start = irq;
+ mali_gpu_resources_m450_mp4[i].end = irq;
+ }
+ }
+ pdev->num_resources = ARRAY_SIZE(mali_gpu_resources_m450_mp4);
+ pdev->resource = mali_gpu_resources_m450_mp4;
+
+ stat = init_mali_clock_regulator(pdev);
+ if (stat)
+ return stat;
+
+#ifdef CONFIG_PM_RUNTIME
+ pm_runtime_set_autosuspend_delay(&(pdev->dev), 1);
+ pm_runtime_use_autosuspend(&(pdev->dev));
+ pm_runtime_enable(&pdev->dev);
+#endif
+
+ return 0;
+}
+
+int mali_platform_device_deinit(void)
+{
+ int stat;
+
+ stat = deinit_mali_clock_regulator();
+ if (stat)
+ return stat;
+
+ mali_unmap_soc_addr();
+
+ return 0;
+}
diff --git a/drivers/gpu/arm/utgard/platform/hikey/mali_hikey_hi6220_registers_gpu.h b/drivers/gpu/arm/utgard/platform/hikey/mali_hikey_hi6220_registers_gpu.h
new file mode 100644
index 000000000000..0bdf4a0482fd
--- /dev/null
+++ b/drivers/gpu/arm/utgard/platform/hikey/mali_hikey_hi6220_registers_gpu.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 Hisilicon Co. Ltd.
+ * Copyright (C) 2015 ARM Ltd.
+ *
+ * Author: Xuzixin <Xuzixin@hisilicon.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef MALI_HIKEY_HI6220_REGISTERS_GPU_H
+#define MALI_HIKEY_HI6220_REGISTERS_GPU_H 1
+
+#include <linux/mm.h>
+
+#define SOC_G3D_S_BASE_ADDR 0xF4080000 /* G3D ctrl base addr */
+#define SOC_MEDIA_SCTRL_BASE_ADDR 0xF4410000 /* media ctrl base addr */
+#define REG_MEDIA_SC_IOSIZE PAGE_ALIGN(SZ_4K)
+#define SOC_PMCTRL_BASE_ADDR 0xF7032000 /* pm ctrl base addr */
+#define REG_PMCTRL_IOSIZE PAGE_ALIGN(SZ_4K)
+#define SOC_AO_SCTRL_BASE_ADDR 0xF7800000 /* ao ctrl base addr */
+#define SOC_PERI_SCTRL_BASE_ADDR 0xF7030000 /* peri ctrl base addr */
+#define REG_SC_ON_IOSIZE PAGE_ALIGN(SZ_8K)
+#define REG_SC_OFF_IOSIZE PAGE_ALIGN(SZ_4K)
+
+/* ----------------------------------------------------------------------------
+ * MEDIA SCTRL
+ */
+
+#define SOC_MEDIA_SCTRL_SC_MEDIA_SUBSYS_CTRL5_ADDR(base) ((base) + (0x51C))
+#define SOC_MEDIA_SCTRL_SC_MEDIA_CLKCFG0_ADDR(base) ((base) + (0xCBC))
+#define SOC_MEDIA_SCTRL_SC_MEDIA_CLKCFG2_ADDR(base) ((base) + (0xCC4))
+#define SOC_MEDIA_SCTRL_SC_MEDIA_CLKEN_ADDR(base) ((base) + (0x520))
+#define SOC_MEDIA_SCTRL_SC_MEDIA_CLKDIS_ADDR(base) ((base) + (0x524))
+#define SOC_MEDIA_SCTRL_SC_MEDIA_RSTEN_ADDR(base) ((base) + (0x52C))
+#define SOC_MEDIA_SCTRL_SC_MEDIA_RSTDIS_ADDR(base) ((base) + (0x530))
+#define SOC_MEDIA_SCTRL_SC_MEDIA_RST_STAT_ADDR(base) ((base) + (0x534))
+
+/* ----------------------------------------------------------------------------
+ * AO SCTRL,only bit 1 is necessary for GPU.
+ */
+
+#define SOC_AO_SCTRL_SC_PW_CLKEN0_ADDR(base) ((base) + (0x800))
+#define SOC_AO_SCTRL_SC_PW_CLKDIS0_ADDR(base) ((base) + (0x804))
+#define SOC_AO_SCTRL_SC_PW_CLK_STAT0_ADDR(base) ((base) + (0x808))
+#define SOC_AO_SCTRL_SC_PW_RSTEN0_ADDR(base) ((base) + (0x810))
+#define SOC_AO_SCTRL_SC_PW_RSTDIS0_ADDR(base) ((base) + (0x814))
+#define SOC_AO_SCTRL_SC_PW_RST_STAT0_ADDR(base) ((base) + (0x818))
+#define SOC_AO_SCTRL_SC_PW_ISOEN0_ADDR(base) ((base) + (0x820))
+#define SOC_AO_SCTRL_SC_PW_ISODIS0_ADDR(base) ((base) + (0x824))
+#define SOC_AO_SCTRL_SC_PW_ISO_STAT0_ADDR(base) ((base) + (0x828))
+#define SOC_AO_SCTRL_SC_PW_MTCMOS_EN0_ADDR(base) ((base) + (0x830))
+#define SOC_AO_SCTRL_SC_PW_MTCMOS_DIS0_ADDR(base) ((base) + (0x834))
+#define SOC_AO_SCTRL_SC_PW_MTCMOS_STAT0_ADDR(base) ((base) + (0x838))
+
+/* ----------------------------------------------------------------------------
+ * PERI SCTRL,only bit 10 is necessary for GPU.
+ */
+
+#define SOC_PERI_SCTRL_SC_PERIPH_CLKEN12_ADDR(base) ((base) + (0x270))
+#define SOC_PERI_SCTRL_SC_PERIPH_CLKSTAT12_ADDR(base) ((base) + (0x278))
+
+#endif /* MALI_HIKEY_HI6220_REGISTERS_GPU_H */