// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
 *
 * Copyright(C) 2024 MediaTek Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *****************************************************************************/


#include <mali_kbase.h>
#include <linux/delay.h>
#include "mali_kbase_platform_mtk_dtv.h"
#include "mali_kbase_platform_mtk_dtv_mt5877_reg.h"

#define debug_print pr_info

#ifdef CONFIG_DEBUG_FS

static void update_frequency(u32 frequency)
{
	mali_gpu_clock = frequency;
    /* set GPU clock */
	SET_REG(GPUBRDGPLL, pd_gpubrdgpll, 0x0);
	SET_REG(GPUBRDGPLL, gc_gpubrdgpll_loopdiv_second, (frequency/GPU_CLOCK_STEP));
	udelay(1);
}

#define BUFFER_SIZE_64 64
#define BUFFER_SIZE_32 32

static ssize_t gpu_clock_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
{
	char buf[BUFFER_SIZE_64];
	int r;

	r = snprintf(buf, BUFFER_SIZE_64, "%u\n", mali_gpu_clock);

	if ((r < 0) || (r >= sizeof(buf)))
		return 0;

	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
}

static ssize_t gpu_clock_write(struct file *filp, const char __user *ubuf, size_t cnt,
	loff_t *ppos)
{
	int ret;
	char buffer[BUFFER_SIZE_32];
	unsigned long val;

	if (cnt >= sizeof(buffer))
		return -ENOMEM;

	if (copy_from_user(&buffer[0], ubuf, cnt))
		return -EFAULT;

	buffer[cnt] = '\0';
	ret = kstrtoul(&buffer[0], 10, &val);

	if (ret != 0)
		return -EINVAL;


	if (mali_debug_property == MALI_DEBUG_PROPERTY_PASSWORD)
		update_frequency(val);

	return cnt;
}

#if defined(MTK_DTV_ZEBU) && defined(CONFIG_MALI_DEBUG)
static unsigned int g_debug_function;
static ssize_t gpu_function_read(struct file *filp, char __user *ubuf,
		size_t cnt, loff_t *ppos)
{
	char buf[BUFFER_SIZE_64];
	size_t r;

	r = snprintf(buf, BUFFER_SIZE_64, "0x%x\n", g_debug_function);

	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
}

#define DEALY_100_microsecond 100

