// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
/*
 * Copyright (c) 2024 MediaTek Inc.
 */
#include <linux/kernel.h>
#include <mali_kbase.h>
#include "mali_kbase_platform_mtk_dtv.h"
#include "mali_kbase_platform_mtk_dtv_mt5877_reg.h"
#include <linux/delay.h>

#if MTK_DTV_GPU_MFDEC
extern u16 mfdec_used_id;
#endif

#define TEST_MPU 0
#define EN_MPU 0
#define SLPPROT_REG 0

#define debug_print pr_info

#if TEST_MPU
#define MPU_TEST_BASE_ADDR 0x91000000
#define MPU_BASE_ADDR_REG_SHIFT 12
#define MPU_AREA0_END 0xffff

void init_mpu(struct kbase_device *kbdev)
{

	/* set srinfo mode 1: 5bit 0: 8bit */
	SET_DW_REG(IOMPU_GPU, srinfo_mode, 1);
	debug_print("[MPU] srinfo mode  ? 0x%04x\n", GET_DW_REG(IOMPU_GPU, srinfo_mode));
	debug_print("[MPU] bypass table enable ? 0x%04x\n",
GET_DW_REG(IOMPU_GPU, mpu_byp_gpu_table_enable));

	/* Set MPU table base to DRAM offset phy:0x9000_0000 >> 12 (PHYS ADDR, 4k aligned) */
	SET_DW_REG(IOMPU_GPU, mpu_table_base_addr,
			(u32)(((u32) MPU_TEST_BASE_ADDR) >> MPU_BASE_ADDR_REG_SHIFT));
	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)(0));
	SET_DW_REG(IOMPU_GPU, mpu_area_0_end, (u32)(MPU_AREA0_END));
	debug_print("[MPU] mpu_area0_start: 0x%04x\n",
			GET_DW_REG(IOMPU_GPU, mpu_area_0_start));
	debug_print("[MPU] mpu_area0_end: 0x%04x\n",
			GET_DW_REG(IOMPU_GPU, mpu_area_0_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);


	/* Enable MPU for IOMPU global */
	SET_DW_REG(IOMPU_GPU, mpu_enable, 0x1);
	dev_dbg(kbdev->dev, "[MPU] mpu_enable: 0x%04x\n",
			GET_DW_REG(IOMPU_GPU, mpu_enable));

}
#endif

/* Platform functions */


#ifdef MTK_DTV_DEVICE_TREE_PROBE

#if (MALI_AUTO_IOREMAP == 1)
#ifndef IO_PHYS
#define IO_PHYS 0x000000001C000000
#endif
ptrdiff_t GPUBRDGPLL_vaddr;
ptrdiff_t CKGEN00_vaddr;
ptrdiff_t CKGEN01_vaddr;
ptrdiff_t SRAM_PD_vaddr;
ptrdiff_t TZPC_AID_0_vaddr;
ptrdiff_t X32_GPU_vaddr;
ptrdiff_t IOMPU_GLOBAL_vaddr;
ptrdiff_t IOMPU_GPU_vaddr;
ptrdiff_t PM_POR_vaddr;
ptrdiff_t TEST_CTRL_vaddr;
ptrdiff_t CKGEN103A_vaddr;
#if defined(CONFIG_MALI_DEBUG) && defined(MTK_DTV_ZEBU)
ptrdiff_t mtk_pm_vaddr; // for debug only
ptrdiff_t EMI_vaddr;
#endif
ptrdiff_t MFDEC_BKA415_vaddr;
ptrdiff_t MIU_vaddr;
ptrdiff_t GPU_MPU_BYPASS_vaddr;
ptrdiff_t CPU_MPU_BYPASS_vaddr;
ptrdiff_t X32_SMI_CTRL_vaddr;

ptrdiff_t CKGEN1029_vaddr;
ptrdiff_t CKGEN1035_vaddr;
ptrdiff_t CKGEN1036_vaddr;
ptrdiff_t CKGEN1037_vaddr;
ptrdiff_t CKGEN103C_vaddr;
ptrdiff_t CKGENA040_vaddr;
ptrdiff_t MFDEC_BKA432_vaddr;
ptrdiff_t MFDEC_BKA433_vaddr;
ptrdiff_t MFDEC_BKA412_vaddr;
ptrdiff_t MFDEC_BKA413_vaddr;
ptrdiff_t MFDEC_BKA414_vaddr;

#define MTK_PM_ADDR_VALUE 0xA000000
#define HEX_SIZE_10 0x10
#define HEX_SIZE_100 0x100
#define HEX_SIZE_200 0x200
#define HEX_SIZE_2000 0x2000
#define HEX_SIZE_10000 0x10000


