// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
 *
 * Copyright(C) 2023 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 "mali_kbase_platform_mtk_dtv.h"
#include "mali_kbase_platform_mtk_dtv_mt5896_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

#if TEST_MPU
void init_mpu(void)
{
    /* Set MPU table base to DRAM offset phy:0x2000_0000 >> 12 (PHYS ADDR, 4k aligned) */
    SET_REG(IOMMU_GLOBAL, mpu_table_base_low, 0x0000);
    printk("[MPU] mpu_table_base_low: 0x%04x\n", GET_REG(IOMMU_GLOBAL, mpu_table_base_low));
    SET_REG(IOMMU_GLOBAL, mpu_table_base_high, 0x2);
    printk("[MPU] mpu_table_base_high: 0x%04x\n", GET_REG(IOMMU_GLOBAL, mpu_table_base_high));

    /* Set MPU area0 start phy:0x1000_0000 >> 20 (PHYS ADDR) */
    SET_REG(IOMMU_GLOBAL, mpu_area0_start, 0x100);
    printk("[MPU] mpu_area0_start: 0x%04x\n", GET_REG(IOMMU_GLOBAL, mpu_area0_start));

    /* Set MPU area0 end phy:0x1000_4000 */
    SET_REG(IOMMU_GLOBAL, mpu_area0_end, 0x101);
    printk("[MPU] mpu_area0_end: 0x%04x\n", GET_REG(IOMMU_GLOBAL, mpu_area0_end));

    /* Set MPU area1 start */
    SET_REG(IOMMU_GLOBAL, mpu_area1_start, 0xffff);
    printk("[MPU] mpu_area1_start: 0x%04x\n", GET_REG(IOMMU_GLOBAL, mpu_area1_start));
    /* Set MPU area1 end */
    SET_REG(IOMMU_GLOBAL, mpu_area1_end, 0xffff);
    printk("[MPU] mpu_area1_end: 0x%04x\n", GET_REG(IOMMU_GLOBAL, mpu_area1_end));

    /* Update MPU table base & area */
    SET_REG(IOMMU_GLOBAL, mpu_table_update, 0x00);
    SET_REG(IOMMU_GLOBAL, mpu_table_update, 0x01);
    printk("[MPU] mpu_table_update: 0x%04x\n", GET_REG(IOMMU_GLOBAL, mpu_table_update));

#if EN_MPU
    /* Enable MPU for IOMMU global */
    SET_REG(IOMMU_GLOBAL,  mpu_enable, 0x0);
    SET_REG(IOMMU_GLOBAL,  mpu_enable, 0x1);
    printk("[MPU] mpu_enable: 0x%04x\n", GET_REG(IOMMU_GLOBAL, mpu_enable));
    SET_REG(X32_IOMMU_LOCAL_GPU, mpu_enable_local, 0xffff);
    printk("[MPU] mpu_enable_local: 0x%04x\n", GET_REG(X32_IOMMU_LOCAL_GPU, mpu_enable_local));
#endif

    /* Bypass Table Invalidate Cache Setting, Working when mpu_byp_table_enable = 1*/
    // PHY: 0x1000_0000 (tex src) >> 2^18 (256K bytes aligned) */
    SET_REG(IOMMU_GLOBAL, mpu_tlb_invalid_start, 0x400);
    printk("[MPU] mpu_tlb_invalid_start: 0x%04x\n", GET_REG(IOMMU_GLOBAL, mpu_tlb_invalid_start));
    SET_REG(IOMMU_GLOBAL, mpu_tlb_invalid_end, 0x401);
    printk("[MPU] mpu_tlb_invalid_end: 0x%04x\n", GET_REG(IOMMU_GLOBAL, mpu_tlb_invalid_end));

    printk("[MPU] Get Default Setting: \n");
    printk("[MPU] mpu_enable: 0x%04x\n", GET_REG(IOMMU_GLOBAL, mpu_enable));
    printk("[MPU] mpu_enable_local: 0x%04x\n", GET_REG(X32_IOMMU_LOCAL_GPU, mpu_enable_local));
    printk("[MPU] mpu_table_invalid_mode: 0x%04x\n", GET_REG(IOMMU_GLOBAL, mpu_table_invalid_mode));
    printk("[MPU] mpu_byp_table_enable: 0x%04x\n", GET_REG(X32_IOMMU_LOCAL_GPU, mpu_byp_table_enable));
    printk("[MPU] mpu_byp_table_debug_enable: 0x%04x\n", GET_REG(X32_IOMMU_LOCAL_GPU, mpu_byp_table_debug_enable));
    printk("[MPU] mpu_byp_table_entry_size: 0x%04x\n", GET_REG(X32_IOMMU_LOCAL_GPU, mpu_byp_table_entry_size));
    printk("[MPU] mpu_bypass_table_content [0:3]: 0x%04x\n", GET_REG(X32_IOMMU_BYPASS_TABLE0_GPU, mpu_bypass_table_content));
    printk("[MPU] End of Default Setting. \n");

#if 0 // Invalidate Fire
    SET_REG(mpu_table_invalid_mode, 0); // 0: invalidate by range, 1: Invalidate all
    SET_REG(iommu_mpu_tlb_invalid_fire, 0);
    SET_REG(iommu_mpu_tlb_invalid_fire, 1);
#endif

#if 0 /* Enable bypass table check*/
    SET_REG(mpu_bypass, mpu_bypass_table_content, 0x0f);
    printk("[MPU] mpu_bypass_table_content: 0x%04x\n", GET_REG(mpu_bypass, mpu_bypass_table_content));
    SET_REG(X32_IOMMU_LOCAL_GPU, mpu_bypass_table_size, 0x00);
    printk("[MPU] mpu_bypass_table_size: 0x%04x\n", GET_REG(X32_IOMMU_LOCAL_GPU, mpu_bypass_table_size));

    SET_REG(X32_IOMMU_LOCAL_GPU, mpu_byp_table_enable, 0x1); //default 0: disable
    printk("[MPU] mpu_byp_table_enable: 0x%04x\n", GET_REG(X32_IOMMU_LOCAL_GPU, mpu_byp_table_enable));

    SET_REG(X32_IOMMU_LOCAL_GPU, mpu_byp_table_debug_enable, 0x1);
    printk("[MPU] mpu_byp_table_debug_enable: 0x%04x\n", GET_REG(X32_IOMMU_LOCAL_GPU, mpu_byp_table_debug_enable));
#endif
}
#endif