static ssize_t gpu_function_write(struct file *filp, const char __user *ubuf, size_t cnt,
		loff_t *ppos)
{
	int ret;
	char buffer[BUFFER_SIZE_32];
	unsigned long val;

	if (cnt >= sizeof(buffer))
		return -ENOMEM;

	if (copy_from_user(&buffer[0], ubuf, cnt))
		return -EFAULT;

	buffer[cnt] = '\0';
	ret = kstrtoul(&buffer[0], 0, &val);

	g_debug_function = val;

	if (ret != 0)
		return -EINVAL;

	if (g_debug_function == 1) {
		unsigned int mpu_not_invalidate_done = 1;

		debug_print("[MPU] Invalate all IOMPU_GLOBAL 2\n");
		SET_DW_REG(IOMPU_GLOBAL, mpu_invalide_mode, 1);
		SET_DW_REG(IOMPU_GLOBAL, mpu_cache_invalidate_idle_mode, 0);
		SET_DW_REG(IOMPU_GLOBAL, mpu_trigger_invalidate, 0);
		SET_DW_REG(IOMPU_GLOBAL, mpu_trigger_invalidate, 1);

		//while(mpu_not_invalidate_done == 1) {
			mpu_not_invalidate_done = GET_DW_REG(IOMPU_GLOBAL, mpu_invalide_status);
			debug_print("mpu_not_invalidate_done IOMPU_GLOBAL (%d)\n",
					mpu_not_invalidate_done);
			udelay(DEALY_100_microsecond);
		//}
	} else if (g_debug_function == 2) {
		unsigned int mpu_not_invalidate_done = 1;

		debug_print("[MPU] Invalate range IOMPU GLOBAL\n");
		SET_DW_REG(IOMPU_GLOBAL, mpu_invalide_mode, 0);
		SET_DW_REG(IOMPU_GLOBAL, mpu_cache_invalidate_idle_mode, 1);
		SET_DW_REG(IOMPU_GLOBAL, mpu_invalide_start_addr, (0x60000000 >> 18));
		SET_DW_REG(IOMPU_GLOBAL, mpu_invalide_end_addr,   (0x60100000 >> 18));
		SET_DW_REG(IOMPU_GLOBAL, mpu_trigger_invalidate, 0);
		SET_DW_REG(IOMPU_GLOBAL, mpu_trigger_invalidate, 1);
		//while(mpu_not_invalidate_done == 1) {
			mpu_not_invalidate_done = GET_DW_REG(IOMPU_GLOBAL, mpu_invalide_status);
			debug_print("mpu_not_invalidate_done IOMPU_GPU (%d)\n",
					mpu_not_invalidate_done);
			udelay(DEALY_100_microsecond);
		//}
	} else if (g_debug_function == 3) {
		debug_print("[MPU] FAULT INFORMATION\n");
		SET_DW_REG(IOMPU_GPU, mpu_pmu_debug_client_sel, 0);
		debug_print("[MPU] fault happen 0x(%lx)\n",
				GET_DW_REG(IOMPU_GPU, mpu_fault_info_valid));
		debug_print("[MPU] fault pa 0x(%lx)\n", GET_DW_REG(IOMPU_GPU,
				mpu_fault_physical_address));
		debug_print("[MPU] fault sr info  0x(%lx)\n",
				GET_DW_REG(IOMPU_GPU, mpu_fault_sr_info));
		debug_print("[MPU] state 0x(%lx)\n",
				GET_DW_REG(IOMPU_GPU, mpu_state));
		SET_DW_REG(IOMPU_GPU, mpu_clean_fault_information, 1);
		SET_DW_REG(IOMPU_GPU, mpu_clean_fault_information, 0);
	} else if (g_debug_function == 4) {
		unsigned int mpu_not_invalidate_done = 1;

		debug_print("[MPU] Invalate all IOMPU_GPU\n");
		SET_DW_REG(IOMPU_GPU, mpu_invalide_mode, 1);
		SET_DW_REG(IOMPU_GPU, mpu_cache_invalidate_idle_mode, 1);
		SET_DW_REG(IOMPU_GPU, mpu_trigger_invalidate, 0);
		SET_DW_REG(IOMPU_GPU, mpu_trigger_invalidate, 1);
		while (mpu_not_invalidate_done == 1) {
			mpu_not_invalidate_done = GET_DW_REG(IOMPU_GPU, mpu_invalide_status);
			debug_print("mpu_not_invalidate_done IOMPU_GLOBAL (%d)\n",
					mpu_not_invalidate_done);
			udelay(DEALY_100_microsecond);
		}
	} else if (g_debug_function == 5) {
		unsigned int mpu_not_invalidate_done = 1;

		debug_print("[MPU] IOMPU GPU Invalate range\n");
		SET_DW_REG(IOMPU_GPU, mpu_invalide_mode, 0);
		SET_DW_REG(IOMPU_GPU, mpu_cache_invalidate_idle_mode, 1);
		SET_DW_REG(IOMPU_GPU, mpu_invalide_start_addr, (0x60000000 >> 18));
		SET_DW_REG(IOMPU_GPU, mpu_invalide_end_addr,   (0x60100000 >> 18));
		SET_DW_REG(IOMPU_GPU, mpu_trigger_invalidate, 0);
		SET_DW_REG(IOMPU_GPU, mpu_trigger_invalidate, 1);
		while (mpu_not_invalidate_done == 1) {
			mpu_not_invalidate_done = GET_DW_REG(IOMPU_GPU,
					mpu_invalide_status);
			debug_print("mpu_not_invalidate_done IOMPU_GPU (%d)\n",
					mpu_not_invalidate_done);
			udelay(DEALY_100_microsecond);
		}
	} else if (g_debug_function == 6) {
		debug_print("[MPU] mpu bypass table set\n");
		SET_DW_REG(IOMPU_GPU, mpu_pmu_debug_client_sel, 0);
		SET_DW_REG(IOMPU_GPU, mpu_byp_client_status_sel, 0);
		SET_DW_REG(IOMPU_GPU, mpu_log_sel, 0);
		SET_DW_REG(IOMPU_GPU, mpu_byp_pa_60000000, 0xffff);
		SET_DW_REG(IOMPU_GPU, mpu_byp_entry_size, 3);
		SET_DW_REG(IOMPU_GPU, mpu_byp_gpu_table_enable, 1);
		SET_DW_REG(IOMPU_GPU, mpu_byp_gpu_table_debug_enable, 1);
		debug_print("[MPU] mpu bypass table set done\n");
	} else if (g_debug_function == 7) {
		debug_print("[MPU] mpu byp debug info\n");
		debug_print("[MPU] mpu byp debug mpu_byp_clean_fault_info 0x(%X)\n",
				GET_DW_REG(IOMPU_GPU, mpu_byp_clean_fault_info));
		debug_print("[MPU] mpu byp debug mpu_byp_client_status_sel debug 0x(%X)\n",
				GET_DW_REG(IOMPU_GPU, mpu_byp_client_status_sel));
		debug_print("[MPU] mpu bypass table debug info pa_0_31 0x(%X)\n",
				GET_DW_REG(IOMPU_GPU, mpu_byp_log_pa_0_31));
		debug_print("[MPU] mpu bypass table debug info pa_0_31 0x(%X)\n",
				GET_DW_REG(IOMPU_GPU, mpu_byp_log_pa_0_31));
		debug_print("[MPU] mpu bypass table debug info pa_32_33 0x(%X)\n",
				GET_DW_REG(IOMPU_GPU, mpu_byp_log_pa_32_33) & 0xf);
		debug_print("[MPU] mpu bypass table debug byp table value 0x(%X)\n",
				GET_DW_REG(IOMPU_GPU, mpu_byp_log_byp_value));
		debug_print("[MPU] mpu bypass table debug log valid flag 0x(%X)\n",
				GET_DW_REG(IOMPU_GPU, mpu_byp_log_valid_flag));
		SET_DW_REG(IOMPU_GPU, mpu_log_sel, 1);
		debug_print("[MPU] mpu bypass table debug log sr_info 0x(%X)\n",
				GET_DW_REG(IOMPU_GPU, mpu_byp_log_sr_info));
		SET_DW_REG(IOMPU_GPU, mpu_byp_clean_fault_info, 1);
		SET_DW_REG(IOMPU_GPU, mpu_byp_clean_fault_info, 0);
	} else if (g_debug_function == 8) {
		debug_print("[MPU] mpu bypass table disable\n");
		SET_DW_REG(IOMPU_GPU, mpu_byp_gpu_table_enable, 0);
		SET_DW_REG(IOMPU_GPU, mpu_byp_gpu_table_debug_enable, 0);
	} else if (g_debug_function == 9) {
		debug_print("[MPU] detect gpu security enable detect 0x40\n");
		debug_print("[MPU] read detected (%X)\n",
				GET_DW_REG(IOMPU_GPU, read_detected_AID));
		SET_DW_REG(IOMPU_GPU, detect_AID_value, 0x40);
		SET_DW_REG(IOMPU_GPU, detect_AID_enable, 1);
		SET_DW_REG(IOMPU_GPU, fault_latch_enable, 1);
		debug_print("[MPU] read detected (%X)\n",
				GET_DW_REG(IOMPU_GPU, read_detected_AID));
	} else if (g_debug_function == 10) {
		debug_print("[MPU] detect gpu security enable detect 0x5a\n");
		debug_print("[MPU] read detected (%X)\n",
				GET_DW_REG(IOMPU_GPU, read_detected_AID));
		SET_DW_REG(IOMPU_GPU, detect_AID_value, 0x5a);
		SET_DW_REG(IOMPU_GPU, detect_AID_enable, 1);
		SET_DW_REG(IOMPU_GPU, fault_latch_enable, 1);
		debug_print("[MPU] read detected (%X)\n",
				GET_DW_REG(IOMPU_GPU, read_detected_AID));
	} else if (g_debug_function == 11) {
		debug_print("[MPU] check detected AID\n");
		debug_print("[MPU] check detected AID (%X)\n",
				GET_DW_REG(IOMPU_GPU, read_detected_AID));
	} else if (g_debug_function == 12) {
		debug_print("[MPU] enable MPU\n");
		SET_DW_REG(IOMPU_GPU, mpu_table_base_addr, (u32)(((u32)0x61000000)>>12));
		debug_print("[MPU] mpu_table_base_addr: 0x%04x\n",
				GET_DW_REG(IOMPU_GPU, mpu_table_base_addr));
		SET_DW_REG(IOMPU_GPU, mpu_area_0_start, (u32)(((u32)0x60000000) >> 20));
		debug_print("[MPU] mpu_area0_start: 0x%04x\n",
				GET_DW_REG(IOMPU_GPU, mpu_area_0_start));
		SET_DW_REG(IOMPU_GPU, mpu_area_0_end, (u32)(((u32)0x60100000) >> 20));
		debug_print("[MPU] mpu_area0_end: 0x%04x\n",
				GET_DW_REG(IOMPU_GPU, mpu_area_0_end));
		/* Set MPU area1 start */
		SET_DW_REG(IOMPU_GPU, mpu_area_1_start, (u32)(((u32)0xffffffff) >> 20));
		debug_print("[MPU] mpu_area1_start: 0x%04x\n",
				GET_DW_REG(IOMPU_GPU, mpu_area_1_start));
		/* Set MPU area1 end */
		SET_DW_REG(IOMPU_GPU, mpu_area_1_end, (u32) (((u32)0xffffffff) >> 20));
		debug_print("[MPU] mpu_area1_end: 0x%04x\n",
				GET_DW_REG(IOMPU_GPU, mpu_area_1_end));
		/* Update MPU table base & area */
		SET_DW_REG(IOMPU_GPU, mpu_table_base_area_update, (u32)0x0);
		debug_print("[MPU] mpu_table_update: 0x%04x\n",
				GET_DW_REG(IOMPU_GPU, mpu_table_base_area_update));
		SET_DW_REG(IOMPU_GPU, mpu_table_base_area_update, (u32)0x1);
		SET_DW_REG(IOMPU_GPU, mpu_enable, 0x1);
		debug_print("[MPU] mpu_enable: 0x%04x\n",
				GET_DW_REG(IOMPU_GPU, mpu_enable));
	} else {
	}

	return cnt;
}
#endif