void map_registers(struct kbase_device *kbdev)
{
#if defined(MTK_DTV_ZEBU)
	dev_dbg(kbdev->dev, "%s, IO_PHYS = 0x%x\n", __func__, IO_PHYS);

#if defined(CONFIG_MALI_DEBUG)
	mtk_pm_vaddr = (ptrdiff_t)ioremap(IO_PHYS, MTK_PM_ADDR_VALUE); // for debug only
	dev_dbg(kbdev->dev, "mtk_pm_vaddr: 0x%lx, io_pa: 0x%x\n",
		mtk_pm_vaddr, IO_PHYS);
	EMI_vaddr       = (ptrdiff_t)ioremap(IO_PHYS + (reg_EMI_base<<1), HEX_SIZE_2000);
	dev_dbg(kbdev->dev, "EMI_vaddr: 0x%lx, io_pa: 0x%x\n",
		EMI_vaddr, IO_PHYS + (reg_EMI_base<<1));
#endif
	GPUBRDGPLL_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_GPUBRDGPLL_base<<1),
HEX_SIZE_100);
	//dev_dbg(kbdev->dev, "GPUBRDGPLL_vaddr: 0x%lx, io_pa: 0x%x\n",
	//	GPUBRDGPLL_vaddr, IO_PHYS + (reg_GPUBRDGPLL_base<<1));
	CKGEN00_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_CKGEN00_base<<1),
HEX_SIZE_2000);
	//dev_dbg(kbdev->dev, "CKGEN00_vaddr: 0x%lx, io_pa: 0x%x\n",
	//	CKGEN00_vaddr, IO_PHYS + (reg_CKGEN00_base<<1));
	CKGEN01_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_CKGEN01_base<<1),
HEX_SIZE_2000);
	//dev_dbg(kbdev->dev, "CKGEN01_vaddr: 0x%lx, io_pa: 0x%x\n",
	//	CKGEN01_vaddr, IO_PHYS + (reg_CKGEN01_base<<1));
	SRAM_PD_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_SRAM_PD_base<<1),
HEX_SIZE_10000);
	//dev_dbg(kbdev->dev, "SRAM_PD_vaddr: 0x%lx, io_pa: 0x%x\n",
	//	SRAM_PD_vaddr, IO_PHYS + (reg_SRAM_PD_base<<1));
	TZPC_AID_0_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_TZPC_AID_0_base<<1),
HEX_SIZE_200);
	//dev_dbg(kbdev->dev, "TZPC_AID_0_vaddr: 0x%lx, io_pa: 0x%x\n",
	//	TZPC_AID_0_vaddr, IO_PHYS + (reg_TZPC_AID_0_base<<1));
	X32_GPU_vaddr             = (ptrdiff_t)ioremap(IO_PHYS + (reg_X32_GPU_base<<1),
HEX_SIZE_200);
	//dev_dbg(kbdev->dev, "X32_GPU_vaddr: 0x%lx, io_pa: 0x%x\n",
	//	X32_GPU_vaddr, IO_PHYS + (reg_X32_GPU_base<<1));
	IOMPU_GLOBAL_vaddr      = (ptrdiff_t)ioremap(IO_PHYS + (reg_IOMPU_GLOBAL_base<<1),
HEX_SIZE_2000);
	IOMPU_GPU_vaddr      = (ptrdiff_t)ioremap(IO_PHYS + (reg_IOMPU_GPU_base<<1),
HEX_SIZE_2000);

	MFDEC_BKA415_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_MFDEC_BKA415_base<<1),
HEX_SIZE_200);
	//dv_dbg(kbdev->dev, "MFDEC_BKA415_vaddr: 0x%lx, io_pa: 0x%x\n",
	//	MFDEC_BKA415_vaddr, IO_PHYS + (reg_MFDEC_BKA415_base<<1));
	GPU_MPU_BYPASS_vaddr =
			(ptrdiff_t)ioremap(IO_PHYS + (reg_GPU_MPU_BYPASS_base<<1), HEX_SIZE_200);
	//dev_dbg(kbdev->dev, "GPU_MPU_BYPASS_vaddr: 0x%lx, io_pa: 0x%x\n",
	//	GPU_MPU_BYPASS_vaddr, IO_PHYS + (reg_GPU_MPU_BYPASS_base<<1));
	CPU_MPU_BYPASS_vaddr =
			(ptrdiff_t)ioremap(IO_PHYS + (reg_CPU_MPU_BYPASS_base<<1), HEX_SIZE_200);
	//dev_dbg(kbdev->dev, "CPU_MPU_BYPASS_vaddr: 0x%lx, io_pa: 0x%x\n",
	//	CPU_MPU_BYPASS_vaddr, IO_PHYS + (reg_CPU_MPU_BYPASS_base<<1));
	X32_SMI_CTRL_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_X32_SMI_CTRL_base<<1),
