ARM: mali400: r5p2_rel0: add exynos platform codes
authorJoonyoung Shim <jy0922.shim@samsung.com>
Mon, 23 May 2016 06:09:33 +0000 (15:09 +0900)
committerJoonyoung Shim <jy0922.shim@samsung.com>
Thu, 7 Jul 2016 06:39:56 +0000 (15:39 +0900)
This comes from r4p0_rel0.

Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
drivers/gpu/arm/mali400/r5p2_rel0/Kbuild
drivers/gpu/arm/mali400/r5p2_rel0/platform/exynos/exynos.c [new file with mode: 0644]
drivers/gpu/arm/mali400/r5p2_rel0/platform/exynos/exynos.h [new file with mode: 0644]

index ab2a41ebda8a9c681e91d8c8143f2f3b7b69f80d..4af73700354c41c58a1fe3b65888fd1d6ed632de 100644 (file)
@@ -21,6 +21,8 @@ MALI_PP_SCHEDULER_KEEP_SUB_JOB_STARTS_ALIGNED ?= 0
 MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP_BETWEEN_APPS ?= 0
 MALI_UPPER_HALF_SCHEDULING ?= 1
 MALI_ENABLE_CPU_CYCLES ?= 0
+MALI_PLATFORM ?= exynos
+MALI_FAKE_PLATFORM_DEVICE ?= 1
 
 # For customer releases the Linux Device Drivers will be provided as ARM proprietary and GPL releases:
 # The ARM proprietary product will only include the license/proprietary directory
@@ -118,6 +120,7 @@ mali-y += \
        linux/mali_pmu_power_up_down.o \
        __malidrv_build_info.o
 