static const struct file_operations kbasep_gpu_clock_debugfs_fops = {
	.read = gpu_clock_read,
	.write = gpu_clock_write,
};


/* exam reg */



#if defined(MTK_DTV_ZEBU) && defined(CONFIG_MALI_DEBUG)
static const struct file_operations kbasep_gpu_function_debugfs_fops = {
	.read = gpu_function_read,
	.write = gpu_function_write,
};
#endif

#if defined(CONFIG_MALI_DEBUG) && (defined(MTK_DTV_ZEBU) || defined(MTK_DTV_HAPS)) && \
defined(MTK_DTV_DEVICE_TREE_PROBE)

#define RIU ((volatile unsigned short *)(mtk_pm_vaddr))
#define RIU_DW ((volatile unsigned int *)(mtk_pm_vaddr))
#define RIU_B ((volatile unsigned char *)(mtk_pm_vaddr))

#define DEFAULT_REG_ADDRESS 0x1c000000;
#define DEFAULT_REG_BANK 0x2ee9;
#define DEFAULT_REG_BASE 0x49;
#define DEFAULT_MSB 15;

static unsigned int g_mst_reg_adress = DEFAULT_REG_ADDRESS;
static unsigned int g_mst_reg_bank = DEFAULT_REG_BANK;
static unsigned int g_mst_reg_base = DEFAULT_REG_BASE;
static unsigned int g_mst_lsb;
static unsigned int g_mst_msb = DEFAULT_MSB;