HEX_SIZE_100);
	//dev_dbg(kbdev->dev, " X32_SMI_CTRL_vaddr: 0x%lx, io_pa: 0x%x\n",
	//	X32_SMI_CTRL_vaddr, IO_PHYS + (reg_X32_SMI_CTRL_base<<1));
	CKGEN1029_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_CKGEN1029_base<<1),
HEX_SIZE_100);
	//dev_dbg(kbdev->dev, "CKGEN1029_vaddr: 0x%lx, io_pa: 0x%x\n",
	//	CKGEN1029_vaddr, IO_PHYS + (reg_CKGEN1029_base<<1));
	CKGEN1035_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_CKGEN1035_base<<1),
HEX_SIZE_100);
	//dev_dbg(kbdev->dev, "CKGEN1035_vaddr: 0x%lx, io_pa: 0x%x\n",
	//	CKGEN1035_vaddr, IO_PHYS + (reg_CKGEN1035_base<<1));
	CKGEN1036_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_CKGEN1036_base<<1),
HEX_SIZE_100);
	//dev_dbg(kbdev->dev, "CKGEN1036_vaddr: 0x%lx, io_pa: 0x%x\n",
	//	CKGEN1036_vaddr, IO_PHYS + (reg_CKGEN1036_base<<1));
	CKGEN1037_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_CKGEN1037_base<<1),
HEX_SIZE_100);
	//	CKGEN1037_vaddr, IO_PHYS + (reg_CKGEN1037_base<<1));
	CKGEN103C_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_CKGEN103C_base<<1),
HEX_SIZE_100);
	//dev_dbg(kbdev->dev, "CKGEN103C_vaddr: 0x%lx, io_pa: 0x%x\n",
	//	CKGEN103C_vaddr, IO_PHYS + (reg_CKGEN103C_base<<1));
	CKGEN103A_vaddr             = (ptrdiff_t)ioremap(IO_PHYS + (reg_CKGEN103A_base<<1),
HEX_SIZE_2000);
	PM_POR_vaddr             = (ptrdiff_t)ioremap(IO_PHYS + (reg_PM_POR_base<<1),
HEX_SIZE_2000);
	TEST_CTRL_vaddr             = (ptrdiff_t)ioremap(IO_PHYS + (reg_TEST_CTRL_base<<1),
HEX_SIZE_2000);
	CKGENA040_vaddr             = (ptrdiff_t)ioremap(IO_PHYS + (reg_CKGENA040_base<<1),
HEX_SIZE_2000);
	MFDEC_BKA432_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_MFDEC_BKA432_base<<1),
HEX_SIZE_2000);
	MFDEC_BKA412_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_MFDEC_BKA412_base<<1),
HEX_SIZE_2000);
	MFDEC_BKA413_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_MFDEC_BKA413_base<<1),
		HEX_SIZE_100);
	MFDEC_BKA414_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_MFDEC_BKA414_base<<1),
		HEX_SIZE_100);
	MFDEC_BKA433_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_MFDEC_BKA433_base<<1),
HEX_SIZE_2000);


#else
	GPUBRDGPLL_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_GPUBRDGPLL_base<<1),
HEX_SIZE_100);
	CKGEN00_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_CKGEN00_base<<1),
HEX_SIZE_2000);
	CKGEN01_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_CKGEN01_base<<1),
HEX_SIZE_2000);
	TEST_CTRL_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_TEST_CTRL_base<<1),
HEX_SIZE_2000);
	SRAM_PD_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_SRAM_PD_base<<1),
HEX_SIZE_10000);
	TZPC_AID_0_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_TZPC_AID_0_base<<1),
HEX_SIZE_200);
	X32_GPU_vaddr             = (ptrdiff_t)ioremap(IO_PHYS + (reg_X32_GPU_base<<1),
HEX_SIZE_200);

	IOMPU_GLOBAL_vaddr      = (ptrdiff_t)ioremap(IO_PHYS + (reg_IOMPU_GLOBAL_base<<1),
			HEX_SIZE_2000);
	IOMPU_GPU_vaddr      = (ptrdiff_t)ioremap(IO_PHYS + (reg_IOMPU_GPU_base<<1),
			HEX_SIZE_2000);

	MFDEC_BKA415_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_MFDEC_BKA415_base<<1),
			HEX_SIZE_200);
	MIU_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_MIU_base<<1), HEX_SIZE_10);
	X32_SMI_CTRL_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_X32_SMI_CTRL_base<<1),
