aboutsummaryrefslogtreecommitdiff
path: root/drivers/misc/mediatek/gpu/ged/src
diff options
context:
space:
mode:
authorMeizu OpenSource <patchwork@meizu.com>2016-08-15 10:19:42 +0800
committerMeizu OpenSource <patchwork@meizu.com>2016-08-15 10:19:42 +0800
commitd2e1446d81725c351dc73a03b397ce043fb18452 (patch)
tree4dbc616b7f92aea39cd697a9084205ddb805e344 /drivers/misc/mediatek/gpu/ged/src
downloadandroid_kernel_m2note-d2e1446d81725c351dc73a03b397ce043fb18452.tar.gz
first commit
Diffstat (limited to 'drivers/misc/mediatek/gpu/ged/src')
-rw-r--r--drivers/misc/mediatek/gpu/ged/src/ged_base.c99
-rw-r--r--drivers/misc/mediatek/gpu/ged/src/ged_bridge.c79
-rw-r--r--drivers/misc/mediatek/gpu/ged/src/ged_debugFS.c178
-rw-r--r--drivers/misc/mediatek/gpu/ged/src/ged_hal.c284
-rw-r--r--drivers/misc/mediatek/gpu/ged/src/ged_hashtable.c217
-rw-r--r--drivers/misc/mediatek/gpu/ged/src/ged_log.c984
-rw-r--r--drivers/misc/mediatek/gpu/ged/src/ged_main.c338
-rw-r--r--drivers/misc/mediatek/gpu/ged/src/ged_monitor_3D_fence.c141
-rw-r--r--drivers/misc/mediatek/gpu/ged/src/ged_profile_dvfs.c190
9 files changed, 2510 insertions, 0 deletions
diff --git a/drivers/misc/mediatek/gpu/ged/src/ged_base.c b/drivers/misc/mediatek/gpu/ged/src/ged_base.c
new file mode 100644
index 000000000..91ed382ca
--- /dev/null
+++ b/drivers/misc/mediatek/gpu/ged/src/ged_base.c
@@ -0,0 +1,99 @@
+/*
+ * (C) Copyright 2010
+ * MediaTek <www.MediaTek.com>
+ *
+ * MTK GPU Extension Device
+ *
+ */
+
+#include "ged_base.h"
+#include <asm/page.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38))
+#ifndef AUTOCONF_INCLUDED
+#include <linux/config.h>
+#endif
+#endif
+
+#include <asm/uaccess.h>
+
+unsigned long ged_copy_to_user(void __user *pvTo, const void *pvFrom, unsigned long ulBytes)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33))
+ if (access_ok(VERIFY_WRITE, pvTo, ulBytes))
+ {
+ return __copy_to_user(pvTo, pvFrom, ulBytes);
+ }
+ return ulBytes;
+#else
+ return copy_to_user(pvTo, pvFrom, ulBytes);
+#endif
+}
+
+unsigned long ged_copy_from_user(void *pvTo, const void __user *pvFrom, unsigned long ulBytes)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33))
+ if (access_ok(VERIFY_READ, pvFrom, ulBytes))
+ {
+ return __copy_from_user(pvTo, pvFrom, ulBytes);
+ }
+ return ulBytes;
+#else
+ return copy_from_user(pvTo, pvFrom, ulBytes);
+#endif
+}
+
+void* ged_alloc(int i32Size)
+{
+ void *pvBuf;
+
+ if (i32Size <= PAGE_SIZE)
+ {
+ pvBuf = kmalloc(i32Size, GFP_KERNEL);
+ }
+ else
+ {
+ pvBuf = vmalloc(i32Size);
+ }
+
+ return pvBuf;
+}
+
+void ged_free(void* pvBuf, int i32Size)
+{
+ if (pvBuf)
+ {
+ if (i32Size <= PAGE_SIZE)
+ {
+ kfree(pvBuf);
+ }
+ else
+ {
+ vfree(pvBuf);
+ }
+ }
+}
+
+long ged_get_pid(void)
+{
+ if (in_interrupt())
+ {
+ return 0xffffffffL;
+ }
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
+ return (long)current->pgrp;
+#else
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24))
+ return (long)task_tgid_nr(current);
+#else
+ return (long)current->tgid;
+#endif
+#endif
+}
+
diff --git a/drivers/misc/mediatek/gpu/ged/src/ged_bridge.c b/drivers/misc/mediatek/gpu/ged/src/ged_bridge.c
new file mode 100644
index 000000000..99eccd774
--- /dev/null
+++ b/drivers/misc/mediatek/gpu/ged/src/ged_bridge.c
@@ -0,0 +1,79 @@
+#include <linux/kernel.h>
+#include <linux/mtk_gpu_utility.h>
+
+#include "ged_base.h"
+#include "ged_bridge.h"
+#include "ged_log.h"
+#include "ged_profile_dvfs.h"
+#include "ged_monitor_3D_fence.h"
+
+//-----------------------------------------------------------------------------
+int ged_bridge_log_buf_get(
+ GED_BRIDGE_IN_LOGBUFGET *psLogBufGetIN,
+ GED_BRIDGE_OUT_LOGBUFGET *psLogBufGetOUT)
+{
+ psLogBufGetOUT->hLogBuf = ged_log_buf_get(psLogBufGetIN->acName);
+ psLogBufGetOUT->eError = psLogBufGetOUT->hLogBuf ? GED_OK : GED_ERROR_FAIL;
+ return 0;
+}
+//-----------------------------------------------------------------------------
+int ged_bridge_log_buf_write(
+ GED_BRIDGE_IN_LOGBUFWRITE *psLogBufWriteIN,
+ GED_BRIDGE_OUT_LOGBUFWRITE *psLogBufWriteOUT)
+{
+ psLogBufWriteOUT->eError =
+ ged_log_buf_print2(psLogBufWriteIN->hLogBuf, psLogBufWriteIN->attrs, psLogBufWriteIN->acLogBuf);
+
+#if 0
+ if (ged_log_buf_write(
+ psLogBufWriteIN->hLogBuf,
+ /*from user*/psLogBufWriteIN->acLogBuf,
+ GED_BRIDGE_IN_LOGBUF_SIZE) > 0)
+ {
+ psLogBufWriteOUT->eError = GED_OK;
+ }
+ else
+ {
+ psLogBufWriteOUT->eError = GED_ERROR_FAIL;
+ }
+#endif
+ return 0;
+}
+//-----------------------------------------------------------------------------
+int ged_bridge_log_buf_reset(
+ GED_BRIDGE_IN_LOGBUFRESET *psLogBufResetIn,
+ GED_BRIDGE_OUT_LOGBUFRESET *psLogBufResetOUT)
+{
+ psLogBufResetOUT->eError = ged_log_buf_reset(psLogBufResetIn->hLogBuf);
+ return 0;
+}
+//-----------------------------------------------------------------------------
+int ged_bridge_boost_gpu_freq(
+ GED_BRIDGE_IN_BOOSTGPUFREQ *psBoostGpuFreqIN,
+ GED_BRIDGE_OUT_BOOSTGPUFREQ *psBoostGpuFreqOUT)
+{
+#if 1
+ psBoostGpuFreqOUT->eError = mtk_boost_gpu_freq() ? GED_OK : GED_ERROR_FAIL;
+#else
+ unsigned int ui32Count;
+ if (mtk_custom_get_gpu_freq_level_count(&ui32Count))
+ {
+ int i32Level = (ui32Count - 1) - GED_BOOST_GPU_FREQ_LEVEL_MAX - psBoostGpuFreqIN->eGPUFreqLevel;
+ mtk_boost_gpu_freq(i32Level);
+ psBoostGpuFreqOUT->eError = GED_OK;
+ }
+ else
+ {
+ psBoostGpuFreqOUT->eError = GED_ERROR_FAIL;
+ }
+#endif
+ return 0;
+}
+//-----------------------------------------------------------------------------
+int ged_bridge_monitor_3D_fence(
+ GED_BRIDGE_IN_MONITOR3DFENCE *psMonitor3DFenceINT,
+ GED_BRIDGE_OUT_MONITOR3DFENCE *psMonitor3DFenceOUT)
+{
+ psMonitor3DFenceOUT->eError = ged_monitor_3D_fence_add(psMonitor3DFenceINT->fd);
+ return 0;
+}
diff --git a/drivers/misc/mediatek/gpu/ged/src/ged_debugFS.c b/drivers/misc/mediatek/gpu/ged/src/ged_debugFS.c
new file mode 100644
index 000000000..0e208903d
--- /dev/null
+++ b/drivers/misc/mediatek/gpu/ged/src/ged_debugFS.c
@@ -0,0 +1,178 @@
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <linux/debugfs.h>
+
+#include "ged_base.h"
+#include "ged_debugFS.h"
+
+#define GED_DEBUGFS_DIR_NAME "ged"
+
+static struct dentry *gpsDebugFSEntryDir = NULL;
+
+typedef struct _GED_DEBUGFS_PRIV_DATA_
+{
+ struct seq_operations* psReadOps;
+ GED_ENTRY_WRITE_FUNC* pfnWrite;
+ void* pvData;
+} GED_DEBUGFS_PRIV_DATA;
+//-----------------------------------------------------------------------------
+static GED_ERROR ged_debugFS_open(struct inode *psINode, struct file *psFile)
+{
+ GED_DEBUGFS_PRIV_DATA *psPrivData = (GED_DEBUGFS_PRIV_DATA *)psINode->i_private;
+ int iResult;
+
+ iResult = seq_open(psFile, psPrivData->psReadOps);
+ if (iResult == 0)
+ {
+ struct seq_file *psSeqFile = psFile->private_data;
+
+ psSeqFile->private = psPrivData->pvData;
+
+ return GED_OK;
+ }
+
+ return GED_ERROR_FAIL;
+}
+//-----------------------------------------------------------------------------
+static ssize_t ged_debugFS_write(
+ struct file* psFile,
+ const char __user* pszBuffer,
+ size_t uiCount,
+ loff_t* puiPosition)
+{
+ struct inode *psINode = psFile->f_path.dentry->d_inode;
+ GED_DEBUGFS_PRIV_DATA *psPrivData = (GED_DEBUGFS_PRIV_DATA *)psINode->i_private;
+
+ if (psPrivData->pfnWrite == NULL)
+ {
+ return -EIO;
+ }
+
+ return psPrivData->pfnWrite(pszBuffer, uiCount, *puiPosition, psPrivData->pvData);
+}
+//-----------------------------------------------------------------------------
+static const struct file_operations gsGEDDebugFSFileOps =
+{
+ .owner = THIS_MODULE,
+ .open = ged_debugFS_open,
+ .read = seq_read,
+ .write = ged_debugFS_write,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+//-----------------------------------------------------------------------------
+GED_ERROR ged_debugFS_create_entry(
+ const char* pszName,
+ void* pvDir,
+ struct seq_operations* psReadOps,
+ GED_ENTRY_WRITE_FUNC* pfnWrite,
+ void* pvData,
+ struct dentry** ppsEntry)
+{
+ GED_DEBUGFS_PRIV_DATA* psPrivData;
+ struct dentry* psEntry;
+ umode_t uiMode;
+
+ //assert(gpkDebugFSEntryDir != NULL);
+
+ psPrivData = ged_alloc(sizeof(GED_DEBUGFS_PRIV_DATA));
+ if (psPrivData == NULL)
+ {
+ return GED_ERROR_OOM;
+ }
+
+ psPrivData->psReadOps = psReadOps;
+ psPrivData->pfnWrite = pfnWrite;
+ psPrivData->pvData = pvData;
+
+ uiMode = S_IFREG;
+
+ if (psReadOps != NULL)
+ {
+ uiMode |= S_IRUGO;
+ }
+
+ if (pfnWrite != NULL)
+ {
+ uiMode |= S_IWUSR;
+ }
+
+ psEntry = debugfs_create_file(pszName,
+ uiMode,
+ (pvDir != NULL) ? (struct dentry *)pvDir : gpsDebugFSEntryDir,
+ psPrivData,
+ &gsGEDDebugFSFileOps);
+ if (IS_ERR(psEntry))
+ {
+ GED_LOGE("Failed to create '%s' debugfs entry\n", pszName);
+ return GED_ERROR_FAIL;
+ }
+
+ *ppsEntry = psEntry;
+
+ return GED_OK;
+}
+//-----------------------------------------------------------------------------
+void ged_debugFS_remove_entry(struct dentry *psEntry)
+{
+ if (psEntry->d_inode->i_private != NULL)
+ {
+ ged_free(psEntry->d_inode->i_private, sizeof(GED_DEBUGFS_PRIV_DATA));
+ }
+
+ debugfs_remove(psEntry);
+}
+//-----------------------------------------------------------------------------
+GED_ERROR ged_debugFS_create_entry_dir(
+ const char* pszName,
+ struct dentry* psParentDir,
+ struct dentry** ppsDir)
+{
+ struct dentry *psDir;
+
+ if (pszName == NULL || ppsDir == NULL)
+ {
+ return GED_ERROR_INVALID_PARAMS;
+ }
+
+ psDir = debugfs_create_dir(pszName, (psParentDir) ? psParentDir : gpsDebugFSEntryDir);
+ if (psDir == NULL)
+ {
+ GED_LOGE("Failed to create '%s' debugfs directory\n", pszName);
+ return GED_ERROR_OOM;
+ }
+
+ *ppsDir = psDir;
+
+ return GED_OK;
+}
+//-----------------------------------------------------------------------------
+void ged_debugFS_remove_entry_dir(struct dentry *psDir)
+{
+ debugfs_remove(psDir);
+}
+//-----------------------------------------------------------------------------
+GED_ERROR ged_debugFS_init(void)
+{
+ //assert(gpkDebugFSEntryDir == NULL);
+
+ gpsDebugFSEntryDir = debugfs_create_dir(GED_DEBUGFS_DIR_NAME, NULL);
+ if (gpsDebugFSEntryDir == NULL)
+ {
+ GED_LOGE("Failed to create '%s' debugfs root directory\n", GED_DEBUGFS_DIR_NAME);
+ return GED_ERROR_OOM;
+ }
+
+ return GED_OK;
+}
+//-----------------------------------------------------------------------------
+void ged_debugFS_exit(void)
+{
+ //assert(gpkDebugFSEntryDir != NULL);
+
+ debugfs_remove(gpsDebugFSEntryDir);
+ gpsDebugFSEntryDir = NULL;
+}
+//-----------------------------------------------------------------------------
+
diff --git a/drivers/misc/mediatek/gpu/ged/src/ged_hal.c b/drivers/misc/mediatek/gpu/ged/src/ged_hal.c
new file mode 100644
index 000000000..3f3fe293c
--- /dev/null
+++ b/drivers/misc/mediatek/gpu/ged/src/ged_hal.c
@@ -0,0 +1,284 @@
+#include <linux/version.h>
+#include <asm/io.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/genalloc.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include <linux/xlog.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/mtk_gpu_utility.h>
+
+#include "ged_base.h"
+#include "ged_hal.h"
+#include "ged_debugFS.h"
+
+static struct dentry* gpsHALDir = NULL;
+static struct dentry* gpsTotalGPUFreqLevelCountEntry = NULL;
+static struct dentry* gpsCustomBoostGPUFreqEntry = NULL;
+static struct dentry* gpsCustomUpboundGPUFreqEntry = NULL;
+
+//-----------------------------------------------------------------------------
+static void* ged_total_gpu_freq_level_count_seq_start(struct seq_file *psSeqFile, loff_t *puiPosition)
+{
+ if (0 == *puiPosition)
+ {
+ return 1;
+ }
+
+ return NULL;
+}
+//-----------------------------------------------------------------------------
+static void ged_total_gpu_freq_level_count_seq_stop(struct seq_file *psSeqFile, void *pvData)
+{
+
+}
+//-----------------------------------------------------------------------------
+static void* ged_total_gpu_freq_level_count_seq_next(struct seq_file *psSeqFile, void *pvData, loff_t *puiPosition)
+{
+ return NULL;
+}
+//-----------------------------------------------------------------------------
+static int ged_total_gpu_freq_level_count_seq_show(struct seq_file *psSeqFile, void *pvData)
+{
+ if (pvData != NULL)
+ {
+ unsigned int ui32FreqLevelCount;
+ if (false == mtk_custom_get_gpu_freq_level_count(&ui32FreqLevelCount))
+ {
+ ui32FreqLevelCount = 0;
+ }
+ seq_printf(psSeqFile, "%u\n", ui32FreqLevelCount);
+ }
+
+ return 0;
+}
+//-----------------------------------------------------------------------------
+static struct seq_operations gsTotalGPUFreqLevelCountReadOps =
+{
+ .start = ged_total_gpu_freq_level_count_seq_start,
+ .stop = ged_total_gpu_freq_level_count_seq_stop,
+ .next = ged_total_gpu_freq_level_count_seq_next,
+ .show = ged_total_gpu_freq_level_count_seq_show,
+};
+//-----------------------------------------------------------------------------
+static ssize_t ged_custom_boost_gpu_freq_write_entry(const char __user *pszBuffer, size_t uiCount, loff_t uiPosition, void *pvData)
+{
+#define GED_HAL_DEBUGFS_SIZE 64
+ char acBuffer[GED_HAL_DEBUGFS_SIZE];
+
+ int i32Value;
+
+ if ((0 < uiCount) && (uiCount < GED_HAL_DEBUGFS_SIZE))
+ {
+ if (0 == ged_copy_from_user(acBuffer, pszBuffer, uiCount))
+ {
+ acBuffer[uiCount] = '\0';
+ if (sscanf(acBuffer, "%d", &i32Value) == 1)
+ {
+ if (i32Value < 0)
+ i32Value = 0;
+ mtk_custom_boost_gpu_freq(i32Value);
+ }
+ //else if (...) //for other commands
+ //{
+ //}
+ }
+ }
+
+ return uiCount;
+}
+//-----------------------------------------------------------------------------
+static void* ged_custom_boost_gpu_freq_seq_start(struct seq_file *psSeqFile, loff_t *puiPosition)
+{
+ if (0 == *puiPosition)
+ {
+ return 1;
+ }
+
+ return NULL;
+}
+//-----------------------------------------------------------------------------
+static void ged_custom_boost_gpu_freq_seq_stop(struct seq_file *psSeqFile, void *pvData)
+{
+
+}
+//-----------------------------------------------------------------------------
+static void* ged_custom_boost_gpu_freq_seq_next(struct seq_file *psSeqFile, void *pvData, loff_t *puiPosition)
+{
+ return NULL;
+}
+//-----------------------------------------------------------------------------
+static int ged_custom_boost_gpu_freq_seq_show(struct seq_file *psSeqFile, void *pvData)
+{
+ if (pvData != NULL)
+ {
+ unsigned int ui32BoostGpuFreqLevel;
+ if (false == mtk_get_custom_boost_gpu_freq(&ui32BoostGpuFreqLevel))
+ {
+ ui32BoostGpuFreqLevel = 0;
+ }
+ seq_printf(psSeqFile, "%u\n", ui32BoostGpuFreqLevel);
+ }
+
+ return 0;
+}
+//-----------------------------------------------------------------------------
+static struct seq_operations gsCustomBoostGpuFreqReadOps =
+{
+ .start = ged_custom_boost_gpu_freq_seq_start,
+ .stop = ged_custom_boost_gpu_freq_seq_stop,
+ .next = ged_custom_boost_gpu_freq_seq_next,
+ .show = ged_custom_boost_gpu_freq_seq_show,
+};
+//-----------------------------------------------------------------------------
+static ssize_t ged_custom_upbound_gpu_freq_write_entry(const char __user *pszBuffer, size_t uiCount, loff_t uiPosition, void *pvData)
+{
+#define GED_HAL_DEBUGFS_SIZE 64
+ char acBuffer[GED_HAL_DEBUGFS_SIZE];
+
+ int i32Value;
+
+ if ((0 < uiCount) && (uiCount < GED_HAL_DEBUGFS_SIZE))
+ {
+ if (0 == ged_copy_from_user(acBuffer, pszBuffer, uiCount))
+ {
+ acBuffer[uiCount] = '\0';
+ if (sscanf(acBuffer, "%d", &i32Value) == 1)
+ {
+ if (i32Value < 0)
+ i32Value = 0;
+ mtk_custom_upbound_gpu_freq(i32Value);
+ }
+ //else if (...) //for other commands
+ //{
+ //}
+ }
+ }
+
+ return uiCount;
+}
+//-----------------------------------------------------------------------------
+static void* ged_custom_upbound_gpu_freq_seq_start(struct seq_file *psSeqFile, loff_t *puiPosition)
+{
+ if (0 == *puiPosition)
+ {
+ return 1;
+ }
+
+ return NULL;
+}
+//-----------------------------------------------------------------------------
+static void ged_custom_upbound_gpu_freq_seq_stop(struct seq_file *psSeqFile, void *pvData)
+{
+
+}
+//-----------------------------------------------------------------------------
+static void* ged_custom_upbound_gpu_freq_seq_next(struct seq_file *psSeqFile, void *pvData, loff_t *puiPosition)
+{
+ return NULL;
+}
+//-----------------------------------------------------------------------------
+static int ged_custom_upbound_gpu_freq_seq_show(struct seq_file *psSeqFile, void *pvData)
+{
+ if (pvData != NULL)
+ {
+ unsigned int ui32UpboundGpuFreqLevel;
+ if (false == mtk_get_custom_upbound_gpu_freq(&ui32UpboundGpuFreqLevel))
+ {
+ ui32UpboundGpuFreqLevel = 0;
+ seq_printf(psSeqFile, "call mtk_get_custom_upbound_gpu_freq false\n");
+ }
+ seq_printf(psSeqFile, "%u\n", ui32UpboundGpuFreqLevel);
+ }
+
+ return 0;
+}
+//-----------------------------------------------------------------------------
+static struct seq_operations gsCustomUpboundGpuFreqReadOps =
+{
+ .start = ged_custom_upbound_gpu_freq_seq_start,
+ .stop = ged_custom_upbound_gpu_freq_seq_stop,
+ .next = ged_custom_upbound_gpu_freq_seq_next,
+ .show = ged_custom_upbound_gpu_freq_seq_show,
+};
+//-----------------------------------------------------------------------------
+GED_ERROR ged_hal_init(void)
+{
+ GED_ERROR err = GED_OK;
+
+ err = ged_debugFS_create_entry_dir(
+ "hal",
+ NULL,
+ &gpsHALDir);
+
+ if (unlikely(err != GED_OK))
+ {
+ err = GED_ERROR_FAIL;
+ GED_LOGE("ged: failed to create hal dir!\n");
+ goto ERROR;
+ }
+
+ /* Feedback the gpu freq level count */
+ err = ged_debugFS_create_entry(
+ "total_gpu_freq_level_count",
+ gpsHALDir,
+ &gsTotalGPUFreqLevelCountReadOps,
+ NULL,
+ NULL,
+ &gpsTotalGPUFreqLevelCountEntry);
+
+ if (unlikely(err != GED_OK))
+ {
+ GED_LOGE("ged: failed to create total_gpu_freq_level_count entry!\n");
+ goto ERROR;
+ }
+
+ /* Control the gpu freq */
+ err = ged_debugFS_create_entry(
+ "custom_boost_gpu_freq",
+ gpsHALDir,
+ &gsCustomBoostGpuFreqReadOps,
+ ged_custom_boost_gpu_freq_write_entry,
+ NULL,
+ &gpsCustomBoostGPUFreqEntry);
+
+ if (unlikely(err != GED_OK))
+ {
+ GED_LOGE("ged: failed to create custom_boost_gpu_freq entry!\n");
+ goto ERROR;
+ }
+
+ /* Control the gpu freq */
+ err = ged_debugFS_create_entry(
+ "custom_upbound_gpu_freq",
+ gpsHALDir,
+ &gsCustomUpboundGpuFreqReadOps,
+ ged_custom_upbound_gpu_freq_write_entry,
+ NULL,
+ &gpsCustomUpboundGPUFreqEntry);
+
+ if (unlikely(err != GED_OK))
+ {
+ GED_LOGE("ged: failed to create custom_upbound_gpu_freq entry!\n");
+ goto ERROR;
+ }
+
+ return err;
+
+ERROR:
+
+ ged_hal_exit();
+
+ return err;
+}
+//-----------------------------------------------------------------------------
+void ged_hal_exit(void)
+{
+ ged_debugFS_remove_entry(gpsCustomUpboundGPUFreqEntry);
+ ged_debugFS_remove_entry(gpsCustomBoostGPUFreqEntry);
+ ged_debugFS_remove_entry(gpsTotalGPUFreqLevelCountEntry);
+ ged_debugFS_remove_entry_dir(gpsHALDir);
+}
+//-----------------------------------------------------------------------------
diff --git a/drivers/misc/mediatek/gpu/ged/src/ged_hashtable.c b/drivers/misc/mediatek/gpu/ged/src/ged_hashtable.c
new file mode 100644
index 000000000..456ca364d
--- /dev/null
+++ b/drivers/misc/mediatek/gpu/ged/src/ged_hashtable.c
@@ -0,0 +1,217 @@
+#include "ged_base.h"
+#include "ged_hashtable.h"
+#include <linux/hashtable.h>
+
+typedef struct GED_HASHTABLE_TAG
+{
+ unsigned int ui32Bits;
+ unsigned int ui32Length;
+ unsigned int ui32CurrentID;
+ unsigned int ui32Count;
+ struct hlist_head* psHashTable;
+} GED_HASHTABLE;
+
+typedef struct GED_HASHNODE_TAG
+{
+ unsigned int ui32ID;
+ void* pvoid;
+ struct hlist_node sNode;
+} GED_HASHNODE;
+
+#define GED_HASHTABLE_INIT_ID 1234 // 0 = invalid
+
+void* __ged_hashtable_find(struct hlist_head *head, unsigned int ui32ID)
+{
+ GED_HASHNODE* psHN;
+ hlist_for_each_entry_rcu(psHN, head, sNode)
+ {
+ if (psHN->ui32ID == ui32ID)
+ {
+ return psHN;
+ }
+ }
+ return NULL;
+}
+
+static int ged_hash(GED_HASHTABLE_HANDLE hHashTable, unsigned int ui32ID)
+{
+ GED_HASHTABLE* psHT = (GED_HASHTABLE*)hHashTable;
+ return hash_32(ui32ID, psHT->ui32Bits);
+}
+
+GED_HASHTABLE_HANDLE ged_hashtable_create(unsigned int ui32Bits)
+{
+ GED_HASHTABLE* psHT;
+ unsigned int i;
+
+ if (ui32Bits > 20)
+ {
+ // 1048576 slots !?
+ // Need to check the necessary
+ return NULL;
+ }
+
+ psHT = (GED_HASHTABLE*)ged_alloc(sizeof(GED_HASHTABLE));
+ if (psHT)
+ {
+ psHT->ui32Bits = ui32Bits;
+ psHT->ui32Length = 1 << ui32Bits;
+ psHT->ui32CurrentID = GED_HASHTABLE_INIT_ID; // 0 = invalid
+ psHT->psHashTable = (struct hlist_head*)ged_alloc(psHT->ui32Length * sizeof(struct hlist_head));
+ if (psHT->psHashTable)
+ {
+ for (i = 0; i < psHT->ui32Length; i++)
+ {
+ INIT_HLIST_HEAD(&psHT->psHashTable[i]);
+ }
+ return (GED_HASHTABLE_HANDLE)psHT;
+ }
+ }
+
+ ged_hashtable_destroy(psHT);
+ return NULL;
+}
+
+void ged_hashtable_destroy(GED_HASHTABLE_HANDLE hHashTable)
+{
+ GED_HASHTABLE* psHT = (GED_HASHTABLE*)hHashTable;
+ if (psHT)
+ {
+ int i = 0;
+ while(psHT->ui32Count > 0)
+ {
+ unsigned int ui32ID = 0;
+ GED_HASHNODE* psHN;
+ // get one to be freed
+ for (;i < psHT->ui32Length; i++)
+ {
+ struct hlist_head *head = &psHT->psHashTable[i];
+ hlist_for_each_entry_rcu(psHN, head, sNode)
+ {
+ ui32ID = psHN->ui32ID;
+ break;
+ }
+ if (0 < ui32ID)
+ {
+ break;
+ }
+ }
+
+ if (i >= psHT->ui32Length)
+ {
+ break;
+ }
+
+ ged_hashtable_remove(psHT, ui32ID);
+ }
+
+ /* free the hash table */
+ ged_free(psHT->psHashTable, psHT->ui32Length * sizeof(struct hlist_head));
+ ged_free(psHT, sizeof(GED_HASHTABLE));
+ }
+}
+
+GED_ERROR ged_hashtable_insert(GED_HASHTABLE_HANDLE hHashTable, void* pvoid, unsigned int* pui32ID)
+{
+ GED_HASHTABLE* psHT = (GED_HASHTABLE*)hHashTable;
+ GED_HASHNODE* psHN = NULL;
+ unsigned int ui32Hash, ui32ID;
+
+ if ((!psHT) || (!pui32ID))
+ {
+ return GED_ERROR_INVALID_PARAMS;
+ }
+
+ ui32ID = psHT->ui32CurrentID + 1;
+ while(1)
+ {
+ ui32Hash = ged_hash(psHT, ui32ID);
+ psHN = __ged_hashtable_find(&psHT->psHashTable[ui32Hash], ui32ID);
+ if (psHN != NULL)
+ {
+ ui32ID++;
+ if (ui32ID == 0)//skip the value 0
+ {
+ ui32ID = 1;
+ }
+ if (ui32ID == psHT->ui32CurrentID)
+ {
+ return GED_ERROR_FAIL;
+ }
+ }
+ else
+ {
+ break;
+ }
+ };
+
+ psHN = (GED_HASHNODE*)ged_alloc(sizeof(GED_HASHNODE));
+ if (psHN)
+ {
+ psHN->pvoid = pvoid;
+ psHN->ui32ID = ui32ID;
+ psHT->ui32CurrentID = ui32ID;
+ *pui32ID = ui32ID;
+ hlist_add_head_rcu(&psHN->sNode, &psHT->psHashTable[ui32Hash]);
+ psHT->ui32Count += 1;
+ return GED_OK;
+ }
+
+ return GED_ERROR_OOM;
+}
+
+void ged_hashtable_remove(GED_HASHTABLE_HANDLE hHashTable, unsigned int ui32ID)
+{
+ GED_HASHTABLE* psHT = (GED_HASHTABLE*)hHashTable;
+ if (psHT)
+ {
+ unsigned int ui32Hash = ged_hash(psHT, ui32ID);
+ GED_HASHNODE* psHN = __ged_hashtable_find(&psHT->psHashTable[ui32Hash], ui32ID);
+ if (psHN)
+ {
+ hlist_del_rcu(&psHN->sNode);
+ synchronize_rcu();
+ ged_free(psHN, sizeof(GED_HASHNODE));
+ psHT->ui32Count -= 1;
+ }
+ }
+}
+
+void* ged_hashtable_find(GED_HASHTABLE_HANDLE hHashTable, unsigned int ui32ID)
+{
+ GED_HASHTABLE* psHT = (GED_HASHTABLE*)hHashTable;
+ if (psHT)
+ {
+ unsigned int ui32Hash = ged_hash(psHT, ui32ID);
+ GED_HASHNODE* psHN = __ged_hashtable_find(&psHT->psHashTable[ui32Hash], ui32ID);
+ if (psHN)
+ {
+ return psHN->pvoid;
+ }
+#ifdef GED_DEBUG
+ if (ui32ID != 0)
+ {
+ GED_LOGE("ged_hashtable_find: ui32ID=%u ui32Hash=%u psHN=%p\n", ui32ID, ui32Hash, psHN);
+ }
+#endif
+ }
+ return NULL;
+}
+
+GED_ERROR ged_hashtable_set(GED_HASHTABLE_HANDLE hHashTable, unsigned int ui32ID, void* pvoid)
+{
+ GED_HASHTABLE* psHT = (GED_HASHTABLE*)hHashTable;
+ if (psHT)
+ {
+ unsigned int ui32Hash = ged_hash(psHT, ui32ID);
+ GED_HASHNODE* psHN = __ged_hashtable_find(&psHT->psHashTable[ui32Hash], ui32ID);
+ if (psHN)
+ {
+ psHN->pvoid = pvoid;
+ return GED_OK;
+ }
+ }
+
+ return GED_ERROR_INVALID_PARAMS;
+}
+
diff --git a/drivers/misc/mediatek/gpu/ged/src/ged_log.c b/drivers/misc/mediatek/gpu/ged/src/ged_log.c
new file mode 100644
index 000000000..2e7b691c7
--- /dev/null
+++ b/drivers/misc/mediatek/gpu/ged/src/ged_log.c
@@ -0,0 +1,984 @@
+#include <linux/version.h>
+#include <asm/io.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/genalloc.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include <linux/xlog.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/rtc.h>
+
+#include "ged_base.h"
+#include "ged_log.h"
+#include "ged_debugFS.h"
+#include "ged_profile_dvfs.h"
+#include "ged_hashtable.h"
+
+enum
+{
+ /* 0x00 - 0xff reserved for internal buffer type */
+
+ /* rewrite the oldest log when buffer is full */
+ GED_LOG_ATTR_RINGBUFFER = 0x1,
+ /* stop logging when buffer is full */
+ GED_LOG_ATTR_QUEUEBUFFER = 0x2,
+ /* increase buffersize when buffer is full */
+ GED_LOG_ATTR_AUTO_INCREASE = 0x4,
+};
+
+typedef struct GED_LOG_BUF_LINE_TAG
+{
+ int offset;
+ int tattrs;
+ long long time;
+ long int time_usec;
+ int pid;
+ int tid;
+} GED_LOG_BUF_LINE;
+
+typedef struct GED_LOG_BUF_TAG
+{
+ GED_LOG_BUF_TYPE eType;
+ int attrs;
+
+ void *pMemory;
+ int i32MemorySize;
+
+ GED_LOG_BUF_LINE *psLine;
+ char *pcBuffer;
+ int i32LineCount;
+ int i32BufferSize;
+ int i32LineCurrent;
+ int i32BufferCurrent;
+
+ spinlock_t sSpinLock;
+ unsigned long ui32IRQFlags;
+
+ char acName[GED_LOG_BUF_NAME_LENGTH];
+ char acNodeName[GED_LOG_BUF_NODE_NAME_LENGTH];
+
+ struct dentry* psEntry;
+
+ struct list_head sList;
+
+ unsigned int ui32HashNodeID;
+
+} GED_LOG_BUF;
+
+typedef struct GED_LOG_LISTEN_TAG
+{
+ GED_LOG_BUF_HANDLE *pCBHnd;
+ char acName[GED_LOG_BUF_NAME_LENGTH];
+ struct list_head sList;
+} GED_LOG_LISTEN;
+
+typedef struct GED_LOG_BUF_LIST_TAG
+{
+ rwlock_t sLock;
+ struct list_head sList_buf;
+ struct list_head sList_listen;
+} GED_LOG_BUF_LIST;
+
+static GED_LOG_BUF_LIST gsGEDLogBufList = {
+ .sLock = __RW_LOCK_UNLOCKED(gsGEDLogBufList.sLock),
+ .sList_buf = LIST_HEAD_INIT(gsGEDLogBufList.sList_buf),
+ .sList_listen = LIST_HEAD_INIT(gsGEDLogBufList.sList_listen),
+};
+
+static struct dentry* gpsGEDLogEntry = NULL;
+static struct dentry* gpsGEDLogBufsDir = NULL;
+
+static GED_HASHTABLE_HANDLE ghHashTable = NULL;
+
+//-----------------------------------------------------------------------------
+//
+// GED Log Buf
+//
+//-----------------------------------------------------------------------------
+static GED_LOG_BUF* ged_log_buf_from_handle(GED_LOG_BUF_HANDLE hLogBuf)
+{
+ return ged_hashtable_find(ghHashTable, (unsigned int)hLogBuf);
+}
+
+static GED_ERROR __ged_log_buf_vprint(GED_LOG_BUF *psGEDLogBuf, const char *fmt, va_list args, int attrs)
+{
+ int buf_n;
+ int len;
+
+ if (!psGEDLogBuf)
+ return GED_OK;
+
+ spin_lock_irqsave(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags);
+
+ /* if OOM */
+ if (psGEDLogBuf->i32LineCurrent >= psGEDLogBuf->i32LineCount ||
+ psGEDLogBuf->i32BufferCurrent + 256 > psGEDLogBuf->i32BufferSize)
+ {
+ if (attrs & GED_LOG_ATTR_RINGBUFFER)
+ {
+ /* for ring buffer, we start over. */
+ psGEDLogBuf->i32LineCurrent = 0;
+ psGEDLogBuf->i32BufferCurrent = 0;
+ }
+ else if (attrs & GED_LOG_ATTR_QUEUEBUFFER)
+ {
+ if (attrs & GED_LOG_ATTR_AUTO_INCREASE)
+ {
+ int newLineCount, newBufferSize;
+
+ /* incease min(25%, 1MB) */
+ if ((psGEDLogBuf->i32LineCount >> 2) <= 1024 * 1024)
+ {
+ newLineCount = psGEDLogBuf->i32LineCount + (psGEDLogBuf->i32LineCount >> 2);
+ newBufferSize = psGEDLogBuf->i32BufferSize + (psGEDLogBuf->i32BufferSize >> 2);
+ }
+ else
+ {
+ newLineCount = psGEDLogBuf->i32LineCount + 4096;
+ newBufferSize = psGEDLogBuf->i32BufferSize + 1024 * 1024;
+ }
+
+ spin_unlock_irqrestore(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags);
+ if (ged_log_buf_resize(psGEDLogBuf->ui32HashNodeID, newLineCount, newBufferSize) != GED_OK)
+ {
+ return GED_ERROR_OOM;
+ }
+ spin_lock_irqsave(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags);
+ }
+ else
+ {
+ /* for queuebuffer only, we skip the log. */
+ spin_unlock_irqrestore(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags);
+ return GED_ERROR_OOM;
+ }
+ }
+ }
+
+ psGEDLogBuf->psLine[psGEDLogBuf->i32LineCurrent].offset = psGEDLogBuf->i32BufferCurrent;
+ psGEDLogBuf->psLine[psGEDLogBuf->i32LineCurrent].tattrs = 0;
+ psGEDLogBuf->psLine[psGEDLogBuf->i32LineCurrent].time = 0;
+
+ /* record the kernel time */
+ if (attrs & GED_LOG_ATTR_TIME)
+ {
+ psGEDLogBuf->psLine[psGEDLogBuf->i32LineCurrent].tattrs = GED_LOG_ATTR_TIME;
+ psGEDLogBuf->psLine[psGEDLogBuf->i32LineCurrent].time = cpu_clock(smp_processor_id());
+ }
+
+ /* record the user time */
+ if (attrs & GED_LOG_ATTR_TIME_TPT)
+ {
+ struct timeval time;
+ unsigned long local_time;
+
+ do_gettimeofday(&time);
+ local_time = (u32)(time.tv_sec - (sys_tz.tz_minuteswest * 60));
+
+ psGEDLogBuf->psLine[psGEDLogBuf->i32LineCurrent].tattrs = GED_LOG_ATTR_TIME_TPT;
+ psGEDLogBuf->psLine[psGEDLogBuf->i32LineCurrent].time = local_time;
+ psGEDLogBuf->psLine[psGEDLogBuf->i32LineCurrent].time_usec = time.tv_usec;
+ psGEDLogBuf->psLine[psGEDLogBuf->i32LineCurrent].pid = current->tgid;
+ psGEDLogBuf->psLine[psGEDLogBuf->i32LineCurrent].tid = current->pid;
+ }
+
+ buf_n = psGEDLogBuf->i32BufferSize - psGEDLogBuf->i32BufferCurrent;
+ len = vsnprintf(psGEDLogBuf->pcBuffer + psGEDLogBuf->i32BufferCurrent, buf_n, fmt, args);
+
+ if (len > buf_n) len = buf_n;
+
+ buf_n -= len;
+
+ if (attrs & GED_LOG_ATTR_RINGBUFFER)
+ {
+ int i;
+ int check = 10 + 1; /* we check the following 10 items. */
+ int a = psGEDLogBuf->i32BufferCurrent;
+ int b = psGEDLogBuf->i32BufferCurrent + len + 2;
+
+ for (i = psGEDLogBuf->i32LineCurrent+1; --check && i < psGEDLogBuf->i32LineCount; ++i)
+ {
+ int pos = psGEDLogBuf->psLine[i].offset;
+ if (pos >= a && pos < b)
+ psGEDLogBuf->psLine[i].offset = -1;
+ }
+
+ if (check && i == psGEDLogBuf->i32LineCount)
+ {
+ for (i = 0; --check && i < psGEDLogBuf->i32LineCurrent; ++i)
+ {
+ int pos = psGEDLogBuf->psLine[i].offset;
+
+ if (pos >= a && pos < b)
+ psGEDLogBuf->psLine[i].offset = -1;
+ }
+ }
+ }
+
+ /* update current */
+ psGEDLogBuf->i32BufferCurrent += len + 2;
+ psGEDLogBuf->i32LineCurrent += 1;
+
+ spin_unlock_irqrestore(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags);
+
+ return GED_OK;
+}
+
+static GED_ERROR __ged_log_buf_print(GED_LOG_BUF *psGEDLogBuf, const char *fmt, ...)
+{
+ va_list args;
+ GED_ERROR err;
+
+ va_start(args, fmt);
+ err = __ged_log_buf_vprint(psGEDLogBuf, fmt, args, psGEDLogBuf->attrs);
+ va_end(args);
+
+ return err;
+}
+
+static int __ged_log_buf_write(GED_LOG_BUF *psGEDLogBuf, const char __user *pszBuffer, int i32Count)
+{
+ int cnt;
+ char buf[256];
+
+ if (!psGEDLogBuf)
+ {
+ return 0;
+ }
+
+ cnt = (i32Count >= 256) ? 255 : i32Count;
+
+ ged_copy_from_user(buf, pszBuffer, cnt);
+
+ buf[cnt] = 0;
+
+ __ged_log_buf_print(psGEDLogBuf, buf);
+
+ return cnt;
+}
+
+static void __ged_log_buf_check_get_early_list(GED_LOG_BUF_HANDLE hLogBuf, const char *pszName)
+{
+ struct list_head *psListEntry, *psListEntryTemp, *psList;
+ GED_LOG_LISTEN *psFound = NULL, *psLogListen;
+
+ read_lock_bh(&gsGEDLogBufList.sLock);
+
+ psList = &gsGEDLogBufList.sList_listen;
+ list_for_each_safe(psListEntry, psListEntryTemp, psList)
+ {
+ psLogListen = list_entry(psListEntry, GED_LOG_LISTEN, sList);
+ if (0 == strcmp(psLogListen->acName, pszName))
+ {
+ psFound = psLogListen;
+ break;
+ }
+ }
+
+ read_unlock_bh(&gsGEDLogBufList.sLock);
+
+ if (psFound)
+ {
+ write_lock_bh(&gsGEDLogBufList.sLock);
+ *psFound->pCBHnd = hLogBuf;
+ list_del(&psFound->sList);
+ write_unlock_bh(&gsGEDLogBufList.sLock);
+ }
+}
+
+static ssize_t ged_log_buf_write_entry(const char __user *pszBuffer, size_t uiCount, loff_t uiPosition, void *pvData)
+{
+ return (ssize_t)__ged_log_buf_write((GED_LOG_BUF *)pvData, pszBuffer, (int)uiCount);
+}
+//-----------------------------------------------------------------------------
+static void* ged_log_buf_seq_start(struct seq_file *psSeqFile, loff_t *puiPosition)
+{
+ GED_LOG_BUF *psGEDLogBuf = (GED_LOG_BUF *)psSeqFile->private;
+
+ if (0 == *puiPosition)
+ {
+ return psGEDLogBuf;
+ }
+ return NULL;
+}
+//-----------------------------------------------------------------------------
+static void ged_log_buf_seq_stop(struct seq_file *psSeqFile, void *pvData)
+{
+
+}
+//-----------------------------------------------------------------------------
+static void* ged_log_buf_seq_next(struct seq_file *psSeqFile, void *pvData, loff_t *puiPosition)
+{
+ (*puiPosition)++;
+
+ return NULL;
+}
+//-----------------------------------------------------------------------------
+static int ged_log_buf_seq_show_print(struct seq_file *psSeqFile, GED_LOG_BUF *psGEDLogBuf, int i)
+{
+ int err = 0;
+ GED_LOG_BUF_LINE *line;
+
+ line = &psGEDLogBuf->psLine[i];
+
+ if (line->offset >= 0)
+ {
+ if (line->tattrs & GED_LOG_ATTR_TIME)
+ {
+ unsigned long long t;
+ unsigned long nanosec_rem;
+
+ t = line->time;
+ nanosec_rem = do_div(t, 1000000000);
+
+ seq_printf(psSeqFile,"[%5llu.%06lu] ", t, nanosec_rem / 1000);
+ }
+
+ if (line->tattrs & GED_LOG_ATTR_TIME_TPT)
+ {
+ unsigned long local_time;
+ struct rtc_time tm;
+
+ local_time = line->time;
+ rtc_time_to_tm(local_time, &tm);
+
+ seq_printf(psSeqFile,"%02d-%02d %02d:%02d:%02d.%06lu %5d %5d ",
+ /*tm.tm_year + 1900,*/ tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec,
+ line->time_usec, line->pid, line->tid);
+ }
+
+ err = seq_printf(psSeqFile, "%s\n", psGEDLogBuf->pcBuffer + line->offset);
+ }
+
+ return err;
+}
+
+static int ged_log_buf_seq_show(struct seq_file *psSeqFile, void *pvData)
+{
+ GED_LOG_BUF *psGEDLogBuf = (GED_LOG_BUF *)pvData;
+
+ if (psGEDLogBuf != NULL)
+ {
+ int i;
+
+ spin_lock_irqsave(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags);
+
+ if (psGEDLogBuf->acName[0] != '\0')
+ {
+ seq_printf(psSeqFile, "---------- %s (%d/%d) ----------\n",
+ psGEDLogBuf->acName, psGEDLogBuf->i32BufferCurrent, psGEDLogBuf->i32BufferSize);
+ }
+
+ if (psGEDLogBuf->attrs & GED_LOG_ATTR_RINGBUFFER)
+ {
+ for (i = psGEDLogBuf->i32LineCurrent; i < psGEDLogBuf->i32LineCount; ++i)
+ {
+ if (0 != ged_log_buf_seq_show_print(psSeqFile, psGEDLogBuf, i))
+ break;
+ }
+
+ //seq_printf(psSeqFile, " > ---------- start over ----------\n");
+
+ for (i = 0; i < psGEDLogBuf->i32LineCurrent; ++i)
+ {
+ if (0 != ged_log_buf_seq_show_print(psSeqFile, psGEDLogBuf, i))
+ break;
+ }
+ }
+ else if (psGEDLogBuf->attrs & GED_LOG_ATTR_QUEUEBUFFER)
+ {
+ for (i = 0; i < psGEDLogBuf->i32LineCount; ++i)
+ {
+ if (0 != ged_log_buf_seq_show_print(psSeqFile, psGEDLogBuf, i))
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags);
+ }
+
+ return 0;
+}
+//-----------------------------------------------------------------------------
+static struct seq_operations gsGEDLogBufReadOps =
+{
+ .start = ged_log_buf_seq_start,
+ .stop = ged_log_buf_seq_stop,
+ .next = ged_log_buf_seq_next,
+ .show = ged_log_buf_seq_show,
+};
+//-----------------------------------------------------------------------------
+GED_LOG_BUF_HANDLE ged_log_buf_alloc(
+ int i32MaxLineCount,
+ int i32MaxBufferSizeByte,
+ GED_LOG_BUF_TYPE eType,
+ const char* pszName,
+ const char* pszNodeName)
+{
+ GED_LOG_BUF *psGEDLogBuf;
+ GED_ERROR error;
+
+ if (((!pszName) && (!pszNodeName)) || (i32MaxLineCount <= 0) || (i32MaxBufferSizeByte <= 0))
+ {
+ return (GED_LOG_BUF_HANDLE)0;
+ }
+
+ psGEDLogBuf = (GED_LOG_BUF*)ged_alloc(sizeof(GED_LOG_BUF));
+ if (NULL == psGEDLogBuf)
+ {
+ GED_LOGE("ged: failed to allocate log buf!\n");
+ return (GED_LOG_BUF_HANDLE)0;
+ }
+
+ psGEDLogBuf->eType = eType;
+
+ switch (eType)
+ {
+ case GED_LOG_BUF_TYPE_RINGBUFFER:
+ psGEDLogBuf->attrs = GED_LOG_ATTR_RINGBUFFER;
+ break;
+ case GED_LOG_BUF_TYPE_QUEUEBUFFER:
+ psGEDLogBuf->attrs = GED_LOG_ATTR_QUEUEBUFFER;
+ break;
+ case GED_LOG_BUF_TYPE_QUEUEBUFFER_AUTO_INCREASE:
+ psGEDLogBuf->attrs = GED_LOG_ATTR_QUEUEBUFFER | GED_LOG_ATTR_AUTO_INCREASE;
+ break;
+ }
+
+ psGEDLogBuf->i32MemorySize = i32MaxBufferSizeByte + sizeof(GED_LOG_BUF_LINE) * i32MaxLineCount;
+ psGEDLogBuf->pMemory = ged_alloc(psGEDLogBuf->i32MemorySize);
+ if (NULL == psGEDLogBuf->pMemory)
+ {
+ ged_free(psGEDLogBuf, sizeof(GED_LOG_BUF));
+ GED_LOGE("ged: failed to allocate log buf!\n");
+ return (GED_LOG_BUF_HANDLE)0;
+ }
+
+ psGEDLogBuf->psLine = (GED_LOG_BUF_LINE *)psGEDLogBuf->pMemory;
+ psGEDLogBuf->pcBuffer = (char *)&psGEDLogBuf->psLine[i32MaxLineCount];
+ psGEDLogBuf->i32LineCount = i32MaxLineCount;
+ psGEDLogBuf->i32BufferSize = i32MaxBufferSizeByte;
+ psGEDLogBuf->i32LineCurrent = 0;
+ psGEDLogBuf->i32BufferCurrent = 0;
+
+ psGEDLogBuf->psEntry = NULL;
+ spin_lock_init(&psGEDLogBuf->sSpinLock);
+ psGEDLogBuf->acName[0] = '\0';
+ psGEDLogBuf->acNodeName[0] = '\0';
+
+ /* Init Line */
+ {
+ int i = 0;
+ for (i = 0; i < psGEDLogBuf->i32LineCount; ++i)
+ psGEDLogBuf->psLine[i].offset = -1;
+ }
+
+ if (pszName)
+ {
+ snprintf(psGEDLogBuf->acName, GED_LOG_BUF_NAME_LENGTH, "%s", pszName);
+ }
+
+ // Add into the global list
+ INIT_LIST_HEAD(&psGEDLogBuf->sList);
+ write_lock_bh(&gsGEDLogBufList.sLock);
+ list_add(&psGEDLogBuf->sList, &gsGEDLogBufList.sList_buf);
+ write_unlock_bh(&gsGEDLogBufList.sLock);
+
+ if (pszNodeName)
+ {
+ int err;
+ snprintf(psGEDLogBuf->acNodeName, GED_LOG_BUF_NODE_NAME_LENGTH, "%s", pszNodeName);
+ err = ged_debugFS_create_entry(
+ psGEDLogBuf->acNodeName,
+ gpsGEDLogBufsDir,
+ &gsGEDLogBufReadOps,
+ ged_log_buf_write_entry,
+ psGEDLogBuf,
+ &psGEDLogBuf->psEntry);
+
+ if (unlikely(err))
+ {
+ GED_LOGE("ged: failed to create %s entry, err(%d)!\n", pszNodeName, err);
+ ged_log_buf_free(psGEDLogBuf->ui32HashNodeID);
+ return (GED_LOG_BUF_HANDLE)0;
+ }
+ }
+
+ error = ged_hashtable_insert(ghHashTable, psGEDLogBuf, &psGEDLogBuf->ui32HashNodeID);
+ if (GED_OK != error)
+ {
+ GED_LOGE("ged: failed to insert into a hash table, err(%d)!\n", error);
+ ged_log_buf_free(psGEDLogBuf->ui32HashNodeID);
+ return (GED_LOG_BUF_HANDLE)0;
+ }
+
+ GED_LOGI("ged_log_buf_alloc OK\n");
+
+ __ged_log_buf_check_get_early_list(psGEDLogBuf->ui32HashNodeID, pszName);
+
+ return (GED_LOG_BUF_HANDLE)psGEDLogBuf->ui32HashNodeID;
+}
+
+GED_ERROR ged_log_buf_resize(
+ GED_LOG_BUF_HANDLE hLogBuf,
+ int i32NewMaxLineCount,
+ int i32NewMaxBufferSizeByte)
+{
+ int i;
+ GED_LOG_BUF *psGEDLogBuf = ged_log_buf_from_handle(hLogBuf);
+ int i32NewMemorySize, i32OldMemorySize;
+ void *pNewMemory, *pOldMemory;
+ GED_LOG_BUF_LINE *pi32NewLine;
+ char *pcNewBuffer;
+
+ if ((NULL == psGEDLogBuf) || (i32NewMaxLineCount <= 0) || (i32NewMaxBufferSizeByte <= 0))
+ {
+ return GED_ERROR_INVALID_PARAMS;
+ }
+
+ i32NewMemorySize = i32NewMaxBufferSizeByte + sizeof(GED_LOG_BUF_LINE) * i32NewMaxLineCount;
+ pNewMemory = ged_alloc(i32NewMemorySize);
+ if (NULL == pNewMemory)
+ {
+ return GED_ERROR_OOM;
+ }
+
+ spin_lock_irqsave(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags);
+
+ pi32NewLine = (GED_LOG_BUF_LINE *)pNewMemory;
+ pcNewBuffer = (char *)&pi32NewLine[i32NewMaxLineCount];
+
+ memcpy(pi32NewLine, psGEDLogBuf->psLine, sizeof(GED_LOG_BUF_LINE) * min(i32NewMaxLineCount, psGEDLogBuf->i32LineCount));
+ memcpy(pcNewBuffer, psGEDLogBuf->pcBuffer, min(i32NewMaxBufferSizeByte, psGEDLogBuf->i32BufferSize));
+
+ for (i = psGEDLogBuf->i32LineCount; i < i32NewMaxLineCount; ++i)
+ pi32NewLine[i].offset = -1;
+
+ i32OldMemorySize = psGEDLogBuf->i32MemorySize;
+ pOldMemory = psGEDLogBuf->pMemory;
+
+ psGEDLogBuf->i32MemorySize = i32NewMemorySize;
+ psGEDLogBuf->pMemory = pNewMemory;
+ psGEDLogBuf->psLine = pi32NewLine;
+ psGEDLogBuf->pcBuffer = pcNewBuffer;
+ psGEDLogBuf->i32LineCount = i32NewMaxLineCount;
+ psGEDLogBuf->i32BufferSize = i32NewMaxBufferSizeByte;
+
+ if (psGEDLogBuf->i32BufferCurrent >= i32NewMaxBufferSizeByte)
+ psGEDLogBuf->i32BufferCurrent = i32NewMaxBufferSizeByte - 1;
+ pcNewBuffer[psGEDLogBuf->i32BufferCurrent] = 0;
+
+ spin_unlock_irqrestore(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags);
+ ged_free(pOldMemory, i32OldMemorySize);
+
+ return GED_OK;
+}
+
+GED_ERROR ged_log_buf_ignore_lines(GED_LOG_BUF_HANDLE hLogBuf, int n)
+{
+ GED_LOG_BUF *psGEDLogBuf = ged_log_buf_from_handle(hLogBuf);
+
+ if (psGEDLogBuf && n > 0)
+ {
+ if (psGEDLogBuf->attrs & GED_LOG_ATTR_QUEUEBUFFER)
+ {
+ if (n >= psGEDLogBuf->i32LineCurrent)
+ {
+ /* reset all buffer */
+ ged_log_buf_reset(hLogBuf);
+ }
+ else
+ {
+ int i;
+ int buf_offset;
+ int buf_size;
+
+ spin_lock_irqsave(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags);
+
+ buf_offset = psGEDLogBuf->psLine[n].offset;
+ buf_size = psGEDLogBuf->i32BufferCurrent - buf_offset;
+
+ /* Move lines, update offset and update current */
+ for (i = 0; n + i < psGEDLogBuf->i32LineCount; ++i)
+ {
+ psGEDLogBuf->psLine[i] = psGEDLogBuf->psLine[n + i];
+ psGEDLogBuf->psLine[i].offset -= buf_offset;
+ }
+ psGEDLogBuf->i32LineCurrent -= n;
+
+ /* Move buffers and update current */
+ for (i = 0; i < buf_size; ++i)
+ psGEDLogBuf->pcBuffer[i] = psGEDLogBuf->pcBuffer[buf_offset + i];
+ psGEDLogBuf->i32BufferCurrent = buf_size;
+
+ spin_unlock_irqrestore(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags);
+ }
+ }
+ }
+
+ return GED_OK;
+}
+
+GED_LOG_BUF_HANDLE ged_log_buf_get(const char* pszName)
+{
+ struct list_head *psListEntry, *psListEntryTemp, *psList;
+ GED_LOG_BUF *psFound = NULL, *psLogBuf;
+
+ if (!pszName)
+ {
+ return (GED_LOG_BUF_HANDLE)0;
+ }
+
+ read_lock_bh(&gsGEDLogBufList.sLock);
+
+ psList = &gsGEDLogBufList.sList_buf;
+ list_for_each_safe(psListEntry, psListEntryTemp, psList)
+ {
+ psLogBuf = list_entry(psListEntry, GED_LOG_BUF, sList);
+ if (0 == strcmp(psLogBuf->acName, pszName))
+ {
+ psFound = psLogBuf;
+ break;
+ }
+ }
+
+ read_unlock_bh(&gsGEDLogBufList.sLock);
+
+ if (!psFound)
+ {
+ return (GED_LOG_BUF_HANDLE)0;
+ }
+
+ return (GED_LOG_BUF_HANDLE)psFound->ui32HashNodeID;
+}
+
+int ged_log_buf_get_early(const char* pszName, GED_LOG_BUF_HANDLE *callback_set_handle)
+{
+ int err = 0;
+
+ if (NULL == pszName)
+ {
+ return GED_ERROR_INVALID_PARAMS;
+ }
+
+ *callback_set_handle = ged_log_buf_get(pszName);
+
+ if (0 == *callback_set_handle)
+ {
+ GED_LOG_LISTEN *psGEDLogListen;
+
+ write_lock_bh(&gsGEDLogBufList.sLock);
+
+ /* search again */
+ {
+ struct list_head *psListEntry, *psListEntryTemp, *psList;
+ GED_LOG_BUF *psFound = NULL, *psLogBuf;
+
+ psList = &gsGEDLogBufList.sList_buf;
+ list_for_each_safe(psListEntry, psListEntryTemp, psList)
+ {
+ psLogBuf = list_entry(psListEntry, GED_LOG_BUF, sList);
+ if (0 == strcmp(psLogBuf->acName, pszName))
+ {
+ psFound = psLogBuf;
+ break;
+ }
+ }
+
+ if (psFound)
+ {
+ *callback_set_handle = (GED_LOG_BUF_HANDLE)psFound->ui32HashNodeID;
+ goto exit_unlock;
+ }
+ }
+
+ /* add to listen list */
+ psGEDLogListen = (GED_LOG_LISTEN*)ged_alloc(sizeof(GED_LOG_LISTEN));
+ if (NULL == psGEDLogListen)
+ {
+ err = GED_ERROR_OOM;
+ goto exit_unlock;
+ }
+ psGEDLogListen->pCBHnd = callback_set_handle;
+ snprintf(psGEDLogListen->acName, GED_LOG_BUF_NAME_LENGTH, "%s", pszName);
+ INIT_LIST_HEAD(&psGEDLogListen->sList);
+ list_add(&psGEDLogListen->sList, &gsGEDLogBufList.sList_listen);
+
+exit_unlock:
+ write_unlock_bh(&gsGEDLogBufList.sLock);
+ }
+
+ return err;
+}
+
+//-----------------------------------------------------------------------------
+void ged_log_buf_free(GED_LOG_BUF_HANDLE hLogBuf)
+{
+ GED_LOG_BUF *psGEDLogBuf = ged_log_buf_from_handle(hLogBuf);
+ if (psGEDLogBuf)
+ {
+ ged_hashtable_remove(ghHashTable, psGEDLogBuf->ui32HashNodeID);
+
+ write_lock_bh(&gsGEDLogBufList.sLock);
+ list_del(&psGEDLogBuf->sList);
+ write_unlock_bh(&gsGEDLogBufList.sLock);
+
+ if (psGEDLogBuf->psEntry)
+ {
+ ged_debugFS_remove_entry(psGEDLogBuf->psEntry);
+ }
+
+ ged_free(psGEDLogBuf->pMemory, psGEDLogBuf->i32MemorySize);
+ ged_free(psGEDLogBuf, sizeof(GED_LOG_BUF));
+
+ GED_LOGI("ged_log_buf_free OK\n");
+ }
+}
+//-----------------------------------------------------------------------------
+GED_ERROR ged_log_buf_print(GED_LOG_BUF_HANDLE hLogBuf, const char *fmt, ...)
+{
+ va_list args;
+ GED_ERROR err;
+ GED_LOG_BUF *psGEDLogBuf;
+
+ if (hLogBuf)
+ {
+ psGEDLogBuf = ged_log_buf_from_handle(hLogBuf);
+
+ va_start(args, fmt);
+ err = __ged_log_buf_vprint(psGEDLogBuf, fmt, args, psGEDLogBuf->attrs);
+ va_end(args);
+ }
+
+ return GED_OK;
+}
+GED_ERROR ged_log_buf_print2(GED_LOG_BUF_HANDLE hLogBuf, int i32LogAttrs, const char *fmt, ...)
+{
+ va_list args;
+ GED_ERROR err;
+ GED_LOG_BUF *psGEDLogBuf;
+
+ if (hLogBuf)
+ {
+ psGEDLogBuf = ged_log_buf_from_handle(hLogBuf);
+
+ /* clear reserved attrs */
+ i32LogAttrs &= ~0xff;
+
+ va_start(args, fmt);
+ err = __ged_log_buf_vprint(psGEDLogBuf, fmt, args, psGEDLogBuf->attrs | i32LogAttrs);
+ va_end(args);
+ }
+
+ return GED_OK;
+}
+//-----------------------------------------------------------------------------
+GED_ERROR ged_log_buf_reset(GED_LOG_BUF_HANDLE hLogBuf)
+{
+ GED_LOG_BUF *psGEDLogBuf = ged_log_buf_from_handle(hLogBuf);
+ if (psGEDLogBuf)
+ {
+ int i;
+ spin_lock_irqsave(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags);
+
+ psGEDLogBuf->i32LineCurrent = 0;
+ psGEDLogBuf->i32BufferCurrent = 0;
+ for (i = 0; i < psGEDLogBuf->i32LineCount; ++i)
+ {
+ psGEDLogBuf->psLine[i].offset = -1;
+ }
+
+ spin_unlock_irqrestore(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags);
+ }
+
+ return GED_OK;
+}
+
+//-----------------------------------------------------------------------------
+//
+// GED Log System
+//
+//-----------------------------------------------------------------------------
+static ssize_t ged_log_write_entry(const char __user *pszBuffer, size_t uiCount, loff_t uiPosition, void *pvData)
+{
+#define GED_LOG_CMD_SIZE 64
+ char acBuffer[GED_LOG_CMD_SIZE];
+
+ int i32Value;
+
+ if ((0 < uiCount) && (uiCount < GED_LOG_CMD_SIZE))
+ {
+ if (0 == ged_copy_from_user(acBuffer, pszBuffer, uiCount))
+ {
+ acBuffer[uiCount - 1] = '\0';
+ if (strcmp(acBuffer, "reset") == 0)
+ {
+ struct list_head *psListEntry, *psListEntryTemp, *psList;
+ write_lock_bh(&gsGEDLogBufList.sLock);
+ psList = &gsGEDLogBufList.sList_buf;
+ list_for_each_safe(psListEntry, psListEntryTemp, psList)
+ {
+ GED_LOG_BUF* psGEDLogBuf = (GED_LOG_BUF*)list_entry(psListEntry, GED_LOG_BUF, sList);
+ ged_log_buf_reset(psGEDLogBuf->ui32HashNodeID);
+ }
+ write_unlock_bh(&gsGEDLogBufList.sLock);
+ }
+ else if (strcmp(acBuffer, "profile_dvfs_enable") == 0)
+ {
+ ged_profile_dvfs_enable();
+ }
+ else if (strcmp(acBuffer, "profile_dvfs_disable") == 0)
+ {
+ ged_profile_dvfs_disable();
+ }
+ else if (strcmp(acBuffer, "profile_dvfs_start") == 0)
+ {
+ ged_profile_dvfs_start();
+ }
+ else if (strcmp(acBuffer, "profile_dvfs_stop") == 0)
+ {
+ ged_profile_dvfs_stop();
+ }
+ else if (sscanf(acBuffer, "profile_dvfs_ignore_lines %d", &i32Value) == 1)
+ {
+ ged_profile_dvfs_ignore_lines(i32Value);
+ }
+ //else if (...) //for other commands
+ //{
+ //}
+ }
+ }
+
+ return uiCount;
+}
+//-----------------------------------------------------------------------------
+static void* ged_log_seq_start(struct seq_file *psSeqFile, loff_t *puiPosition)
+{
+ struct list_head *psListEntry, *psListEntryTemp, *psList;
+ loff_t uiCurrentPosition = 0;
+
+ read_lock_bh(&gsGEDLogBufList.sLock);
+
+ psList = &gsGEDLogBufList.sList_buf;
+ list_for_each_safe(psListEntry, psListEntryTemp, psList)
+ {
+ GED_LOG_BUF* psGEDLogBuf = (GED_LOG_BUF*)list_entry(psListEntry, GED_LOG_BUF, sList);
+ if (psGEDLogBuf->acName[0] != '\0')
+ {
+ if (uiCurrentPosition == *puiPosition)
+ {
+ return psGEDLogBuf;
+ }
+ uiCurrentPosition ++;
+ }
+ }
+
+ return NULL;
+}
+//-----------------------------------------------------------------------------
+static void ged_log_seq_stop(struct seq_file *psSeqFile, void *pvData)
+{
+ read_unlock_bh(&gsGEDLogBufList.sLock);
+}
+//-----------------------------------------------------------------------------
+static void* ged_log_seq_next(struct seq_file *psSeqFile, void *pvData, loff_t *puiPosition)
+{
+ struct list_head *psListEntry, *psListEntryTemp, *psList;
+ loff_t uiCurrentPosition = 0;
+
+ (*puiPosition)++;
+
+ psList = &gsGEDLogBufList.sList_buf;
+ list_for_each_safe(psListEntry, psListEntryTemp, psList)
+ {
+ GED_LOG_BUF* psGEDLogBuf = (GED_LOG_BUF*)list_entry(psListEntry, GED_LOG_BUF, sList);
+ if (psGEDLogBuf->acName[0] != '\0')
+ {
+ if (uiCurrentPosition == *puiPosition)
+ {
+ return psGEDLogBuf;
+ }
+ uiCurrentPosition ++;
+ }
+ }
+
+ return NULL;
+}
+//-----------------------------------------------------------------------------
+static struct seq_operations gsGEDLogReadOps =
+{
+ .start = ged_log_seq_start,
+ .stop = ged_log_seq_stop,
+ .next = ged_log_seq_next,
+ .show = ged_log_buf_seq_show,
+};
+//-----------------------------------------------------------------------------
+GED_ERROR ged_log_system_init(void)
+{
+ GED_ERROR err = GED_OK;
+
+ err = ged_debugFS_create_entry(
+ "gedlog",
+ NULL,
+ &gsGEDLogReadOps,
+ ged_log_write_entry,
+ NULL,
+ &gpsGEDLogEntry);
+
+ if (unlikely(err != GED_OK))
+ {
+ GED_LOGE("ged: failed to create gedlog entry!\n");
+ goto ERROR;
+ }
+
+ err = ged_debugFS_create_entry_dir(
+ "logbufs",
+ NULL,
+ &gpsGEDLogBufsDir);
+
+ if (unlikely(err != GED_OK))
+ {
+ err = GED_ERROR_FAIL;
+ GED_LOGE("ged: failed to create logbufs dir!\n");
+ goto ERROR;
+ }
+
+ ghHashTable = ged_hashtable_create(5);
+ if (!ghHashTable)
+ {
+ err = GED_ERROR_OOM;
+ GED_LOGE("ged: failed to create a hash table!\n");
+ goto ERROR;
+ }
+
+ return err;
+
+ERROR:
+
+ ged_log_system_exit();
+
+ return err;
+}
+//-----------------------------------------------------------------------------
+void ged_log_system_exit(void)
+{
+ ged_hashtable_destroy(ghHashTable);
+
+ ged_debugFS_remove_entry(gpsGEDLogEntry);
+}
+//-----------------------------------------------------------------------------
+int ged_log_buf_write(GED_LOG_BUF_HANDLE hLogBuf, const char __user *pszBuffer, int i32Count)
+{
+ GED_LOG_BUF *psGEDLogBuf = ged_log_buf_from_handle(hLogBuf);
+ return __ged_log_buf_write(psGEDLogBuf, pszBuffer, i32Count);
+}
+
+EXPORT_SYMBOL(ged_log_buf_alloc);
+EXPORT_SYMBOL(ged_log_buf_reset);
+EXPORT_SYMBOL(ged_log_buf_get);
+EXPORT_SYMBOL(ged_log_buf_get_early);
+EXPORT_SYMBOL(ged_log_buf_free);
+EXPORT_SYMBOL(ged_log_buf_print);
+EXPORT_SYMBOL(ged_log_buf_print2);
diff --git a/drivers/misc/mediatek/gpu/ged/src/ged_main.c b/drivers/misc/mediatek/gpu/ged/src/ged_main.c
new file mode 100644
index 000000000..eff199d18
--- /dev/null
+++ b/drivers/misc/mediatek/gpu/ged/src/ged_main.c
@@ -0,0 +1,338 @@
+/*
+ * (C) Copyright 2010
+ * MediaTek <www.MediaTek.com>
+ *
+ * MTK GPU Extension Device
+ *
+ */
+
+#include <linux/cdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/hardirq.h>
+#include <linux/init.h>
+#include <linux/kallsyms.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+#include <linux/disp_assert_layer.h>
+#include <mach/system.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/semaphore.h>
+#include <linux/workqueue.h>
+#include <linux/kthread.h>
+#include <linux/aee.h>
+
+#include "ged_debugFS.h"
+#include "ged_log.h"
+#include "ged_hal.h"
+#include "ged_bridge.h"
+#include "ged_profile_dvfs.h"
+#include "ged_monitor_3D_fence.h"
+
+#define GED_DRIVER_DEVICE_NAME "ged"
+
+#define GED_IOCTL_PARAM_BUF_SIZE 0x3000 //12KB
+
+#ifdef GED_DEBUG
+#define GED_LOG_BUF_COMMON_FENCE "FENCE"
+static GED_LOG_BUF_HANDLE ghLogBuf_FENCE = 0;
+#define GED_LOG_BUF_COMMON_GLES "GLES"
+static GED_LOG_BUF_HANDLE ghLogBuf_GLES = 0;
+GED_LOG_BUF_HANDLE ghLogBuf_GED = 0;
+#endif
+
+static void* gvIOCTLParamBuf = NULL;
+
+/******************************************************************************
+ * GED File operations
+ *****************************************************************************/
+static int ged_open(struct inode *inode, struct file *filp)
+{
+ GED_LOGE("%s:%d:%d\n", __func__, MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
+ return 0;
+}
+
+static int ged_release(struct inode *inode, struct file *filp)
+{
+ GED_LOGE("%s:%d:%d\n", __func__, MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
+ return 0;
+}
+
+static unsigned int ged_poll(struct file *file, struct poll_table_struct *ptable)
+{
+ return 0;
+}
+
+static ssize_t ged_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
+{
+ return 0;
+}
+
+static ssize_t ged_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
+{
+ return 0;
+}
+
+static long ged_dispatch(GED_BRIDGE_PACKAGE *psBridgePackageKM)
+{
+ int ret = -EFAULT;
+ void *pvInt, *pvOut;
+ typedef int (ged_bridge_func_type)(void*, void*);
+ ged_bridge_func_type* pFunc = NULL;
+
+ if ((psBridgePackageKM->i32InBufferSize >=0) && (psBridgePackageKM->i32OutBufferSize >=0) &&
+ (psBridgePackageKM->i32InBufferSize + psBridgePackageKM->i32OutBufferSize < GED_IOCTL_PARAM_BUF_SIZE))
+ {
+ pvInt = gvIOCTLParamBuf;
+ pvOut = (void*)((char*)pvInt + (uintptr_t)psBridgePackageKM->i32InBufferSize);
+ if (psBridgePackageKM->i32InBufferSize > 0)
+ {
+ if (0 != ged_copy_from_user(pvInt, psBridgePackageKM->pvParamIn, psBridgePackageKM->i32InBufferSize))
+ {
+ GED_LOGE("ged_copy_from_user fail\n");
+ return ret;
+ }
+ }
+
+ // we will change the below switch into a function pointer mapping table in the future
+ switch(GED_GET_BRIDGE_ID(psBridgePackageKM->ui32FunctionID))
+ {
+ case GED_BRIDGE_COMMAND_LOG_BUF_GET:
+ pFunc = (ged_bridge_func_type*)ged_bridge_log_buf_get;
+ break;
+ case GED_BRIDGE_COMMAND_LOG_BUF_WRITE:
+ pFunc = (ged_bridge_func_type*)ged_bridge_log_buf_write;
+ break;
+ case GED_BRIDGE_COMMAND_LOG_BUF_RESET:
+ pFunc = (ged_bridge_func_type*)ged_bridge_log_buf_reset;
+ break;
+ case GED_BRIDGE_COMMAND_BOOST_GPU_FREQ:
+ pFunc = (ged_bridge_func_type*)ged_bridge_boost_gpu_freq;
+ break;
+ case GED_BRIDGE_COMMAND_MONITOR_3D_FENCE:
+ pFunc = (ged_bridge_func_type*)ged_bridge_monitor_3D_fence;
+ break;
+ default:
+ GED_LOGE("Unknown Bridge ID: %u\n", GED_GET_BRIDGE_ID(psBridgePackageKM->ui32FunctionID));
+ break;
+ }
+
+ if (pFunc)
+ {
+ ret = pFunc(pvInt, pvOut);
+ }
+
+ if (psBridgePackageKM->i32OutBufferSize > 0)
+ {
+ if (0 != ged_copy_to_user(psBridgePackageKM->pvParamOut, pvOut, psBridgePackageKM->i32OutBufferSize))
+ {
+ return ret;
+ }
+ }
+ }
+
+ return ret;
+}
+
+DEFINE_SEMAPHORE(ged_dal_sem);
+
+static long ged_ioctl(struct file *pFile, unsigned int ioctlCmd, unsigned long arg)
+{
+ int ret = -EFAULT;
+ GED_BRIDGE_PACKAGE *psBridgePackageKM, *psBridgePackageUM = (GED_BRIDGE_PACKAGE*)arg;
+ GED_BRIDGE_PACKAGE sBridgePackageKM;
+
+ if (down_interruptible(&ged_dal_sem) < 0)
+ {
+ GED_LOGE("Fail to down ged_dal_sem\n");
+ return -ERESTARTSYS;
+ }
+
+ psBridgePackageKM = &sBridgePackageKM;
+ if (0 != ged_copy_from_user(psBridgePackageKM, psBridgePackageUM, sizeof(GED_BRIDGE_PACKAGE)))
+ {
+ GED_LOGE("Fail to ged_copy_from_user\n");
+ goto unlock_and_return;
+ }
+
+ ret = ged_dispatch(psBridgePackageKM);
+
+unlock_and_return:
+ up(&ged_dal_sem);
+
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static long ged_ioctl_compat(struct file *pFile, unsigned int ioctlCmd, unsigned long arg)
+{
+ typedef struct GED_BRIDGE_PACKAGE_32_TAG
+ {
+ unsigned int ui32FunctionID;
+ int i32Size;
+ unsigned int ui32ParamIn;
+ int i32InBufferSize;
+ unsigned int ui32ParamOut;
+ int i32OutBufferSize;
+ } GED_BRIDGE_PACKAGE_32;
+
+ int ret = -EFAULT;
+ GED_BRIDGE_PACKAGE sBridgePackageKM64;
+ GED_BRIDGE_PACKAGE_32 sBridgePackageKM32;
+ GED_BRIDGE_PACKAGE_32 *psBridgePackageKM32 = &sBridgePackageKM32;
+ GED_BRIDGE_PACKAGE_32 *psBridgePackageUM32 = (GED_BRIDGE_PACKAGE_32*)arg;
+
+ if (down_interruptible(&ged_dal_sem) < 0)
+ {
+ GED_LOGE("Fail to down ged_dal_sem\n");
+ return -ERESTARTSYS;
+ }
+
+ if (0 != ged_copy_from_user(psBridgePackageKM32, psBridgePackageUM32, sizeof(GED_BRIDGE_PACKAGE_32)))
+ {
+ GED_LOGE("Fail to ged_copy_from_user\n");
+ goto unlock_and_return;
+ }
+
+ sBridgePackageKM64.ui32FunctionID = psBridgePackageKM32->ui32FunctionID;
+ sBridgePackageKM64.i32Size = sizeof(GED_BRIDGE_PACKAGE);
+ sBridgePackageKM64.pvParamIn = (void*) ((size_t) psBridgePackageKM32->ui32ParamIn);
+ sBridgePackageKM64.pvParamOut = (void*) ((size_t) psBridgePackageKM32->ui32ParamOut);
+ sBridgePackageKM64.i32InBufferSize = psBridgePackageKM32->i32InBufferSize;
+ sBridgePackageKM64.i32OutBufferSize = psBridgePackageKM32->i32OutBufferSize;
+
+ ret = ged_dispatch(&sBridgePackageKM64);
+
+unlock_and_return:
+ up(&ged_dal_sem);
+
+ return ret;
+}
+#endif
+
+/******************************************************************************
+ * Module related
+ *****************************************************************************/
+
+static struct file_operations ged_fops = {
+ .owner = THIS_MODULE,
+ .open = ged_open,
+ .release = ged_release,
+ .poll = ged_poll,
+ .read = ged_read,
+ .write = ged_write,
+ .unlocked_ioctl = ged_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ged_ioctl_compat,
+#endif
+};
+
+#if 0
+static struct miscdevice ged_dev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "ged",
+ .fops = &ged_fops,
+};
+#endif
+
+static void ged_exit(void)
+{
+#ifdef GED_DEBUG
+ ged_log_buf_free(ghLogBuf_GED);
+ ghLogBuf_GED = 0;
+ ged_log_buf_free(ghLogBuf_GLES);
+ ghLogBuf_GLES = 0;
+ ged_log_buf_free(ghLogBuf_FENCE);
+ ghLogBuf_FENCE = 0;
+#endif
+
+ ged_profile_dvfs_exit();
+
+ ged_hal_exit();
+
+ ged_log_system_exit();
+
+ ged_debugFS_exit();
+
+ remove_proc_entry(GED_DRIVER_DEVICE_NAME, NULL);
+
+ if (gvIOCTLParamBuf)
+ {
+ vfree(gvIOCTLParamBuf);
+ gvIOCTLParamBuf = NULL;
+ }
+}
+
+static int ged_init(void)
+{
+ GED_ERROR err = GED_ERROR_FAIL;
+
+ gvIOCTLParamBuf = vmalloc(GED_IOCTL_PARAM_BUF_SIZE);
+ if (NULL == gvIOCTLParamBuf)
+ {
+ err = GED_ERROR_OOM;
+ goto ERROR;
+ }
+
+ if (NULL == proc_create(GED_DRIVER_DEVICE_NAME, 0644, NULL, &ged_fops))
+ {
+ err = GED_ERROR_FAIL;
+ GED_LOGE("ged: failed to register ged proc entry!\n");
+ goto ERROR;
+ }
+
+ err = ged_debugFS_init();
+ if (unlikely(err != GED_OK))
+ {
+ GED_LOGE("ged: failed to init debug FS!\n");
+ goto ERROR;
+ }
+
+ err = ged_log_system_init();
+ if (unlikely(err != GED_OK))
+ {
+ GED_LOGE("ged: failed to create gedlog entry!\n");
+ goto ERROR;
+ }
+
+ err = ged_hal_init();
+ if (unlikely(err != GED_OK))
+ {
+ GED_LOGE("ged: failed to create hal entry!\n");
+ goto ERROR;
+ }
+
+ err = ged_profile_dvfs_init();
+ if (unlikely(err != GED_OK))
+ {
+ GED_LOGE("ged: failed to init profile dvfs!\n");
+ goto ERROR;
+ }
+
+#ifdef GED_DEBUG
+ ghLogBuf_FENCE = ged_log_buf_alloc(256, 128 * 256, GED_LOG_BUF_TYPE_RINGBUFFER, GED_LOG_BUF_COMMON_FENCE, NULL);
+ ghLogBuf_GLES = ged_log_buf_alloc(160, 128 * 160, GED_LOG_BUF_TYPE_RINGBUFFER, GED_LOG_BUF_COMMON_GLES, NULL);
+ ghLogBuf_GED = ged_log_buf_alloc(32, 64 * 32, GED_LOG_BUF_TYPE_RINGBUFFER, "GED internal", NULL);
+#endif
+
+ return 0;
+
+ERROR:
+ ged_exit();
+
+ return -EFAULT;
+}
+
+module_init(ged_init);
+module_exit(ged_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MediaTek GED Driver");
+MODULE_AUTHOR("MediaTek Inc.");
diff --git a/drivers/misc/mediatek/gpu/ged/src/ged_monitor_3D_fence.c b/drivers/misc/mediatek/gpu/ged/src/ged_monitor_3D_fence.c
new file mode 100644
index 000000000..b953a2b44
--- /dev/null
+++ b/drivers/misc/mediatek/gpu/ged/src/ged_monitor_3D_fence.c
@@ -0,0 +1,141 @@
+#include <linux/version.h>
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <asm/atomic.h>
+#include <linux/module.h>
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0))
+#include <linux/sync.h>
+#else
+#include <../drivers/staging/android/sync.h>
+#endif
+
+#include <linux/mtk_gpu_utility.h>
+#include <trace/events/gpu.h>
+#include "ged_monitor_3D_fence.h"
+#include "ged_log.h"
+#include "ged_base.h"
+
+static atomic_t g_i32Count = ATOMIC_INIT(0);
+static unsigned int ged_monitor_3D_fence_debug = 0;
+static unsigned int ged_monitor_3D_fence_disable = 0;
+static unsigned int ged_monitor_3D_fence_systrace = 0;
+
+#ifdef GED_DEBUG_MONITOR_3D_FENCE
+extern GED_LOG_BUF_HANDLE ghLogBuf_GED;
+#endif
+
+typedef struct GED_MONITOR_3D_FENCE_TAG
+{
+ struct sync_fence_waiter sSyncWaiter;
+ struct work_struct sWork;
+ struct sync_fence* psSyncFence;
+} GED_MONITOR_3D_FENCE;
+
+static void ged_sync_cb(struct sync_fence *fence, struct sync_fence_waiter *waiter)
+{
+ GED_MONITOR_3D_FENCE *psMonitor;
+ psMonitor = GED_CONTAINER_OF(waiter, GED_MONITOR_3D_FENCE, sSyncWaiter);
+ schedule_work(&psMonitor->sWork);
+}
+
+static void ged_monitor_3D_fence_work_cb(struct work_struct *psWork)
+{
+ GED_MONITOR_3D_FENCE *psMonitor;
+
+ if (atomic_sub_return(1, &g_i32Count) < 1)
+ {
+ if (0 == ged_monitor_3D_fence_disable)
+ {
+ //unsigned int uiFreqLevelID;
+ //if (mtk_get_bottom_gpu_freq(&uiFreqLevelID))
+ {
+ //if (uiFreqLevelID > 0)
+ {
+ mtk_set_bottom_gpu_freq(0);
+#ifdef CONFIG_GPU_TRACEPOINTS
+ if (ged_monitor_3D_fence_systrace)
+ {
+ unsigned long long t = cpu_clock(smp_processor_id());
+ trace_gpu_sched_switch("Smart Boost", t, 0, 0, 1);
+ }
+#endif
+ }
+ }
+ }
+ }
+
+ if (ged_monitor_3D_fence_debug > 0)
+ {
+ GED_LOGI("[-]3D fences count = %d\n", atomic_read(&g_i32Count));
+ }
+
+ psMonitor = GED_CONTAINER_OF(psWork, GED_MONITOR_3D_FENCE, sWork);
+ sync_fence_put(psMonitor->psSyncFence);
+ ged_free(psMonitor, sizeof(GED_MONITOR_3D_FENCE));
+}
+
+GED_ERROR ged_monitor_3D_fence_add(int fence_fd)
+{
+ int err;
+ GED_MONITOR_3D_FENCE* psMonitor;
+
+ psMonitor = (GED_MONITOR_3D_FENCE*)ged_alloc(sizeof(GED_MONITOR_3D_FENCE));
+ if (!psMonitor)
+ {
+ return GED_ERROR_OOM;
+ }
+
+ sync_fence_waiter_init(&psMonitor->sSyncWaiter, ged_sync_cb);
+ INIT_WORK(&psMonitor->sWork, ged_monitor_3D_fence_work_cb);
+ psMonitor->psSyncFence = sync_fence_fdget(fence_fd);
+ if (NULL == psMonitor->psSyncFence)
+ {
+ ged_free(psMonitor, sizeof(GED_MONITOR_3D_FENCE));
+ return GED_ERROR_INVALID_PARAMS;
+ }
+
+ err = sync_fence_wait_async(psMonitor->psSyncFence, &psMonitor->sSyncWaiter);
+
+ if ((1 == err) || (0 > err))
+ {
+ sync_fence_put(psMonitor->psSyncFence);
+ ged_free(psMonitor, sizeof(GED_MONITOR_3D_FENCE));
+ }
+ else if (0 == err)
+ {
+ int iCount = atomic_add_return(1, &g_i32Count);
+ if (iCount > 1)
+ {
+ if (0 == ged_monitor_3D_fence_disable)
+ {
+ //unsigned int uiFreqLevelID;
+ //if (mtk_get_bottom_gpu_freq(&uiFreqLevelID))
+ {
+ //if (uiFreqLevelID != 4)
+ {
+#ifdef CONFIG_GPU_TRACEPOINTS
+ if (ged_monitor_3D_fence_systrace)
+ {
+ unsigned long long t = cpu_clock(smp_processor_id());
+ trace_gpu_sched_switch("Smart Boost", t, 1, 0, 1);
+ }
+#endif
+ mtk_set_bottom_gpu_freq(4);
+ }
+ }
+ }
+ }
+ }
+
+ if (ged_monitor_3D_fence_debug > 0)
+ {
+ GED_LOGI("[+]3D fences count = %d\n", atomic_read(&g_i32Count));
+ }
+
+ return GED_OK;
+}
+
+module_param(ged_monitor_3D_fence_debug, uint, 0644);
+module_param(ged_monitor_3D_fence_disable, uint, 0644);
+module_param(ged_monitor_3D_fence_systrace, uint, 0644);
diff --git a/drivers/misc/mediatek/gpu/ged/src/ged_profile_dvfs.c b/drivers/misc/mediatek/gpu/ged/src/ged_profile_dvfs.c
new file mode 100644
index 000000000..05cf7d7c4
--- /dev/null
+++ b/drivers/misc/mediatek/gpu/ged/src/ged_profile_dvfs.c
@@ -0,0 +1,190 @@
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include "ged_base.h"
+#include "ged_log.h"
+#include "ged_profile_dvfs.h"
+
+static GED_LOG_BUF_HANDLE ghLogBuf = 0;
+static struct mutex gsMutex;
+static GED_BOOL gbAllowRecord = GED_FALSE;
+
+GED_ERROR ged_profile_dvfs_init(void)
+{
+ mutex_init(&gsMutex);
+
+#if 0
+ ghLogBuf = ged_log_buf_alloc(320, 64 * 320, GED_LOG_BUF_TYPE_QUEUEBUFFER_AUTO_INCREASE, NULL, "profile_dvfs");
+#endif
+
+ return GED_OK;
+}
+
+GED_ERROR ged_profile_dvfs_enable(void)
+{
+ GED_ERROR ret;
+
+ mutex_lock(&gsMutex);
+
+ if (NULL == ghLogBuf)
+ {
+ ghLogBuf = ged_log_buf_alloc(320, 64 * 320, GED_LOG_BUF_TYPE_QUEUEBUFFER_AUTO_INCREASE, NULL, "profile_dvfs");
+ }
+
+ ret = ghLogBuf ? GED_OK : GED_ERROR_FAIL;
+
+ mutex_unlock(&gsMutex);
+
+ return ret;
+}
+
+void ged_profile_dvfs_disable(void)
+{
+ mutex_lock(&gsMutex);
+
+ if (NULL != ghLogBuf)
+ {
+ ged_log_buf_free(ghLogBuf);
+ ghLogBuf = NULL;
+ }
+
+ mutex_unlock(&gsMutex);
+}
+
+void ged_profile_dvfs_start(void)
+{
+ gbAllowRecord = GED_TRUE;
+}
+
+void ged_profile_dvfs_stop(void)
+{
+ gbAllowRecord = GED_FALSE;
+}
+
+void ged_profile_dvfs_ignore_lines(int i32LineCount)
+{
+ mutex_lock(&gsMutex);
+
+ if (ghLogBuf)
+ {
+ ged_log_buf_ignore_lines(ghLogBuf, i32LineCount);
+ }
+
+ mutex_unlock(&gsMutex);
+}
+
+void ged_profile_dvfs_exit(void)
+{
+ ged_profile_dvfs_disable();
+}
+
+void ged_profile_dvfs_record_freq_volt(unsigned int ui32Frequency, unsigned int ui32Voltage)
+{
+ mutex_lock(&gsMutex);
+
+ if (ghLogBuf && gbAllowRecord)
+ {
+ /* copy & modify from ./kernel/printk.c */
+ unsigned long long t;
+ unsigned long nanosec_rem;
+
+ t = cpu_clock(smp_processor_id());
+ nanosec_rem = do_div(t, 1000000000) / 1000;
+
+ ged_log_buf_print(ghLogBuf, "%5lu.%06lu,freq_volt,%u,%u", (unsigned long) t, nanosec_rem, ui32Frequency, ui32Voltage);
+ }
+ mutex_unlock(&gsMutex);
+}
+
+void ged_profile_dvfs_record_temp(int i32Temp)
+{
+ mutex_lock(&gsMutex);
+
+ if (ghLogBuf && gbAllowRecord)
+ {
+ /* copy & modify from ./kernel/printk.c */
+ unsigned long long t;
+ unsigned long nanosec_rem;
+
+ t = cpu_clock(smp_processor_id());
+ nanosec_rem = do_div(t, 1000000000) / 1000;
+
+ ged_log_buf_print(ghLogBuf, "%5lu.%06lu,temp,%d", (unsigned long) t, nanosec_rem, i32Temp);
+ }
+ mutex_unlock(&gsMutex);
+
+}
+
+void ged_profile_dvfs_record_thermal_limit(unsigned int ui32FreqLimit)
+{
+ mutex_lock(&gsMutex);
+
+ if (ghLogBuf && gbAllowRecord)
+ {
+ /* copy & modify from ./kernel/printk.c */
+ unsigned long long t;
+ unsigned long nanosec_rem;
+
+ t = cpu_clock(smp_processor_id());
+ nanosec_rem = do_div(t, 1000000000) / 1000;
+
+ ged_log_buf_print(ghLogBuf, "%5lu.%06lu,thermal_limit,%u", (unsigned long) t, nanosec_rem, ui32FreqLimit);
+ }
+ mutex_unlock(&gsMutex);
+}
+
+void ged_profile_dvfs_record_gpu_loading(unsigned int ui32GpuLoading)
+{
+ mutex_lock(&gsMutex);
+
+ if (ghLogBuf && gbAllowRecord)
+ {
+ /* copy & modify from ./kernel/printk.c */
+ unsigned long long t;
+ unsigned long nanosec_rem;
+
+ t = cpu_clock(smp_processor_id());
+ nanosec_rem = do_div(t, 1000000000) / 1000;
+
+ ged_log_buf_print(ghLogBuf, "%5lu.%06lu,gpu_load,%u", (unsigned long) t, nanosec_rem, ui32GpuLoading);
+ }
+
+ mutex_unlock(&gsMutex);
+}
+
+void ged_profile_dvfs_record_clock_on(void)
+{
+ mutex_lock(&gsMutex);
+
+ if (ghLogBuf && gbAllowRecord)
+ {
+ /* copy & modify from ./kernel/printk.c */
+ unsigned long long t;
+ unsigned long nanosec_rem;
+
+ t = cpu_clock(smp_processor_id());
+ nanosec_rem = do_div(t, 1000000000) / 1000;
+
+ ged_log_buf_print(ghLogBuf, "%5lu.%06lu,gpu_clock,1", (unsigned long) t, nanosec_rem);
+ }
+
+ mutex_unlock(&gsMutex);
+}
+
+void ged_profile_dvfs_record_clock_off(void)
+{
+ mutex_lock(&gsMutex);
+
+ if (ghLogBuf && gbAllowRecord)
+ {
+ /* copy & modify from ./kernel/printk.c */
+ unsigned long long t;
+ unsigned long nanosec_rem;
+
+ t = cpu_clock(smp_processor_id());
+ nanosec_rem = do_div(t, 1000000000) / 1000;
+
+ ged_log_buf_print(ghLogBuf, "%5lu.%06lu,gpu_clock,0", (unsigned long) t, nanosec_rem);
+ }
+
+ mutex_unlock(&gsMutex);
+}