#define SHIFT_8 8
#define SHIFT_7 7

static unsigned int mst_get_reg(void)
{
	unsigned int mask_bank_name;
	unsigned int shift_bank_name;

	mask_bank_name = ((1 << (g_mst_msb - g_mst_lsb + 1)) - 1) << g_mst_lsb;
	shift_bank_name = g_mst_lsb;

	return ((RIU[(g_mst_reg_bank << SHIFT_8) + (g_mst_reg_base << 1)] & mask_bank_name)
			>> shift_bank_name);
}

static unsigned int mst_get_reg_dw(void)
{
	return RIU_DW[(g_mst_reg_bank << SHIFT_7) + g_mst_reg_base];
}

static void mst_set_reg(unsigned int value)
{
	unsigned int mask_bank_name;
	unsigned int shift_bank_name;

	mask_bank_name = ((1 << (g_mst_msb - g_mst_lsb + 1)) - 1) << g_mst_lsb;
	shift_bank_name = g_mst_lsb;

	RIU[(g_mst_reg_bank << SHIFT_8) + (g_mst_reg_base << 1)] &= ~mask_bank_name;
	RIU[(g_mst_reg_bank << SHIFT_8) + (g_mst_reg_base << 1)] |=
		((value) << shift_bank_name) & mask_bank_name;
}