HEX_SIZE_100);
	CKGEN1029_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_CKGEN1029_base<<1),
HEX_SIZE_100);
	CKGEN1035_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_CKGEN1035_base<<1),
HEX_SIZE_100);
	CKGEN1036_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_CKGEN1036_base<<1),
HEX_SIZE_100);
	CKGEN1037_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_CKGEN1037_base<<1),
HEX_SIZE_100);
	CKGEN103C_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_CKGEN103C_base<<1),
HEX_SIZE_100);

	CKGEN103A_vaddr             = (ptrdiff_t)ioremap(IO_PHYS + (reg_CKGEN103A_base<<1),
			HEX_SIZE_2000);
	PM_POR_vaddr             = (ptrdiff_t)ioremap(IO_PHYS + (reg_PM_POR_base<<1),
			HEX_SIZE_2000);
	TEST_CTRL_vaddr             = (ptrdiff_t)ioremap(IO_PHYS + (reg_TEST_CTRL_base<<1),
			HEX_SIZE_2000);
	CKGENA040_vaddr             = (ptrdiff_t)ioremap(IO_PHYS + (reg_CKGENA040_base<<1),
			HEX_SIZE_2000);
	MFDEC_BKA432_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_MFDEC_BKA432_base<<1),
			HEX_SIZE_2000);
	MFDEC_BKA412_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_MFDEC_BKA412_base<<1),
			HEX_SIZE_2000);
	MFDEC_BKA413_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_MFDEC_BKA413_base<<1),
			HEX_SIZE_100);
	MFDEC_BKA414_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_MFDEC_BKA414_base<<1),
			HEX_SIZE_100);
	MFDEC_BKA433_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_MFDEC_BKA433_base<<1),
			HEX_SIZE_2000);


#endif
}

void unmap_registers(struct kbase_device *kbdev)
{
#if defined(CONFIG_MALI_DEBUG) &&  defined(MTK_DTV_ZEBU)
	iounmap((void *)mtk_pm_vaddr);  // for debug only
	iounmap((void *)EMI_vaddr);
#endif
	iounmap((void *)GPUBRDGPLL_vaddr);
	iounmap((void *)CKGEN00_vaddr);
	iounmap((void *)CKGEN01_vaddr);
	iounmap((void *)SRAM_PD_vaddr);
	iounmap((void *)TZPC_AID_0_vaddr);
	iounmap((void *)X32_GPU_vaddr);
	iounmap((void *)IOMPU_GLOBAL_vaddr);
	iounmap((void *)MFDEC_BKA415_vaddr);
	iounmap((void *)MIU_vaddr);
	iounmap((void *)GPU_MPU_BYPASS_vaddr);
	iounmap((void *)CPU_MPU_BYPASS_vaddr);
	iounmap((void *)X32_SMI_CTRL_vaddr);
	iounmap((void *)CKGEN1029_vaddr);
	iounmap((void *)CKGEN1035_vaddr);
	iounmap((void *)CKGEN1036_vaddr);
	iounmap((void *)CKGEN1037_vaddr);
	iounmap((void *)CKGEN103C_vaddr);
}
#else  //#if (MALI_AUTO_IOREMAP == 1)
void map_registers(struct kbase_device *kbdev)
{
}
void unmap_registers(struct kbase_device *kbdev)
{
}
#endif
#endif //#ifdef MTK_DTV_DEVICE_TREE_PROBE

#define SHIFT_16 16
#define SHIFT_8 8
#define SIZE_2048 2048
#define SIZE_3072 3072