/* Platform functions */


#ifdef MTK_DTV_DEVICE_TREE_PROBE

#if (MALI_AUTO_IOREMAP == 1)
#ifndef IO_PHYS
#define IO_PHYS 0x000000001C000000
#endif

//reg = <0x0 0x1c5e0000 0x0 0x4000>, /*2F00, mali*/
//      <0x0 0x1c5dc000 0x0  0x200>, /*2EE0, X32_GPU_DIE*/
//      <0x0 0x1c5dc200 0x0  0x200>, /*2EE1, X32_IOMMU_BYPASS_TABLE0_GPU*/
//      <0x0 0x1c5dc400 0x0  0x200>, /*2EE2, X32_IOMMU_BYPASS_TABLE1_GPU*/
//      <0x0 0x1c5dc600 0x0  0x200>, /*2EE3, gpu2miu_mask*/
//      <0x0 0x1c5dce00 0x0  0x200>, /*2EE7, X32_IOMMU_LOCAL_GPU*/
//      <0x0 0x1c5dd200 0x0  0x200>, /*2EE9, X32_GPU*/
//      <0x0 0x1c5dd600 0x0  0x200>, /*2EEB, gpu_ror_w*/
//      <0x0 0x1c5dd800 0x0  0x200>, /*2EEC, gpu_ror_r*/
//      <0x0 0x1c201c00 0x0  0x200>, /*0x100e, armpll*/
//      <0x0 0x1c204000 0x0 0x2000>, /*0x1020, CKGEN00*/
//      <0x0 0x1c206000 0x0 0x2000>, /*0x1030, CKGEN01*/
//      <0x0 0x1c220000 0x0 0x4000>, /*0x1100, sram_pd*/
//      <0x0 0x1c241c00 0x0  0x200>, /*0x120e, IOMMU_GLOBAL*/
//      <0x0 0x1d482a00 0x0  0x200>; /*0xa415, gpu_mfdec*/
//      <0x0 0x1c400400 0x0  0x200>; /*0x2002, cpu*/
//      <0x0 0x1c37e800 0x0  0x200>; /*0x1BF4, X32_MIU*/
//      <0x0 0x1c025200 0x0  0x200>; /*0x0129, efuse0*/

ptrdiff_t pm_top_vaddr;
ptrdiff_t X32_GPU_DIE_vaddr;
ptrdiff_t X32_IOMMU_BYPASS_TABLE0_GPU_vaddr;
ptrdiff_t X32_IOMMU_BYPASS_TABLE1_GPU_vaddr;
ptrdiff_t gpu2miu_mask_vaddr;
ptrdiff_t X32_IOMMU_LOCAL_GPU_vaddr;
ptrdiff_t X32_GPU_vaddr;
ptrdiff_t gpu_ror_w_vaddr;
ptrdiff_t gpu_ror_r_vaddr;
ptrdiff_t GPUBRDGPLL_vaddr;
ptrdiff_t armpll_vaddr;
ptrdiff_t CKGEN00_vaddr;
ptrdiff_t CKGEN01_vaddr;
ptrdiff_t SRAM_PD_vaddr;
ptrdiff_t IOMMU_GLOBAL_vaddr;
ptrdiff_t MFDEC_BKA415_vaddr;
#if defined(CONFIG_MALI_DEBUG)
ptrdiff_t cpu_vaddr;
#endif
ptrdiff_t X32_MIU_vaddr;
ptrdiff_t efuse0_vaddr;
#ifdef MTK_DTV_GPU_THERMAL
ptrdiff_t pm_misc_vaddr;
#endif
ptrdiff_t GPU_GALS_vaddr;