static void mst_set_reg_dw(unsigned int value)
{
	RIU_DW[(g_mst_reg_bank << SHIFT_7)  + g_mst_reg_base] = value;
}

static ssize_t gpu_reg_bank_read(struct file *filp, char __user *ubuf,
		size_t cnt, loff_t *ppos)
{
	char buf[BUFFER_SIZE_64];
	size_t r;

	r = snprintf(buf, BUFFER_SIZE_64, "0x%x\n", g_mst_reg_bank);

	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
}

static ssize_t gpu_reg_bank_write(struct file *filp, const char __user *ubuf,
		size_t cnt, loff_t *ppos)
{
	int ret;
	char buffer[BUFFER_SIZE_32];
	unsigned long val;

	if (cnt >= sizeof(buffer))
		return -ENOMEM;

	if (copy_from_user(&buffer[0], ubuf, cnt))
		return -EFAULT;

	buffer[cnt] = '\0';
	ret = kstrtoul(&buffer[0], 0, &val);

	g_mst_reg_bank = val;

	if (ret != 0)
		return -EINVAL;

	return cnt;
}

static ssize_t gpu_reg_base_read(struct file *filp, char __user *ubuf,
		size_t cnt, loff_t *ppos)
{
	char buf[BUFFER_SIZE_64];
	size_t r;

	r = snprintf(buf, BUFFER_SIZE_64, "0x%x\n", g_mst_reg_base);

	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
}

static ssize_t gpu_reg_base_write(struct file *filp, const char __user *ubuf,
		size_t cnt, loff_t *ppos)
{
	int ret;
	char buffer[BUFFER_SIZE_32];
	unsigned long val;

	if (cnt >= sizeof(buffer))
		return -ENOMEM;

	if (copy_from_user(&buffer[0], ubuf, cnt))
		return -EFAULT;

	buffer[cnt] = '\0';
	ret = kstrtoul(&buffer[0], 0, &val);

	g_mst_reg_base = val;

	if (ret != 0)
		return -EINVAL;

	return cnt;
}

static ssize_t gpu_reg_lsb_read(struct file *filp, char __user *ubuf,
		size_t cnt, loff_t *ppos)
{
	char buf[BUFFER_SIZE_64];
	size_t r;

	r = snprintf(buf, BUFFER_SIZE_64, "%u\n", g_mst_lsb);

	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
}