#if !defined(MTK_DTV_ZEBU)
static u16 get_dram_size_mb(struct kbase_device *kbdev)
{
	u32 miu_start = 0;
	u32 miu_end = 0;
	u32 dram_size_4kb = 0;
	u32 dram_size_mb = 0;

	miu_start = (GET_DW_REG(MIU, out_of_area_start_20_16) << SHIFT_16 |
		GET_DW_REG(MIU, out_of_area_start));
	miu_end = (GET_DW_REG(MIU, out_of_area_end_20_16) << SHIFT_16 |
		GET_DW_REG(MIU, out_of_area_end));
	dram_size_4kb = (miu_end > miu_start) ? (miu_end - miu_start) : 0;
	dram_size_mb = (dram_size_4kb >> SHIFT_8);
#if defined(CONFIG_MALI_DEBUG)
	dev_info(kbdev->dev, "dram_size_mb = %u Mbytes\n", dram_size_mb);
#endif
	debug_print("[GPU] %s, %d: dram_size_mb = %u Mbytes\n", __func__, __LINE__, dram_size_mb);
	if (dram_size_mb == 0) {
		dram_size_mb = SIZE_3072;
		dev_warn(kbdev->dev, "[%s][%d] Force dram_size_mb = %u Mbytes\n",
				__func__, __LINE__, dram_size_mb);
		debug_print("[GPU] %s, %d: Force dram_size_mb = %u Mbytes \n",
				__func__, __LINE__, dram_size_mb);
	}
	return (u16) dram_size_mb;
}
#endif

#define HEX_REG_VAL_2 0x2
#define HEX_REG_VAL_47 0x47
#define HEX_REG_VAL_44 0x44
#define DELAY_500_MISCOSECONDS 500
#define DELAY_100_MISCOSECONDS 100


static void init_gpubrgpll(struct kbase_device *kbdev)
{
	/* TINFO = "GPUBRDGPLL setting" */
#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: mali dev_dbg\n", __func__, __LINE__);
#endif

	/* TINFO = "GPUBRDGPLL gc_gpubrdgpll_ictrl=0x2" */
	SET_REG(GPUBRDGPLL, gc_gpubrdgpll_ictrl, HEX_REG_VAL_2);

#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: mali dev_dbg\n", __func__, __LINE__);
#endif

	/* TINFO = "GPUBRDGPLL gc_gpubrdgpll_output_div=0x0" */
	SET_REG(GPUBRDGPLL, gc_gpubrdgpll_output_div, 0x0);
#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: mali dev_dbg\n", __func__, __LINE__);
#endif
	/* TINFO = "GPUBRDGPLL gc_gpubrdgpll_loopdiv_second=0x44, 816mhz" */
	SET_REG(GPUBRDGPLL, gc_gpubrdgpll_loopdiv_second, HEX_REG_VAL_44);
#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: mali dev_dbg\n", __func__, __LINE__);
#endif
	/* TINFO = "GPUBRDGPLL pd_gpubrdgpll_postdiv=0x0" */
	SET_REG(GPUBRDGPLL, pd_gpubrdgpll_postdiv, 0x0);
#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: mali dev_dbg\n", __func__, __LINE__);
#endif
	/* TINFO = "GPUBRDGPLL pd_gpubrdgpll_clk_div30=0x0" */
	SET_REG(GPUBRDGPLL, pd_gpubrdgpll_clk_div30, 0x0);
#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: mali dev_dbg\n", __func__, __LINE__);
#endif
	/* TINFO = "GPUBRDGPLL pd_gpubrdgpll=0x0" */
	SET_REG(GPUBRDGPLL, pd_gpubrdgpll, 0x0);
#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: mali dev_dbg\n", __func__, __LINE__);
#endif
	/* TINFO = "pd_gpubrdgpll_clk_div1=0x0" */
	SET_REG(GPUBRDGPLL, pd_gpubrdgpll_clk_div1, 0x0);
#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: mali dev_dbg\n", __func__, __LINE__);
#endif
	/* TINFO = "GPUBRDGPLL start to wait for 500us" */
	udelay(DELAY_500_MISCOSECONDS);
	/* TINFO = "reg_pd_gpubrdgpll_clk_div1_dig=0x0" */
	SET_REG(GPUBRDGPLL, pd_gpubrdgpll_clk_div1_dig, 0x0);
#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: mali dev_dbg\n", __func__, __LINE__);
#endif
}

#define REG_HEX_2 2
#define REG_HEX_7 7
#define REG_HEX_A 0xa
#define REG_HEX_2E 0x2e

#define ZEBU_REG_MIU0_START_VAL 0x0400
#define ZEBU_REG_MIU0_END_VAL 0xffff
#define MAX_SLOPPROT_RETRY_CNT 100

static void init_gpu_bridge(struct kbase_device *kbdev)
{
#if defined(CONFIG_MALI_DEBUG)
	u16 val = 0;
#endif

#if SLPPROT_REG
	u16 cnt = 0;
#endif

#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: mali dev_dbg miu0 test before 0x(%x)\n",
		__func__, __LINE__, (int)val);
#endif
#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: mali dev_dbg miu0 test before 0x(%x)\n",
		__func__, __LINE__, (int)val);