void map_registers(struct kbase_device* kbdev)
{
#if defined(CONFIG_MALI_DEBUG) && (defined(MTK_DTV_ZEBU) || defined(MTK_DTV_HAPS))
    printk("map_registers(), IO_PHYS = 0x%x\n ", IO_PHYS);
    pm_top_vaddr          = (ptrdiff_t)ioremap(IO_PHYS + (reg_pm_top_base<<1), 0x10);
    printk("pm_top_vaddr: 0x%lx, io_pa: 0x%x \n", pm_top_vaddr, IO_PHYS + (reg_pm_top_base<<1));
    X32_GPU_DIE_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_X32_GPU_DIE_base<<1), 0x200);
    printk("X32_GPU_DIE_vaddr: 0x%lx, io_pa: 0x%x \n", X32_GPU_DIE_vaddr, IO_PHYS + (reg_X32_GPU_DIE_base<<1));
    X32_IOMMU_BYPASS_TABLE0_GPU_vaddr = (ptrdiff_t)ioremap(IO_PHYS + (reg_X32_IOMMU_BYPASS_TABLE0_GPU_base<<1), 0x200);
    printk("X32_IOMMU_BYPASS_TABLE0_GPU_vaddr: 0x%lx, io_pa: 0x%x \n", X32_IOMMU_BYPASS_TABLE0_GPU_vaddr, IO_PHYS + (reg_X32_IOMMU_BYPASS_TABLE0_GPU_base<<1));
    X32_IOMMU_BYPASS_TABLE1_GPU_vaddr = (ptrdiff_t)ioremap(IO_PHYS + (reg_X32_IOMMU_BYPASS_TABLE1_GPU_base<<1), 0x200);
    printk("X32_IOMMU_BYPASS_TABLE1_GPU_vaddr: 0x%lx, io_pa: 0x%x \n", X32_IOMMU_BYPASS_TABLE1_GPU_vaddr, IO_PHYS + (reg_X32_IOMMU_BYPASS_TABLE1_GPU_base<<1));
    gpu2miu_mask_vaddr    = (ptrdiff_t)ioremap(IO_PHYS + (reg_gpu2miu_mask_base<<1), 0x200);
    printk("gpu2miu_mask_vaddr: 0x%lx, io_pa: 0x%x \n", gpu2miu_mask_vaddr, IO_PHYS + (reg_gpu2miu_mask_base<<1));
    X32_IOMMU_LOCAL_GPU_vaddr       = (ptrdiff_t)ioremap(IO_PHYS + (reg_X32_IOMMU_LOCAL_GPU_base<<1) , 0x200);
    printk("X32_IOMMU_LOCAL_GPU_vaddr: 0x%lx, io_pa: 0x%x \n", X32_IOMMU_LOCAL_GPU_vaddr, IO_PHYS + (reg_X32_IOMMU_LOCAL_GPU_base<<1));
    X32_GPU_vaddr             = (ptrdiff_t)ioremap(IO_PHYS + (reg_X32_GPU_base<<1), 0x200);
    printk("X32_GPU_vaddr: 0x%lx, io_pa: 0x%x \n", X32_GPU_vaddr, IO_PHYS + (reg_X32_GPU_base<<1));
    gpu_ror_w_vaddr       = (ptrdiff_t)ioremap(IO_PHYS + (reg_gpu_ror_w_base<<1), 0x200);
    printk("gpu_ror_w_vaddr: 0x%lx, io_pa: 0x%x \n", gpu_ror_w_vaddr, IO_PHYS + (reg_gpu_ror_w_base<<1));
    gpu_ror_r_vaddr       = (ptrdiff_t)ioremap(IO_PHYS + (reg_gpu_ror_r_base<<1), 0x200);
    printk("gpu_ror_r_vaddr: 0x%lx, io_pa: 0x%x \n", gpu_ror_r_vaddr, IO_PHYS + (reg_gpu_ror_r_base<<1));
    GPUBRDGPLL_vaddr      = (ptrdiff_t)ioremap(IO_PHYS + (reg_GPUBRDGPLL_base<<1), 0x100);//add for m6e3
    printk("GPUBRDGPLL_vaddr: 0x%lx, io_pa: 0x%x \n", GPUBRDGPLL_vaddr, IO_PHYS + (reg_GPUBRDGPLL_base<<1));
    armpll_vaddr          = (ptrdiff_t)ioremap(IO_PHYS + (reg_armpll_base<<1), 0x200);
    printk("armpll_vaddr: 0x%lx, io_pa: 0x%x \n", armpll_vaddr, IO_PHYS + (reg_armpll_base<<1));
    CKGEN00_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_CKGEN00_base<<1), 0x2000);
    printk("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), 0x2000);
    printk("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), 0x4000);
    printk("SRAM_PD_vaddr: 0x%lx, io_pa: 0x%x \n", SRAM_PD_vaddr, IO_PHYS + (reg_SRAM_PD_base<<1));
    IOMMU_GLOBAL_vaddr      = (ptrdiff_t)ioremap(IO_PHYS + (reg_IOMMU_GLOBAL_base<<1), 0x200);
    printk("IOMMU_GLOBAL_vaddr: 0x%lx, io_pa: 0x%x \n", IOMMU_GLOBAL_vaddr, IO_PHYS + (reg_IOMMU_GLOBAL_base<<1));
    MFDEC_BKA415_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_MFDEC_BKA415_base<<1), 0x200);
    printk("MFDEC_BKA415_vaddr: 0x%lx, io_pa: 0x%x \n", MFDEC_BKA415_vaddr, IO_PHYS + (reg_MFDEC_BKA415_base<<1));
    cpu_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_cpu_base<<1), 0x200);
    printk("cpu_vaddr: 0x%lx, io_pa: 0x%x \n", cpu_vaddr, IO_PHYS + (reg_cpu_base<<1));
    X32_MIU_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_X32_MIU_base<<1), 0x10);
    printk("X32_MIU_vaddr: 0x%lx, io_pa: 0x%x \n", X32_MIU_vaddr, IO_PHYS + (reg_X32_MIU_base<<1));
    efuse0_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_efuse0_base<<1), 0x200);
    printk("efuse0_vaddr: 0x%lx, io_pa: 0x%x \n", efuse0_vaddr, IO_PHYS + (reg_efuse0_base<<1));
    GPU_GALS_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_GPU_GALS_base<<1), 0x100);
    printk("GPU_GALS_vaddr: 0x%lx, io_pa: 0x%x \n", GPU_GALS_vaddr, IO_PHYS + (reg_GPU_GALS_base<<1));