static ssize_t gpu_reg_lsb_write(struct file *filp, const char __user *ubuf,
		size_t cnt, loff_t *ppos)
{
	int ret;
	char buffer[BUFFER_SIZE_32];
	unsigned long val;

	if (cnt >= sizeof(buffer))
		return -ENOMEM;

	if (copy_from_user(&buffer[0], ubuf, cnt))
		return -EFAULT;

	buffer[cnt] = '\0';
	ret = kstrtoul(&buffer[0], 0, &val);

	g_mst_lsb = val;

	if (ret != 0)
		return -EINVAL;

	return cnt;
}

static ssize_t gpu_reg_msb_read(struct file *filp, char __user *ubuf, size_t cnt,
		loff_t *ppos)
{
	char buf[BUFFER_SIZE_64];
	size_t r;

	r = snprintf(buf, BUFFER_SIZE_64, "%u\n", g_mst_msb);

	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
}

static ssize_t gpu_reg_msb_write(struct file *filp, const char __user *ubuf, size_t cnt,
		loff_t *ppos)
{
	int ret;
	char buffer[BUFFER_SIZE_32];
	unsigned long val;

	if (cnt >= sizeof(buffer))
		return -ENOMEM;

	if (copy_from_user(&buffer[0], ubuf, cnt))
		return -EFAULT;

	buffer[cnt] = '\0';
	ret = kstrtoul(&buffer[0], 0, &val);

	g_mst_msb = val;

	if (ret != 0)
		return -EINVAL;

	return cnt;
}

#define HEX_200 0x200
#define HEX_4 4

static ssize_t gpu_reg_operate_read(struct file *filp, char __user *ubuf, size_t cnt,
		loff_t *ppos)
{
	char buf[BUFFER_SIZE_64];
	size_t r;
	unsigned int reg;

	reg = mst_get_reg();

	r = snprintf(buf, BUFFER_SIZE_64, "0x%x\n", reg);

	g_mst_reg_adress = mtk_pm_vaddr + g_mst_reg_bank * HEX_200 + g_mst_reg_base * HEX_4;

	debug_print("[read] 0x%x, Bank: 0x%x, Reg: 0x%x [%d:%d] = 0x%x\n",
			g_mst_reg_adress, g_mst_reg_bank,
			g_mst_reg_base, g_mst_msb, g_mst_lsb, reg);

	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
}

static ssize_t gpu_reg_operate_write(struct file *filp, const char __user *ubuf,
		size_t cnt, loff_t *ppos)
{
	int ret;
	char buffer[BUFFER_SIZE_32];
	unsigned long val;

	if (cnt >= sizeof(buffer))
		return -ENOMEM;

	if (copy_from_user(&buffer[0], ubuf, cnt))
		return -EFAULT;

	buffer[cnt] = '\0';
	ret = kstrtoul(&buffer[0], 0, &val);

	mst_set_reg((unsigned int)val);

	g_mst_reg_adress = mtk_pm_vaddr + g_mst_reg_bank * HEX_200 + g_mst_reg_base * HEX_4;
	debug_print("[write] 0x%x, Bank: 0x%x, Reg: 0x%x [%d:%d] = 0x%x\n",
			g_mst_reg_adress, g_mst_reg_bank, g_mst_reg_base, g_mst_msb, g_mst_lsb,
			(unsigned int)val);

	if (ret != 0)
		return -EINVAL;

	return cnt;
}

static ssize_t gpu_reg_dw_operate_read(struct file *filp, char __user *ubuf, size_t cnt,
		loff_t *ppos)
{
	char buf[BUFFER_SIZE_64];
	size_t r;
	unsigned int reg;

	reg = mst_get_reg_dw();


	r = snprintf(buf, BUFFER_SIZE_64, "0x%x\n", reg);

	g_mst_reg_adress = mtk_pm_vaddr + g_mst_reg_bank * HEX_200 + g_mst_reg_base * HEX_4;

	debug_print("[read] 0x%x, Bank: 0x%x, Reg: 0x%x [31:0] = 0x%x\n", g_mst_reg_adress,
			g_mst_reg_bank, g_mst_reg_base, reg);

	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
}