#endif

	/* TINFO = "GPU CKG setting" */
	SET_REG(CKGEN00, ckg_g_xtal_12m_gpu_par_gp, 0x0);
#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: ckg_g_xtal_12m_gpu_par_gp 0x(%x)\n",
		__func__, __LINE__, GET_REG(CKGEN00, ckg_g_xtal_12m_gpu_par_gp));
#endif
	SET_REG(CKGEN00, ckg_g_xtal_24m_gpu_par_gp, 0x0);
#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: ckg_g_xtal_24m_gpu_par_gp 0x(%x)\n",
		__func__, __LINE__, GET_REG(CKGEN00, ckg_g_xtal_24m_gpu_par_gp));
#endif

#ifndef MTK_DTV_ZEBU
	//zebu can not use this clock reg
	//MFDec clk
	SET_REG(CKGEN00, ckg_g_disp_mfdec_gpu_par_gp, 0x0);
#endif

	SET_REG(CKGEN00, sw_en_gpu2gpu_par_gp, 0x1);
#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: sw_en_gpu2gpu_par_gp 0x(%x)\n",
		__func__, __LINE__, GET_REG(CKGEN00, sw_en_gpu2gpu_par_gp));
#endif
	SET_REG(CKGEN00, sw_en_xtal_12m2met, 0x1);
#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: ckg_g_xtal_12m_gpu_par_gp 0x(%x)\n",
		__func__, __LINE__, GET_REG(CKGEN00, sw_en_xtal_12m2met));
#endif
	// *((UINT16P)(APMCU_R iIUBASE+CKGEN00 + 0x513*4 )) = 0xffff;
	SET_REG(CKGEN00, sw_en_xtal_24m2syscount, 0x1);
#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: sw_en_xtal_24m2syscount 0x(%x)\n",
		__func__, __LINE__, GET_REG(CKGEN00, sw_en_xtal_24m2syscount));
#endif

#ifndef MTK_DTV_ZEBU
	//zebu can not use this clock reg
	//MFDec clk
	SET_REG(CKGEN01, sw_en_disp_mfdec2gpu_par_gp, 0x1);
#endif

	SET_REG(CKGEN01, sw_en_xtal_24m2gpu_par_gp_mbist, 0x1);
#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: sw_en_xtal_24m2gpu_par_gp_mbist 0x(%x)\n",
		__func__, __LINE__, GET_REG(CKGEN01, sw_en_xtal_24m2gpu_par_gp_mbist));
#endif

	//unmask mpu for dram accress
	SET_DW_REG(IOMPU_GPU, mpu_bypass_sel, 0);

#if defined(MTK_DTV_ZEBU)
#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: mali dev_dbg\n", __func__, __LINE__);
#endif
	SET_REG(X32_GPU, miu0_start, ZEBU_REG_MIU0_START_VAL);
	SET_REG(X32_GPU, miu0_end, ZEBU_REG_MIU0_END_VAL);
#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: mali dev_dbg\n", __func__, __LINE__);
#endif
#else
	// ToDo: Check dram size
#ifndef MTK_DTV_MIU0_BUS_BASE
#define MTK_DTV_MIU0_BUS_BASE 0x40000000
#endif
#define MIU_BASE_TO_MB(base)        ((base) >> 20)                   /* in MB */
	SET_REG(X32_GPU, miu0_start, MIU_BASE_TO_MB(MTK_DTV_MIU0_BUS_BASE));
	SET_REG(X32_GPU, miu0_end,
		MIU_BASE_TO_MB(MTK_DTV_MIU0_BUS_BASE) + get_dram_size_mb(kbdev));
#endif

	SET_REG(X32_GPU, mfdec_rreq_rd_len, REG_HEX_7);

#if defined(CONFIG_MALI_DEBUG)
dev_dbg(kbdev->dev, "[GPU] %s, %d: mali dev_dbg\n", __func__, __LINE__);
#endif

	SET_REG(X32_GPU, riu_legacy_en,                  0x0);
	SET_REG(X32_GPU, riu_legacy_die_en,              0x0);

	/* TINFO = "GPU soft reset" */
	SET_REG(X32_GPU, soft_reset, 0x0);