#else
    pm_top_vaddr          = (ptrdiff_t)ioremap(IO_PHYS + (reg_pm_top_base<<1), 0x10);
    X32_GPU_DIE_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_X32_GPU_DIE_base<<1), 0x200);
    X32_IOMMU_BYPASS_TABLE0_GPU_vaddr = (ptrdiff_t)ioremap(IO_PHYS + (reg_X32_IOMMU_BYPASS_TABLE0_GPU_base<<1), 0x200);
    X32_IOMMU_BYPASS_TABLE1_GPU_vaddr = (ptrdiff_t)ioremap(IO_PHYS + (reg_X32_IOMMU_BYPASS_TABLE1_GPU_base<<1), 0x200);
    gpu2miu_mask_vaddr    = (ptrdiff_t)ioremap(IO_PHYS + (reg_gpu2miu_mask_base<<1), 0x200);
    X32_IOMMU_LOCAL_GPU_vaddr       = (ptrdiff_t)ioremap(IO_PHYS + (reg_X32_IOMMU_LOCAL_GPU_base<<1) , 0x200);
    X32_GPU_vaddr             = (ptrdiff_t)ioremap(IO_PHYS + (reg_X32_GPU_base<<1), 0x200);
    gpu_ror_w_vaddr       = (ptrdiff_t)ioremap(IO_PHYS + (reg_gpu_ror_w_base<<1), 0x200);
    gpu_ror_r_vaddr       = (ptrdiff_t)ioremap(IO_PHYS + (reg_gpu_ror_r_base<<1), 0x200);
    GPUBRDGPLL_vaddr      = (ptrdiff_t)ioremap(IO_PHYS + (reg_GPUBRDGPLL_base<<1), 0x100);//add for m6e3
    armpll_vaddr          = (ptrdiff_t)ioremap(IO_PHYS + (reg_armpll_base<<1), 0x200);
    CKGEN00_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_CKGEN00_base<<1), 0x2000);
    CKGEN01_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_CKGEN01_base<<1), 0x2000);
    SRAM_PD_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_SRAM_PD_base<<1), 0x4000);
    IOMMU_GLOBAL_vaddr      = (ptrdiff_t)ioremap(IO_PHYS + (reg_IOMMU_GLOBAL_base<<1), 0x200);
    MFDEC_BKA415_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_MFDEC_BKA415_base<<1), 0x200);
#if defined(CONFIG_MALI_DEBUG)
    cpu_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_cpu_base<<1), 0x200);
#endif
    X32_MIU_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_X32_MIU_base<<1), 0x10);
    efuse0_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_efuse0_base<<1), 0x200);
#ifdef MTK_DTV_GPU_THERMAL
    pm_misc_vaddr    = (ptrdiff_t)ioremap(IO_PHYS + (reg_pm_misc_base<<1), 0x100);
#endif
    GPU_GALS_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_GPU_GALS_base<<1), 0x100);
#endif
}