static ssize_t gpu_reg_dw_operate_write(struct file *filp, const char __user *ubuf,
		size_t cnt, loff_t *ppos)
{
	int ret;
	char buffer[BUFFER_SIZE_32];
	unsigned long val;

	if (cnt >= sizeof(buffer))
		return -ENOMEM;

	if (copy_from_user(&buffer[0], ubuf, cnt))
		return -EFAULT;

	buffer[cnt] = '\0';
	ret = kstrtoul(&buffer[0], 0, &val);

	mst_set_reg_dw((unsigned int)val);

	g_mst_reg_adress = mtk_pm_vaddr + g_mst_reg_bank * HEX_200 + g_mst_reg_base * HEX_4;
	debug_print("[write] 0x%x, Bank: 0x%x, Reg: 0x%x [31:0] = 0x%x\n",
			g_mst_reg_adress, g_mst_reg_bank, g_mst_reg_base, (unsigned int) val);

	if (ret != 0)
		return -EINVAL;

	return cnt;
}

static const struct file_operations kbasep_gpu_reg_bank_debugfs_fops = {
	.read = gpu_reg_bank_read,
	.write = gpu_reg_bank_write,
};
static const struct file_operations kbasep_gpu_reg_base_debugfs_fops = {
	.read = gpu_reg_base_read,
	.write = gpu_reg_base_write,
};

static const struct file_operations kbasep_gpu_reg_lsb_debugfs_fops = {
	.read = gpu_reg_lsb_read,
	.write = gpu_reg_lsb_write,
};
static const struct file_operations kbasep_gpu_reg_msb_debugfs_fops = {
	.read = gpu_reg_msb_read,
	.write = gpu_reg_msb_write,
};

static const struct file_operations kbasep_gpu_reg_operate_debugfs_fops = {
	.read = gpu_reg_operate_read,
	.write = gpu_reg_operate_write,
};

static const struct file_operations kbasep_gpu_reg_dw_operate_debugfs_fops = {
	.read = gpu_reg_dw_operate_read,
	.write = gpu_reg_dw_operate_write,
};
#endif

/*
 *  Initialize debugfs entry for gpu clock
 */
void kbasep_gpu_clock_debugfs_init(struct kbase_device *kbdev)
{
	debugfs_create_file("gpu_clock", 0666,
			kbdev->mali_debugfs_directory, NULL,
			&kbasep_gpu_clock_debugfs_fops);
#if defined(MTK_DTV_ZEBU) && defined(CONFIG_MALI_DEBUG)
	debugfs_create_file("gpu_function", 0666,
			kbdev->mali_debugfs_directory, NULL,
			&kbasep_gpu_function_debugfs_fops);
#endif
#if defined(CONFIG_MALI_DEBUG) && (defined(MTK_DTV_ZEBU) || defined(MTK_DTV_HAPS)) && \
defined(MTK_DTV_DEVICE_TREE_PROBE)
	debugfs_create_file("reg_bank", 0666,
			kbdev->mali_debugfs_directory, NULL,
			&kbasep_gpu_reg_bank_debugfs_fops);
	debugfs_create_file("reg_base", 0666,
			kbdev->mali_debugfs_directory, NULL,
			&kbasep_gpu_reg_base_debugfs_fops);
	debugfs_create_file("reg_lsb", 0666,
			kbdev->mali_debugfs_directory, NULL,
			&kbasep_gpu_reg_lsb_debugfs_fops);
	debugfs_create_file("reg_msb", 0666,
			kbdev->mali_debugfs_directory, NULL,
			&kbasep_gpu_reg_msb_debugfs_fops);
	debugfs_create_file("reg", 0666,
			kbdev->mali_debugfs_directory, NULL,
			&kbasep_gpu_reg_operate_debugfs_fops);
	debugfs_create_file("reg_dw", 0666,
			kbdev->mali_debugfs_directory, NULL,
			&kbasep_gpu_reg_dw_operate_debugfs_fops);
#endif
}

#else
/*
 * Stub functions for when debugfs is disabled
 */
void kbasep_gpu_clock_debugfs_init(struct kbase_device *kbdev)
{
}
#endif