#if SLPPROT_REG
	/* TINFO = "gals slpport master set" */
	SET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_mst_slpprot_en, 0x1);
	val = GET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_mst_slpprot_rdy);
	while (val != 1) {
	/* TINFO = "waiting slpport ready=1" */
		cnt++;
		if (cnt >= MAX_SLOPPROT_RETRY_CNT) {
			dev_err(kbdev->dev,
				"[%s][%d] GALS error!! slpprot_rdy_MST is not equal to 1!!!\n",
				__func__, __LINE__);
			break;
		}
		udelay(DELAY_100_MISCOSECONDS);
		val = GET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_mst_slpprot_rdy);
	}
	cnt = 0;
	/* TINFO = "gals slpport slave set" */
	SET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_slv_slpprot_en, 0x1);
	val = GET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_slv_slpprot_rdy);
	while (val != 1) {
		/* TINFO = "waiting slpport ready=1" */
		cnt++;
		if (cnt >= MAX_SLOPPROT_RETRY_CNT) {
			dev_err(kbdev->dev,
				"[%s][%d] GALS error!! slpprot_rdy_SLV is not equal to 1!!!\n",
				__func__, __LINE__);
			break;
		}
		udelay(DELAY_100_MISCOSECONDS);
		val = GET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_slv_slpprot_rdy);
		}
	}
#endif

	SET_REG(X32_GPU, soft_reset, 0x1);

#if SLPPROT_REG
	/* TINFO = "gals slpport master release" */
	SET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_mst_slpprot_en, 0x0);
	/* TINFO = "gals slpport slave release" */
	SET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_slv_slpprot_en, 0x0);
#endif

	/* TINFO = "reg_soft_reset[0] = 0" */
	SET_REG(X32_GPU, soft_reset, 0x0);

}


void init_registers(struct kbase_device *kbdev)
{
	debug_print("[GPU] %s, %d:\n",  __func__, __LINE__);
	dev_dbg(kbdev->dev, "[GPU] %s mali dev_dbg\n", __func__);
	init_gpubrgpll(kbdev);
#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: mali dev_dbg\n", __func__, __LINE__);
#endif
	init_gpu_bridge(kbdev);
#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: mali dev_dbg\n", __func__, __LINE__);
#endif
#if MTK_DTV_GPU_MFDEC
	init_mfdec(kbdev);
#endif

#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s\n", __func__);
#endif
}

void power_on(struct kbase_device *kbdev)
{

	/* TINFO = "Power ON" */

#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: mali dev_dbg\n", __func__, __LINE__);
#endif

#if SLPPROT_REG
		/* TINFO = "gals slpport master release" */
		SET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_mst_slpprot_en, 0x0);
		/* TINFO = "gals slpport slave release" */
		SET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_slv_slpprot_en, 0x0);
#endif

	/* TINFO = "reg_soft_reset[0] = 0" */
	SET_REG(X32_GPU, soft_reset, 0x0); //BK_2ee900_00[0]  reg_soft_reset[0]

#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s\n", __func__);
#endif

#if TEST_MPU
	init_mpu(kbdev);
#endif

}

void power_off(struct kbase_device *kbdev)
{
#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: mali dev_dbg\n", __func__, __LINE__);
#endif

	/* TINFO = "Power OFF" */

#if MTK_DTV_GPU_MFDEC
	/* do not power off if any mfdec slot is occupied */
	if (mfdec_used_id != 0x0) {
#if defined(CONFIG_MALI_DEBUG)
		dev_dbg(kbdev->dev, "[MFDec] mfdec_used_id = 0x%x, do not power off!",
			mfdec_used_id);
#endif
		return;
	}
#endif

#if SLPPROT_REG
	u16 val = 0;
	u16 cnt = 0;

	/* TINFO = "gals slpport master set" */
	SET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_mst_slpprot_en, 0x1);
	val = GET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_mst_slpprot_rdy);
	while (val != 1) {
	/* TINFO = "waiting slpport ready=1" */
		cnt++;
		if (cnt >= MAX_SLOPPROT_RETRY_CNT) {
			dev_err(kbdev->dev,
				"[%s][%d] GALS error!! slpprot_rdy_MST is not equal to 1!!!\n",
				__func__, __LINE__);
			break;
		}
		udelay(DELAY_100_MISCOSECONDS);
		val = GET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_mst_slpprot_rdy);
	}
	cnt = 0;
	/* TINFO = "gals slpport slave set" */
	SET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_slv_slpprot_en, 0x1);
	val = GET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_slv_slpprot_rdy);
	while (val != 1) {
	/* TINFO = "waiting slpport ready=1" */
		cnt++;
		if (cnt >= MAX_SLOPPROT_RETRY_CNT) {
			dev_err(kbdev->dev,
				"[%s][%d] GALS error!! slpprot_rdy_SLV is not equal to 1!!!\n",
				__func__, __LINE__);
			break;
		}
		udelay(DELAY_100_MISCOSECONDS);
		val = GET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_slv_slpprot_rdy);
	}