+MALI_PLATFORM_FILES = $(subst $(src)/,,$(wildcard $(src)/platform/$(MALI_PLATFORM)/*.c))
 ifneq ($(MALI_PLATFORM_FILES),)
        mali-y += $(MALI_PLATFORM_FILES:.c=.o)
 endif
@@ -142,8 +145,6 @@ obj-$(CONFIG_MALI400) := mali.o
 ccflags-y += $(EXTRA_DEFINES)
 
 # Set up our defines, which will be passed to gcc
-ccflags-y += -DSPRD_GPU_BOOST
-
 ccflags-y += -DMALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP=$(MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP)
 ccflags-y += -DMALI_PP_SCHEDULER_KEEP_SUB_JOB_STARTS_ALIGNED=$(MALI_PP_SCHEDULER_KEEP_SUB_JOB_STARTS_ALIGNED)
 ccflags-y += -DMALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP_BETWEEN_APPS=$(MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP_BETWEEN_APPS)
@@ -151,6 +152,7 @@ ccflags-y += -DMALI_STATE_TRACKING=1
 ccflags-y += -DMALI_OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB=$(OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB)
 ccflags-y += -DUSING_GPU_UTILIZATION=$(USING_GPU_UTILIZATION)
 ccflags-y += -DMALI_ENABLE_CPU_CYCLES=$(MALI_ENABLE_CPU_CYCLES)
+ccflags-y += -DMALI_FAKE_PLATFORM_DEVICE=$(MALI_FAKE_PLATFORM_DEVICE)
 
 ifeq ($(MALI_UPPER_HALF_SCHEDULING),1)
        ccflags-y += -DMALI_UPPER_HALF_SCHEDULING
@@ -207,7 +209,7 @@ VERSION_STRINGS += BUILD=debug
 else
 VERSION_STRINGS += BUILD=release
 endif
-VERSION_STRINGS += TARGET_PLATFORM=$(TARGET_PLATFORM)
+VERSION_STRINGS += TARGET_PLATFORM=$(MALI_PLATFORM)
 VERSION_STRINGS += MALI_PLATFORM=$(MALI_PLATFORM)
 VERSION_STRINGS += KDIR=$(KDIR)
 VERSION_STRINGS += OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB=$(OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB)
diff --git a/drivers/gpu/arm/mali400/r5p2_rel0/platform/exynos/exynos.c b/drivers/gpu/arm/mali400/r5p2_rel0/platform/exynos/exynos.c
new file mode 100644 (file)
index 0000000..d4fe53b
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * Mali400 platform glue for Samsung Exynos SoCs
+ *
+ * Copyright 2013 by Samsung Electronics Co., Ltd.
+ * Author: Tomasz Figa <t.figa@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software FoundatIon.
+ */
+
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/mali/mali_utgard.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+
+#include "mali_kernel_common.h"
+#include "mali_osk.h"
+
+#ifdef CONFIG_MALI400_PROFILING
+#include "mali_osk_profiling.h"
+#endif
+
+#include "exynos.h"
+
+struct mali_exynos_variant {
+       const struct mali_exynos_dvfs_step *steps;
+       unsigned int nr_steps;
+       unsigned int has_smmuclk;
+};
+
+struct mali_exynos_dvfs_step {
+       unsigned int rate;
+       unsigned int voltage;
+       unsigned int downthreshold;
+       unsigned int upthreshold;
+};
+
+struct mali_exynos_drvdata {
+       struct device *dev;
+
+       const struct mali_exynos_dvfs_step *steps;
+       unsigned int nr_steps;
+       unsigned int has_smmuclk;
+
+       struct clk *pll;
+       struct clk *mux1;
+       struct clk *mux2;
+       struct clk *sclk;
+       struct clk *smmu;
+       struct clk *g3d;
+
+       struct regulator *vdd_g3d;
+
+       mali_power_mode power_mode;
+       unsigned int dvfs_step;
+       unsigned int load;
+
+       struct workqueue_struct *dvfs_workqueue;
+       struct work_struct dvfs_work;
+};
+
+extern struct platform_device *mali_platform_device;
+
+static struct mali_exynos_drvdata *mali;
+
+/*
+ * DVFS tables
+ */
+
+#define MALI_DVFS_STEP(freq, voltage, down, up) \
+       {freq, voltage, (256 * down) / 100, (256 * up) / 100}
+
+static const struct mali_exynos_dvfs_step mali_exynos_dvfs_step_3250[] = {
+       MALI_DVFS_STEP(134,       0,  0, 100)
+};
+
+static const struct mali_exynos_dvfs_step mali_exynos_dvfs_step_4210[] = {
+       MALI_DVFS_STEP(160,  950000,  0,  90),
+       MALI_DVFS_STEP(266, 1050000, 85, 100)
+};
+
+static const struct mali_exynos_dvfs_step mali_exynos_dvfs_step_4x12[] = {
+       MALI_DVFS_STEP(160,  875000,  0,  70),
+       MALI_DVFS_STEP(266,  900000, 62,  90),
+       MALI_DVFS_STEP(350,  950000, 85,  90),
+       MALI_DVFS_STEP(440, 1025000, 85, 100)
+};
+
+static const struct mali_exynos_dvfs_step mali_exynos_dvfs_step_4x12_prime[] = {
+       MALI_DVFS_STEP(160,  875000,  0,  70),
+       MALI_DVFS_STEP(266,  900000, 62,  90),
+       MALI_DVFS_STEP(350,  950000, 85,  90),
+       MALI_DVFS_STEP(440, 1025000, 85,  90),
+       MALI_DVFS_STEP(533, 1075000, 95, 100)
+};
+
+/*
+ * Variants
+ */
+
+static const struct mali_exynos_variant mali_variant_3250 = {
+       .steps = mali_exynos_dvfs_step_3250,
+       .nr_steps = ARRAY_SIZE(mali_exynos_dvfs_step_3250),
+       .has_smmuclk = true,
+};
+
+static const struct mali_exynos_variant mali_variant_4210 = {
+       .steps = mali_exynos_dvfs_step_4210,
+       .nr_steps = ARRAY_SIZE(mali_exynos_dvfs_step_4210),
+};
+
+static const struct mali_exynos_variant mali_variant_4x12 = {
+       .steps = mali_exynos_dvfs_step_4x12,
+       .nr_steps = ARRAY_SIZE(mali_exynos_dvfs_step_4x12),
+};
+
+static const struct mali_exynos_variant mali_variant_4x12_prime = {
+       .steps = mali_exynos_dvfs_step_4x12_prime,
+       .nr_steps = ARRAY_SIZE(mali_exynos_dvfs_step_4x12_prime),
+};
+
+const struct of_device_id mali_of_matches[] = {
+       { .compatible = "samsung,exynos3250-g3d",
+                                       .data = &mali_variant_3250, },
+       { .compatible = "samsung,exynos4210-g3d",
+                                       .data = &mali_variant_4210, },
+       { .compatible = "samsung,exynos4x12-g3d",
+                                       .data = &mali_variant_4x12, },
+       { .compatible = "samsung,exynos4x12-prime-g3d",
+                                       .data = &mali_variant_4x12_prime, },
+       { /* Sentinel */ }
+};
+
+#ifdef CONFIG_MALI400_PROFILING
+static inline void _mali_osk_profiling_add_gpufreq_event(int rate, int vol)
+{
+       _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE |
+                MALI_PROFILING_EVENT_CHANNEL_GPU |
+                MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE,
+                rate, vol, 0, 0, 0);
+}
+#else
+static inline void _mali_osk_profiling_add_gpufreq_event(int rate, int vol)
+{
+}
+#endif
+
+/*
+ * DVFS control
+ */
+
+static void mali_exynos_set_dvfs_step(struct mali_exynos_drvdata *mali,
+                                                       unsigned int step)
+{
+       const struct mali_exynos_dvfs_step *next = &mali->steps[step];
+
+       if (step <= mali->dvfs_step)
+               clk_set_rate(mali->sclk, next->rate * 1000000);
+
+       regulator_set_voltage(mali->vdd_g3d,
+                                       next->voltage, next->voltage);
+
+       if (step > mali->dvfs_step)
+               clk_set_rate(mali->sclk, next->rate * 1000000);
+
+       _mali_osk_profiling_add_gpufreq_event(next->rate * 1000000,
+                regulator_get_voltage(mali->vdd_g3d) / 1000);
+       mali->dvfs_step = step;
+}
+
+static void exynos_dvfs_work(struct work_struct *work)
+{
+       struct mali_exynos_drvdata *mali = container_of(work,
+                                       struct mali_exynos_drvdata, dvfs_work);
+       unsigned int step = mali->dvfs_step;
+       const struct mali_exynos_dvfs_step *cur = &mali->steps[step];
+
+       if (mali->load > cur->upthreshold)
+               ++step;
+       else if (mali->load < cur->downthreshold)
+               --step;
+
+       BUG_ON(step >= mali->nr_steps);
+
+       if (step != mali->dvfs_step)
+               mali_exynos_set_dvfs_step(mali, step);
+}
+
+static void exynos_update_dvfs(struct mali_gpu_utilization_data *data)
+{
+       if (data->utilization_gpu > 255)
+               data->utilization_gpu = 255;
+
+       mali->load = data->utilization_gpu;
+
+       queue_work(mali->dvfs_workqueue, &mali->dvfs_work);
+}
+
+/*
+ * Power management
+ */
+
+_mali_osk_errcode_t mali_platform_power_mode_change(mali_power_mode power_mode)
+{
+       if (WARN_ON(mali->power_mode == power_mode))
+               MALI_SUCCESS;
+
+       switch (power_mode) {
+       case MALI_POWER_MODE_ON:
+               mali_exynos_set_dvfs_step(mali, 0);
+               clk_prepare_enable(mali->g3d);
+               clk_prepare_enable(mali->sclk);
+               if (mali->has_smmuclk)
+                       clk_prepare_enable(mali->smmu);
+               break;
+
+       case MALI_POWER_MODE_LIGHT_SLEEP:
+       case MALI_POWER_MODE_DEEP_SLEEP:
+               if (mali->has_smmuclk)
+                       clk_disable_unprepare(mali->smmu);
+               clk_disable_unprepare(mali->sclk);
+               clk_disable_unprepare(mali->g3d);
+               _mali_osk_profiling_add_gpufreq_event(0, 0);
+               break;
+       }
+
+       mali->power_mode = power_mode;
+
+       MALI_SUCCESS;
+}
+
+/*
+ * Platform-specific initialization/cleanup
+ */
+
+static struct mali_gpu_device_data mali_exynos_gpu_data = {
+       .shared_mem_size = SZ_256M,
+       .fb_start = 0x40000000,
+       .fb_size = 0xb1000000,
+       .utilization_interval = 100, /* 100ms in Tizen */
+       .utilization_callback = exynos_update_dvfs,
+};
+
+_mali_osk_errcode_t mali_platform_init(void)
+{
+       struct platform_device *pdev = mali_platform_device;
+       const struct mali_exynos_variant *variant;
+       const struct of_device_id *match;
+       struct resource *old_res, *new_res;
+       unsigned int i, irq_res, mem_res;
+       struct device_node *np;
+       int ret;
+
+       if (WARN_ON(!pdev))
+               return -ENODEV;
+
+       MALI_DEBUG_PRINT(4, ("mali_platform_device_register() called\n"));
+
+       pdev->dev.platform_data = &mali_exynos_gpu_data;
+
+       np = pdev->dev.of_node;
+       if (WARN_ON(!np))
+               return -ENODEV;
+
+       match = of_match_node(mali_of_matches, np);
+       if (WARN_ON(!match))
+               return -ENODEV;
+
+       variant = match->data;
+
+       old_res = pdev->resource;
+       new_res = kzalloc(sizeof(*new_res) * pdev->num_resources, GFP_KERNEL);
+       if (WARN_ON(!new_res))
+               return -ENOMEM;
+
+       /* Rearrange next resources */
+       irq_res = 0;
+       mem_res = 0;
+       for (i = 0; i < pdev->num_resources; ++i, ++old_res) {
+               if (resource_type(old_res) == IORESOURCE_MEM)
+                       memcpy(&new_res[2 * mem_res++],
+                                               old_res, sizeof(*old_res));
+               else if (resource_type(old_res) == IORESOURCE_IRQ)
+                       memcpy(&new_res[1 + 2 * irq_res++],
+                                               old_res, sizeof(*old_res));
+       }
+
+       kfree(pdev->resource);
+       pdev->resource = new_res;
+
+       mali = devm_kzalloc(&pdev->dev, sizeof(*mali), GFP_KERNEL);
+       if (WARN_ON(!mali))
+               return -ENOMEM;
+
+       mali->dev = &pdev->dev;
+       mali->steps = variant->steps;
+       mali->nr_steps = variant->nr_steps;
+       mali->has_smmuclk = variant->has_smmuclk;
+
+       mali->pll = devm_clk_get(mali->dev, "pll");
+       if (WARN_ON(IS_ERR(mali->pll)))
+               return PTR_ERR(mali->pll);
+
+       mali->mux1 = devm_clk_get(mali->dev, "mux1");
+       if (WARN_ON(IS_ERR(mali->mux1)))
+               return PTR_ERR(mali->mux1);
+
+       mali->mux2 = devm_clk_get(mali->dev, "mux2");
+       if (WARN_ON(IS_ERR(mali->mux2)))
+               return PTR_ERR(mali->mux2);
+
+       mali->sclk = devm_clk_get(mali->dev, "sclk");
+       if (WARN_ON(IS_ERR(mali->sclk)))
+               return PTR_ERR(mali->sclk);
+
+       if (mali->has_smmuclk) {
+               mali->smmu = devm_clk_get(mali->dev, "smmu");
+               if (WARN_ON(IS_ERR(mali->smmu)))
+                       return PTR_ERR(mali->smmu);
+       }
+
+       mali->g3d = devm_clk_get(mali->dev, "g3d");
+       if (WARN_ON(IS_ERR(mali->g3d)))
+               return PTR_ERR(mali->g3d);
+
+       mali->vdd_g3d = devm_regulator_get(mali->dev, "vdd_g3d");
+       if (WARN_ON(IS_ERR(mali->vdd_g3d)))
+               return PTR_ERR(mali->vdd_g3d);
+
+       mali->dvfs_workqueue = create_singlethread_workqueue("mali_dvfs");
+       if (WARN_ON(!mali->dvfs_workqueue))
+               return -EFAULT;
+
+       mali->power_mode = MALI_POWER_MODE_LIGHT_SLEEP;
+
+       INIT_WORK(&mali->dvfs_work, exynos_dvfs_work);
+
+       ret = regulator_enable(mali->vdd_g3d);
+       if (WARN_ON(ret)) {
+               destroy_workqueue(mali->dvfs_workqueue);
+               MALI_ERROR(_MALI_OSK_ERR_FAULT);
+       }
+
+       clk_set_parent(mali->mux1, mali->pll);
+       clk_set_parent(mali->mux2, mali->mux1);
+       mali_exynos_set_dvfs_step(mali, 0);
+
+       pm_runtime_set_autosuspend_delay(&pdev->dev, 300);
+       pm_runtime_use_autosuspend(&pdev->dev);
+
+       pm_runtime_enable(&pdev->dev);
+
+       MALI_SUCCESS;
+}
+
+_mali_osk_errcode_t mali_platform_deinit(void)
+{
+       struct platform_device *pdev = mali_platform_device;
+
+       pm_runtime_disable(&pdev->dev);
+
+       regulator_disable(mali->vdd_g3d);
+
+       _mali_osk_profiling_add_gpufreq_event(0, 0);
+
+       MALI_SUCCESS;
+}
diff --git a/drivers/gpu/arm/mali400/r5p2_rel0/platform/exynos/exynos.h b/drivers/gpu/arm/mali400/r5p2_rel0/platform/exynos/exynos.h
new file mode 100644 (file)
index 0000000..dd03d6c
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Mali400 platform glue for Samsung Exynos SoCs
+ *
+ * Copyright 2013 by Samsung Electronics Co., Ltd.
+ * Author: Tomasz Figa <t.figa@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software FoundatIon.
+ */
+
+#ifndef __EXYNOS_H__
+#define __EXYNOS_H__
+
+#include <linux/of_device.h>
+
+#include "mali_osk.h"
+
+/** @brief description of power change reasons
+ */
+typedef enum mali_power_mode_tag
+{
+       MALI_POWER_MODE_ON,
+       MALI_POWER_MODE_LIGHT_SLEEP,
+       MALI_POWER_MODE_DEEP_SLEEP,
+} mali_power_mode;
+
+/** @brief Platform specific setup and initialisation of MALI
+ *
+ * This is called from the entrypoint of the driver to initialize the platform
+ *
+ * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error.
+ */
+_mali_osk_errcode_t mali_platform_init(void);
+
+/** @brief Platform specific deinitialisation of MALI
+ *
+ * This is called on the exit of the driver to terminate the platform
+ *
+ * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error.
+ */
+_mali_osk_errcode_t mali_platform_deinit(void);
+
+/** @brief Platform specific powerdown sequence of MALI
+ *
+ * Call as part of platform init if there is no PMM support, else the
+ * PMM will call it.
+ * There are three power modes defined:
+ *  1) MALI_POWER_MODE_ON
+ *  2) MALI_POWER_MODE_LIGHT_SLEEP
+ *  3) MALI_POWER_MODE_DEEP_SLEEP
+ * MALI power management module transitions to MALI_POWER_MODE_LIGHT_SLEEP mode when MALI is idle
+ * for idle timer (software timer defined in mali_pmm_policy_jobcontrol.h) duration, MALI transitions
+ * to MALI_POWER_MODE_LIGHT_SLEEP mode during timeout if there are no more jobs queued.
+ * MALI power management module transitions to MALI_POWER_MODE_DEEP_SLEEP mode when OS does system power
+ * off.
+ * Customer has to add power down code when MALI transitions to MALI_POWER_MODE_LIGHT_SLEEP or MALI_POWER_MODE_DEEP_SLEEP
+ * mode.
+ * MALI_POWER_MODE_ON mode is entered when the MALI is to powered up. Some customers want to control voltage regulators during
+ * the whole system powers on/off. Customer can track in this function whether the MALI is powered up from
+ * MALI_POWER_MODE_LIGHT_SLEEP or MALI_POWER_MODE_DEEP_SLEEP mode and manage the voltage regulators as well.
+ * @param power_mode defines the power modes
+ * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error.
+ */
+_mali_osk_errcode_t mali_platform_power_mode_change(mali_power_mode power_mode);
+
+extern const struct of_device_id mali_of_matches[];
+
+#endif