void unmap_registers(struct kbase_device* kbdev)
{
    iounmap((void *)pm_top_vaddr);
    iounmap((void *)X32_GPU_DIE_vaddr);
    iounmap((void *)X32_IOMMU_BYPASS_TABLE0_GPU_vaddr);
    iounmap((void *)X32_IOMMU_BYPASS_TABLE1_GPU_vaddr);
    iounmap((void *)gpu2miu_mask_vaddr);
    iounmap((void *)X32_IOMMU_LOCAL_GPU_vaddr);
    iounmap((void *)X32_GPU_vaddr);
    iounmap((void *)gpu_ror_w_vaddr);
    iounmap((void *)gpu_ror_r_vaddr);
    iounmap((void *)GPUBRDGPLL_vaddr); //add for m6e3
    iounmap((void *)armpll_vaddr);
    iounmap((void *)CKGEN00_vaddr);
    iounmap((void *)CKGEN01_vaddr);
    iounmap((void *)SRAM_PD_vaddr);
    iounmap((void *)IOMMU_GLOBAL_vaddr);
    iounmap((void *)MFDEC_BKA415_vaddr);
#if defined(CONFIG_MALI_DEBUG)
    iounmap((void *)cpu_vaddr);
#endif
    iounmap((void *)X32_MIU_vaddr);
    iounmap((void *)efuse0_vaddr);
#ifdef MTK_DTV_GPU_THERMAL
    iounmap((void *)pm_misc_vaddr);
#endif
    iounmap((void *)GPU_GALS_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

#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_REG(X32_MIU, out_of_area_start_20_16) << 16 | GET_REG(X32_MIU, out_of_area_start));
    miu_end = (GET_REG(X32_MIU, out_of_area_end_20_16) << 16 | GET_REG(X32_MIU, out_of_area_end));
    dram_size_4kb = (miu_end > miu_start) ? (miu_end - miu_start) : 0;
    dram_size_mb = (dram_size_4kb >> 8);
#if defined(CONFIG_MALI_DEBUG)
    dev_info(kbdev->dev, "dram_size_mb = %u Mbytes\n", dram_size_mb);
#endif
    if (dram_size_mb == 0)
    {
        dram_size_mb = 2048;
        dev_warn(kbdev->dev, "[%s][%d] Force dram_size_mb = %u Mbytes\n", __func__, __LINE__, dram_size_mb);
    }

    return (u16) dram_size_mb;
}
#endif

void init_registers(struct kbase_device* kbdev)
{
    u16 val = 0;
    u16 cnt = 0;

    u16 isM6E3 = 0;

    dev_info(kbdev->dev, "chip_id = 0x%4X", GET_REG(pm_top, chip_id));
    dev_info(kbdev->dev, "chip_version = 0x%4X", GET_REG(pm_top, chip_version));
    dev_info(kbdev->dev, "chip_revision = 0x%4X", GET_REG(pm_top, chip_revision));
    isM6E3 = (GET_REG(pm_top, chip_revision) == 0x2) ? 1 : 0;

    /* set GPU clock */
    SET_REG(CKGEN00, clkgen_sel, 0x03);

#if defined(MTK_DTV_ZEBU)
    SET_REG(armpll, clk_lo, 0x4128);
    SET_REG(armpll, clk_hi, 0x005e);
#else
    SET_REG(armpll, clk_lo, (MHZ_TO_REG(MALI_MAX_FREQ)>> 0)&0xffff);
    SET_REG(armpll, clk_hi, (MHZ_TO_REG(MALI_MAX_FREQ)>>16)&0xffff);
#endif

    SET_REG(armpll, sld, 0x1);
    if (isM6E3)
    {
        SET_REG(armpll, armpll_ictrl, 0x1);
    }
    else
    {
        SET_REG(armpll, armpll_ictrl, 0x3);
    }
    SET_REG(armpll, armpll_loop_div_1st, 0x3);
    SET_REG(armpll, armpll_loop_div_2nd, 0x6);
    SET_REG(armpll, armpll_en_occ_div128, 0x1);
    SET_REG(armpll, armpll_pd_droop_bypass, 0x0);
    SET_REG(armpll, armpll_pd_vringcmp, 0x1);
    SET_REG(armpll, armpll_en_cpuclk, 0x1);
    SET_REG(armpll, armpll_en_occclk2, 0x1);
    SET_REG(armpll, armpll_pd, 0x0);

    udelay(1); //ToDo: Check GPU PLL need to wait for 500 us when lock ?

    if (isM6E3)
    {
        SET_REG(GPUBRDGPLL, gc_gpubrdpll_output_div, 0x4);
        SET_REG(GPUBRDGPLL, gc_gpubrdpll_input_div, 0x0);
        SET_REG(GPUBRDGPLL, gc_gpubrdpll_loopdiv_first, 0x0);
        SET_REG(GPUBRDGPLL, gc_gpubrdpll_loopdiv_second, 0x4a);
        SET_REG(GPUBRDGPLL, pd_gpubrdpll_postdiv, 0x0);
        SET_REG(GPUBRDGPLL, pd_gpubrdpll_clk_div30, 0x0);
        SET_REG(GPUBRDGPLL, pd_gpubrdpll, 0x0);
        udelay(500);
        SET_REG(GPUBRDGPLL, pd_gpubrdpll_clk_div5, 0x0);
        SET_REG(GPUBRDGPLL, pd_gpubrdpll_clk_div1, 0x0);
        SET_REG(GPUBRDGPLL, pd_gpubrdpll_clk_div2, 0x0);
        SET_REG(GPUBRDGPLL, pd_gpubrdpll_clk_div3, 0x0);
    }
    else
    {
        SET_REG(CKGEN00, gc_gpubrdpll_output_div, 0x4);
        SET_REG(CKGEN00, gc_gpubrdpll_input_div, 0x0);
        SET_REG(CKGEN00, gc_gpubrdpll_loopdiv_first, 0x0);
        SET_REG(CKGEN00, gc_gpubrdpll_loopdiv_second, 0x4a);
        SET_REG(CKGEN00, pd_gpubrdpll_postdiv, 0x0);
        SET_REG(CKGEN00, pd_gpubrdpll, 0x0);
        udelay(500);
        SET_REG(CKGEN00, pd_gpubrdpll_clk_div2p5, 0x0);
        SET_REG(CKGEN00, pd_gpubrdpll_clk_div2, 0x0);
    }
    /* enable RIU */
#ifdef MTK_DTV_RIU_ENABLED
    SET_REG(X32_GPU_DIE, riu_apb_en, 0x1);
#endif

    /* set MIU addr */
#if defined(MTK_DTV_ZEBU)
    SET_REG(X32_GPU_DIE, miu0_start, 0x0200); /*for zebu only, 2G*/
    SET_REG(X32_GPU_DIE, miu0_end, 0x0A00);  /*for zebu only, 2G*/
#else
    // ToDo: Check dram size
#ifndef MTK_DTV_MIU0_BUS_BASE
#define MTK_DTV_MIU0_BUS_BASE 0x20000000
#endif
#define MIU_BASE_TO_MB(base)        ((base) >> 20)                   /* in MB */

    SET_REG(X32_GPU_DIE, miu0_start, MIU_BASE_TO_MB(MTK_DTV_MIU0_BUS_BASE));
    SET_REG(X32_GPU_DIE, 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, 0x7);
    SET_REG(CKGEN00, ckg_bridge_gpu_nodie, 0);
    SET_REG(CKGEN00, ckg_gpu_gpu_die, 0);
    SET_REG(CKGEN00, ckg_shader_core, 0);
    SET_REG(CKGEN00, ckg_xtal_24m_gpu_die, 0);
    SET_REG(CKGEN00, ckg_xtal_24m_gpu_nodie, 0);
    SET_REG(CKGEN00, ckg_xtal_24m_gpu_shader, 0);
    SET_REG(CKGEN00, ckg_xtal_12m_gpu_die, 0);

    /* Enable mfdec clock */
    SET_REG(CKGEN00, ckg_g_disp_mfdec, 0);             // bank: 0x1020, reg: 0x49a, bit[0]
    SET_REG(CKGEN00, ckg_disp_mfdec_gpu_nodie, 0);  // bank: 0x1020, reg: 0x49a, bit[8]
    if (isM6E3)
    {
        SET_REG(CKGEN00, ckg_g_disp_mfdec_gpu, 0); // bank: 0x1020, reg: 0x49a, bit[10]
    }

    SET_REG(CKGEN00, sw_en_bridge2gpu_nodie, 1);
    SET_REG(CKGEN00, sw_en_gpu2_gpudie, 1);
    SET_REG(CKGEN00, sw_en_sc2shader, 1);

    SET_REG(CKGEN00, sw_en_xtal_12m2met, 1);
    SET_REG(CKGEN00, sw_en_xtal_24m2syscount, 1);
    SET_REG(CKGEN00, sw_en_xtal_24m2xtal, 1);

    SET_REG(CKGEN01, ckg_mcu_nonpm_gpu_die, 0);
    SET_REG(CKGEN01, ckg_mcu_nonpm_gpu_nodie, 0);
    SET_REG(CKGEN01, sw_en_disp_mfdec2gpu_nodie, 1);
    SET_REG(CKGEN01, sw_en_mcu_nonpm2_gpu_die, 1);
    SET_REG(CKGEN01, sw_en_mcu_nonpm2_gpu_nodie, 1);
    SET_REG(CKGEN01, sw_en_riu_nonpm2riu_dft_gpu_nodie, 1);
    udelay(1);

    SET_REG(X32_GPU, soft_reset, 0);    /* de-assert MALI soft reset */

    SET_REG(GPU_GALS, slpprot_en_gpu02ip_MST, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu02ip_MST );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu02ip_MST is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu02ip_MST );
    }
    cnt = 0;
    SET_REG(GPU_GALS, slpprot_en_gpu02ip_SLV, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu02ip_SLV );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu02ip_SLV is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu02ip_SLV);
    }

    cnt = 0;
    SET_REG(GPU_GALS, slpprot_en_gpu12ip_MST, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu12ip_MST );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu12ip_MST is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu12ip_MST );
    }
    cnt = 0;
    SET_REG(GPU_GALS, slpprot_en_gpu12ip_SLV, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu12ip_SLV );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu12ip_SLV is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu12ip_SLV);
    }

    cnt = 0;
    SET_REG(GPU_GALS, slpprot_en_gpu22ip_MST, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu22ip_MST );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu22ip_MST is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu22ip_MST );
    }
    cnt = 0;
    SET_REG(GPU_GALS, slpprot_en_gpu22ip_SLV, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu22ip_SLV );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu22ip_SLV is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu22ip_SLV);
    }

    cnt = 0;
    SET_REG(GPU_GALS, slpprot_en_gpu2ssc7_MST, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu2ssc7_MST );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu2ssc7_MST is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu2ssc7_MST );
    }
    cnt = 0;
    SET_REG(GPU_GALS, slpprot_en_gpu2ssc7_SLV, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu2ssc7_SLV );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu2ssc7_SLV is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu2ssc7_SLV);
    }

    SET_REG(X32_GPU, soft_reset, 1);    /* assert MALI soft reset */

    SET_REG(GPU_GALS, slpprot_en_gpu02ip_MST, 0x0);
    SET_REG(GPU_GALS, slpprot_en_gpu02ip_SLV, 0x0);
    SET_REG(GPU_GALS, slpprot_en_gpu12ip_MST, 0x0);
    SET_REG(GPU_GALS, slpprot_en_gpu12ip_SLV, 0x0);
    SET_REG(GPU_GALS, slpprot_en_gpu22ip_MST, 0x0);
    SET_REG(GPU_GALS, slpprot_en_gpu22ip_SLV, 0x0);
    SET_REG(GPU_GALS, slpprot_en_gpu2ssc7_MST, 0x0);
    SET_REG(GPU_GALS, slpprot_en_gpu2ssc7_SLV, 0x0);

    SET_REG(X32_GPU, soft_reset, 0);    /* de-assert MALI soft reset */
    udelay(1);

    /* NOTICE!!!!! WROR and RROR trigger must be set after bridge register is init or reset!!!! */
    /* trigger WROR hw arb update */
    SET_REG(gpu_ror_w, wror_miu_hw_arb_update, 0x0);
    SET_REG(gpu_ror_w, wror_miu_hw_arb_update, 0x1);
    /* trigger RROR hw arb update */
    SET_REG(gpu_ror_r, rror_miu_hw_arb_update, 0x0);
    SET_REG(gpu_ror_r, rror_miu_hw_arb_update, 0x1);
    udelay(1);

    SET_REG(X32_GPU, riu_legacy_mode, 0x0);
    SET_REG(X32_GPU_DIE, riu_die_legacy_mode, 0x0);