#endif

	/* TINFO = "reg_soft_reset[0] = 1" */
	SET_REG(X32_GPU, soft_reset, 0x1);    //BK_2ee900_00[0]  reg_soft_reset[0]

#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: mali dev_dbg\n", __func__, __LINE__);
	dev_dbg(kbdev->dev, "[GPU] %s\n", __func__);
#endif
}


#ifdef MTK_DTV_ENABLE_PROTECT_MODE
void soft_reset(struct kbase_device *kbdev)
{
	u16 val = 0;
	u16 cnt = 0;

#if defined(CONFIG_MALI_DEBUG)
	dev_dbg(kbdev->dev, "[GPU] %s, %d: mali dev_dbg\n", __func__, __LINE__);
	dev_dbg(kbdev->dev, "[GPU] %s\n", __func__);
#endif

#if SLPPROT_REG
	/* TINFO = "gals slpport master set" */
	SET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_mst_slpprot_en, 0x1);
	val = GET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_mst_slpprot_rdy);
	while (val != 1) {
		/* TINFO = "waiting slpport ready=1" */
		cnt++;
		if (cnt >= MAX_SLOPPROT_RETRY_CNT) {
			dev_err(kbdev->dev,
				"[%s][%d] GALS error!! slpprot_rdy_MST is not equal to 1!!!\n",
				__func__, __LINE__);
			break;
		}
		udelay(DELAY_100_MISCOSECONDS);
		val = GET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_mst_slpprot_rdy);
	}
	cnt = 0;
	/* TINFO = "gals slpport slave set" */
	SET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_slv_slpprot_en, 0x1);
	val = GET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_slv_slpprot_rdy);
	while (val != 1) {
		/* TINFO = "waiting slpport ready=1" */
		cnt++;
		if (cnt >= MAX_SLOPPROT_RETRY_CNT) {
			dev_err(kbdev->dev,
				"[%s][%d] GALS error!! slpprot_rdy_SLV is not equal to 1!!!\n",
				__func__, __LINE__);
			break;
		}
		udelay(DELAY_100_MISCOSECONDS);
		val = GET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_slv_slpprot_rdy);
	}
#endif
	/* GPU secure sw reset will trigger below 3 items:
	 * 1. clear one-way register (0x5b[0], reg_gpu_dram_mask_en)
	 *    and let GPU use normal AID, which can only R/W normal MIU range.
	 * 2. trigger ARM GPU IP reset (ARM GPU reset will wait bus idle)
	 * 3. trigger MTK GPU bridge reset
	 */
	SET_REG(X32_GPU, secure_sw_reset, 1);
	udelay(1);

#if SLPPROT_REG
	/* TINFO = "gals slpport master release" */
	SET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_mst_slpprot_en, 0x0);
	/* TINFO = "gals slpport slave release" */
	SET_REG(X32_SMI_CTRL, reg_gpu02ip_wrap_gals_slv_slpprot_en, 0x0);
#endif

	SET_REG(X32_GPU, secure_sw_reset, 0);
}
#endif

#ifdef MTK_DTV_DISABLE_SHADER_CORES
u64 get_efuse_disabled_cores_mask(struct kbase_device *kbdev)
{
	return 0;
}
#endif

#if defined(CONFIG_MALI_DEBUG)
void stop_cpu(struct kbase_device *kbdev)
{
	// SET_REG(cpu, cpu_axi_stop, 0x1);
}
#endif

#define ZEBU_MIU_SIZE  2048

void get_dram_length(struct kbase_device *kbdev,
		u32 *miu0_length, u32 *miu1_length, u32 *miu2_length)
{
	//ToDo: Check dram size
#if defined(MTK_DTV_ZEBU)
	*miu0_length = ZEBU_MIU_SIZE; /*2G*/
#else
	*miu0_length = get_dram_size_mb(kbdev);
#endif
	*miu1_length = 0;
	*miu2_length = 0;
}
#ifdef MTK_DTV_ENABLE_PROTECT_MODE
void mtk_dtv_protected_mode_enable(struct kbase_device *kbdev)
{
	/* enable protected mode. This is an one-way register.
	 * for circuit block, this register control GPU to use GPU protected AID,
	 * GPU protected AID will limit GPU can only R/W secure MIU range and READ
	 * normal MIU range.
	 */
	SET_REG(X32_GPU, gpu_protect_mode, 1);
	SET_REG(X32_GPU, gpu_protect_mode, 0);
}
#endif