#if MTK_DTV_GPU_MFDEC
    init_mfdec(kbdev);
#endif

#if defined(CONFIG_MALI_DEBUG)
    printk("[GPU] init_registers()\n");
#endif
}

void power_on(struct kbase_device* kbdev)
{
    SET_REG(CKGEN00, sw_en_bridge2gpu_nodie, 1);
    SET_REG(CKGEN00, sw_en_gpu2_gpudie, 1);
    SET_REG(CKGEN00, sw_en_sc2shader, 1);

    SET_REG(SRAM_PD, glb_sram_pd_reg_gpu, 0);
    SET_REG(SRAM_PD, glb_sram_pd_reg_gpu_die, 0);
    SET_REG(SRAM_PD, glb_sram_pd_reg_shader_core0, 0);
    SET_REG(SRAM_PD, glb_sram_pd_reg_shader_core1, 0);
    SET_REG(SRAM_PD, glb_sram_pd_reg_shader_core2, 0);

    SET_REG(GPU_GALS, slpprot_en_gpu02ip_MST, 0x0);
    SET_REG(GPU_GALS, slpprot_en_gpu02ip_SLV, 0x0);
    SET_REG(GPU_GALS, slpprot_en_gpu12ip_MST, 0x0);
    SET_REG(GPU_GALS, slpprot_en_gpu12ip_SLV, 0x0);
    SET_REG(GPU_GALS, slpprot_en_gpu22ip_MST, 0x0);
    SET_REG(GPU_GALS, slpprot_en_gpu22ip_SLV, 0x0);
    SET_REG(GPU_GALS, slpprot_en_gpu2ssc7_MST, 0x0);
    SET_REG(GPU_GALS, slpprot_en_gpu2ssc7_SLV, 0x0);

    /* PULL DOWN GPU RESET */
    SET_REG(X32_GPU, soft_reset, 0);
    udelay(1);

    /* NOTICE!!!!! WROR and RROR trigger must be set after bridge register is init or reset!!!! */
    /* trigger WROR hw arb update */
    SET_REG(gpu_ror_w, wror_miu_hw_arb_update, 0x0);
    SET_REG(gpu_ror_w, wror_miu_hw_arb_update, 0x1);
    /* trigger RROR hw arb update */
    SET_REG(gpu_ror_r, rror_miu_hw_arb_update, 0x0);
    SET_REG(gpu_ror_r, rror_miu_hw_arb_update, 0x1);

#if defined(CONFIG_MALI_DEBUG)
    printk("[GPU] power_on()\n");
#endif

#if TEST_MPU
    init_mpu();
#endif
}

void power_off(struct kbase_device* kbdev)
{
    u16 val = 0;
    u16 cnt = 0;

#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)
        printk("[MFDec] mfdec_used_id = 0x%x, do not power off!\n", mfdec_used_id);
#endif
        return;
    }
#endif

    SET_REG(GPU_GALS, slpprot_en_gpu02ip_MST, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu02ip_MST );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu02ip_MST is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu02ip_MST );
    }
    cnt = 0;
    SET_REG(GPU_GALS, slpprot_en_gpu02ip_SLV, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu02ip_SLV );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu02ip_SLV is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu02ip_SLV);
    }

    cnt = 0;
    SET_REG(GPU_GALS, slpprot_en_gpu12ip_MST, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu12ip_MST );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu12ip_MST is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu12ip_MST );
    }
    cnt = 0;
    SET_REG(GPU_GALS, slpprot_en_gpu12ip_SLV, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu12ip_SLV );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu12ip_SLV is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu12ip_SLV);
    }

    cnt = 0;
    SET_REG(GPU_GALS, slpprot_en_gpu22ip_MST, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu22ip_MST );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu22ip_MST is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu22ip_MST );
    }
    cnt = 0;
    SET_REG(GPU_GALS, slpprot_en_gpu22ip_SLV, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu22ip_SLV );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu22ip_SLV is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu22ip_SLV);
    }

    cnt = 0;
    SET_REG(GPU_GALS, slpprot_en_gpu2ssc7_MST, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu2ssc7_MST );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu2ssc7_MST is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu2ssc7_MST );
    }
    cnt = 0;
    SET_REG(GPU_GALS, slpprot_en_gpu2ssc7_SLV, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu2ssc7_SLV );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu2ssc7_SLV is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu2ssc7_SLV);
    }

    /* PULL DOWN GPU RESET */
    SET_REG(X32_GPU, soft_reset, 1);

    SET_REG(SRAM_PD, glb_sram_pd_reg_gpu, 1);
    SET_REG(SRAM_PD, glb_sram_pd_reg_gpu_die, 1);
    SET_REG(SRAM_PD, glb_sram_pd_reg_shader_core0, 1);
    SET_REG(SRAM_PD, glb_sram_pd_reg_shader_core1, 1);
    SET_REG(SRAM_PD, glb_sram_pd_reg_shader_core2, 1);

    SET_REG(CKGEN00, sw_en_bridge2gpu_nodie, 0);
    SET_REG(CKGEN00, sw_en_gpu2_gpudie, 0);
    SET_REG(CKGEN00, sw_en_sc2shader, 0);

    udelay(1);

#if defined(CONFIG_MALI_DEBUG)
    printk("[GPU] power_off()\n");
#endif
}

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

    SET_REG(GPU_GALS, slpprot_en_gpu02ip_MST, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu02ip_MST );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu02ip_MST is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu02ip_MST );
    }
    cnt = 0;
    SET_REG(GPU_GALS, slpprot_en_gpu02ip_SLV, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu02ip_SLV );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu02ip_SLV is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu02ip_SLV);
    }

    cnt = 0;
    SET_REG(GPU_GALS, slpprot_en_gpu12ip_MST, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu12ip_MST );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu12ip_MST is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu12ip_MST );
    }
    cnt = 0;
    SET_REG(GPU_GALS, slpprot_en_gpu12ip_SLV, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu12ip_SLV );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu12ip_SLV is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu12ip_SLV);
    }

    cnt = 0;
    SET_REG(GPU_GALS, slpprot_en_gpu22ip_MST, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu22ip_MST );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu22ip_MST is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu22ip_MST );
    }
    cnt = 0;
    SET_REG(GPU_GALS, slpprot_en_gpu22ip_SLV, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu22ip_SLV );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu22ip_SLV is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu22ip_SLV);
    }

    cnt = 0;
    SET_REG(GPU_GALS, slpprot_en_gpu2ssc7_MST, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu2ssc7_MST );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu2ssc7_MST is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu2ssc7_MST );
    }
    cnt = 0;
    SET_REG(GPU_GALS, slpprot_en_gpu2ssc7_SLV, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_gpu2ssc7_SLV );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_gpu2ssc7_SLV is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_gpu2ssc7_SLV);
    }

     /* 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);

    SET_REG(GPU_GALS, slpprot_en_gpu02ip_MST, 0x0);
    SET_REG(GPU_GALS, slpprot_en_gpu02ip_SLV, 0x0);
    SET_REG(GPU_GALS, slpprot_en_gpu12ip_MST, 0x0);
    SET_REG(GPU_GALS, slpprot_en_gpu12ip_SLV, 0x0);
    SET_REG(GPU_GALS, slpprot_en_gpu22ip_MST, 0x0);
    SET_REG(GPU_GALS, slpprot_en_gpu22ip_SLV, 0x0);
    SET_REG(GPU_GALS, slpprot_en_gpu2ssc7_MST, 0x0);
    SET_REG(GPU_GALS, slpprot_en_gpu2ssc7_SLV, 0x0);

    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)
{
    u16 disable_core1 = 0;
    u16 disable_core2 = 0;
    u64 disabled_cores_mask = 0;

    disable_core1 = GET_REG(efuse0, outb_overwrite_35); // 1: disable shader_core1, NATT TRM: SHADER_PRESENT_LO[2] stands for core1
    if (disable_core1 == 0x1)
    {
        disabled_cores_mask |= 0x4;
    }

    disable_core2 = GET_REG(efuse0, outb_overwrite_36); // 1: disable shader_core2, NATT TRM: SHADER_PRESENT_LO[16] stands for core2
    if (disable_core2 == 0x1)
    {
        disabled_cores_mask |= 0x10000;
    }

    return disabled_cores_mask;
}
#endif

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

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 = 2048; /*2G*/
#else
    *miu0_length = get_dram_size_mb(kbdev);
#endif
    *miu1_length = 0;
    *miu2_length = 0;

    return;
}
#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
