// 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_mt5879_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)
{
    printk("[MPU] Check EMI!! \n");
    printk("[MPU] EMI 3a: 0x%08x\n", GET_DW_REG(EMI, emi0_testc_0));
    printk("[MPU] EMI 3c: 0x%08x\n", GET_DW_REG(EMI, emi0_testc_1));

    SET_DW_REG(EMI, emi0_testc_0, 0x62037);
    SET_DW_REG(EMI, emi0_testc_1, 0x38460000);

    printk("[MPU] EMI 3a: 0x%08x\n", GET_DW_REG(EMI, emi0_testc_0));
    printk("[MPU] EMI 3c: 0x%08x\n", GET_DW_REG(EMI, emi0_testc_1));

#if 0// Remove if FPGA_GC_STYLE =2
    SET_REG(X32_GPU, riu_legacy_en, 1);
    printk("[MPU] riu_legacy_en: 0x%04x\n", GET_REG(X32_GPU, riu_legacy_en));
    SET_REG(X32_GPU, riu_legacy_die_en, 1);
    printk("[MPU] riu_legacy_die_en: 0x%04x\n", GET_REG(X32_GPU, riu_legacy_die_en));
#endif

    /* Set MPU table base to DRAM offset phy:0x9000_0000 >> 12 (PHYS ADDR, 4k aligned) */
    SET_REG(IOMMU_GLOBAL, mpu_table_base_addr, 0x0000);
    printk("[MPU] mpu_table_base_addr: 0x%04x\n", GET_REG(IOMMU_GLOBAL, mpu_table_base_addr));
    SET_REG(IOMMU_GLOBAL, mpu_table_base_addr_19_16, 0x9);
    printk("[MPU] mpu_table_base_addr_19_16: 0x%04x\n", GET_REG(IOMMU_GLOBAL, mpu_table_base_addr_19_16));

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

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

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

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

#if EN_MPU
    /* Enable MPU for IOMMU global */
    SET_REG(IOMMU_GLOBAL,  iommu_mpu_enable, 0x1);
    printk("[MPU] mpu_enable: 0x%04x\n", GET_REG(IOMMU_GLOBAL, iommu_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: 0x8000_0000 (tex src) >> 2^18 (256K bytes aligned) */
#if 1
    SET_REG(IOMMU_GLOBAL, mpu_tlb_invalid_start, 0x2000);
    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, 0x2001);
    printk("[MPU] mpu_tlb_invalid_end: 0x%04x\n", GET_REG(IOMMU_GLOBAL, mpu_tlb_invalid_end));
#endif
    printk("[MPU] Get Default Setting: \n");
    printk("[MPU] mpu_enable: 0x%04x\n", GET_REG(IOMMU_GLOBAL, iommu_mpu_enable));
    printk("[MPU] mpu_enable_local: 0x%04x\n", GET_REG(X32_IOMMU_LOCAL_GPU, mpu_enable_local));
    printk("[MPU] mpu_tlb_invalid_mode: 0x%04x\n", GET_REG(IOMMU_GLOBAL, mpu_tlb_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));
#if 0
    printk("[MPU] mpu_bypass_table0_content [0:3]: 0x%04x\n", GET_REG(X32_IOMMU_BYPASS_TABLE0_GPU, mpu_bypass_table0_content));
    printk("[MPU] mpu_bypass_table1_content [0:3]: 0x%04x\n", GET_REG(X32_IOMMU_BYPASS_TABLE1_GPU, mpu_bypass_table1_content));
#endif
    printk("[MPU] End of Default Setting. \n");

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

}
#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 IOMMU_GLOBAL_vaddr;
ptrdiff_t X32_IOMMU_LOCAL_GPU_vaddr;
#if 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 GPU_GALS_vaddr;

void map_registers(struct kbase_device* kbdev)
{
#if defined(MTK_DTV_ZEBU)
    printk("map_registers(), IO_PHYS = 0x%x\n ", IO_PHYS);

    mtk_pm_vaddr = (ptrdiff_t)ioremap(IO_PHYS, 0xA000000); // for debug only
    printk("mtk_pm_vaddr: 0x%lx, io_pa: 0x%x \n", mtk_pm_vaddr, IO_PHYS);

    GPUBRDGPLL_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_GPUBRDGPLL_base<<1), 0x100);
    printk("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), 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("clkgen1_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), 0x10000);
    printk("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), 0x200);
    printk("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), 0x200);
    printk("X32_GPU_vaddr: 0x%lx, io_pa: 0x%x \n", X32_GPU_vaddr, IO_PHYS + (reg_X32_GPU_base<<1));
    IOMMU_GLOBAL_vaddr      = (ptrdiff_t)ioremap(IO_PHYS + (reg_IOMMU_GLOBAL_base<<1), 0x200);
    printk("IOMMU_GLOBALl_vaddr: 0x%lx, io_pa: 0x%x \n", IOMMU_GLOBAL_vaddr, IO_PHYS + (reg_IOMMU_GLOBAL_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));
    EMI_vaddr       = (ptrdiff_t)ioremap(IO_PHYS + (reg_EMI_base<<1) , 0x2000);
    printk("EMI_vaddr: 0x%lx, io_pa: 0x%x \n", EMI_vaddr, IO_PHYS + (reg_EMI_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));
    GPU_MPU_BYPASS_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_GPU_MPU_BYPASS_base<<1), 0x200);
    printk("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), 0x200);
    printk("CPU_MPU_BYPASS_vaddr: 0x%lx, io_pa: 0x%x \n", CPU_MPU_BYPASS_vaddr, IO_PHYS + (reg_CPU_MPU_BYPASS_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
    GPUBRDGPLL_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_GPUBRDGPLL_base<<1), 0x100);
    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), 0x10000);
    TZPC_AID_0_vaddr         = (ptrdiff_t)ioremap(IO_PHYS + (reg_TZPC_AID_0_base<<1), 0x200);
    X32_GPU_vaddr             = (ptrdiff_t)ioremap(IO_PHYS + (reg_X32_GPU_base<<1), 0x200);
    IOMMU_GLOBAL_vaddr      = (ptrdiff_t)ioremap(IO_PHYS + (reg_IOMMU_GLOBAL_base<<1), 0x200);
    X32_IOMMU_LOCAL_GPU_vaddr       = (ptrdiff_t)ioremap(IO_PHYS + (reg_X32_IOMMU_LOCAL_GPU_base<<1) , 0x200);
    MFDEC_BKA415_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_MFDEC_BKA415_base<<1), 0x200);
    MIU_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_MIU_base<<1), 0x10);
    GPU_GALS_vaddr     = (ptrdiff_t)ioremap(IO_PHYS + (reg_GPU_GALS_base<<1), 0x100);
#endif
}

void unmap_registers(struct kbase_device* kbdev)
{
#if defined(MTK_DTV_ZEBU)
    iounmap((void *)mtk_pm_vaddr);  // for debug only
#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 *)IOMMU_GLOBAL_vaddr);
    iounmap((void *)X32_IOMMU_LOCAL_GPU_vaddr);
#if defined(MTK_DTV_ZEBU)
    iounmap((void *)EMI_vaddr);
#endif
    iounmap((void *)MFDEC_BKA415_vaddr);
    iounmap((void *)MIU_vaddr);
    iounmap((void *)GPU_MPU_BYPASS_vaddr);
    iounmap((void *)CPU_MPU_BYPASS_vaddr);
    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(MIU, out_of_area_start_20_16) << 16 | GET_REG(MIU, out_of_area_start));
    miu_end = (GET_REG(MIU, out_of_area_end_20_16) << 16 | GET_REG(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

static void init_gpubrgpll(void)
{
    /* TINFO = "GPUBRDGPLL setting" */

    /* TINFO = "GPUBRDGPLL gc_gpubrdgpll_ictrl=0x1" */
    SET_REG(GPUBRDGPLL, gc_gpubrdgpll_ictrl, 0x1);
    /* TINFO = "GPUBRDGPLL gc_gpubrdgpll_loopdiv_first=0x01" */ //1130
    SET_REG(GPUBRDGPLL, gc_gpubrdgpll_loopdiv_first, 0x01);
    /* TINFO = "GPUBRDGPLL gc_gpubrdgpll_loopdiv_second=0x17" *///1130
    SET_REG(GPUBRDGPLL, gc_gpubrdgpll_loopdiv_second, 0x17);
    /* TINFO = "GPUBRDGPLL gc_gpubrdgpll_output_div=0x4" */
    SET_REG(GPUBRDGPLL, gc_gpubrdgpll_output_div, 0x4);
    /* TINFO = "GPUBRDGPLL test_gpubrdgpll=0x1010" *///1130
    SET_REG(GPUBRDGPLL, test_gpubrdgpll, 0x1010);
    /* TINFO = "GPUBRDGPLL pd_gpubrdgpll_postdiv=0x0" */
    SET_REG(GPUBRDGPLL, pd_gpubrdgpll_postdiv, 0x0);
    /* TINFO = "GPUBRDGPLL pd_gpubrdgpll=0x0" */
    SET_REG(GPUBRDGPLL, pd_gpubrdgpll, 0x0);
    /* TINFO = "GPUBRDGPLL start to wait 500us" */
    udelay(500);
    /* TINFO = "GPUBRDGPLL pd_gpubrdgpll_clk_div2=0x0" */
    SET_REG(GPUBRDGPLL, pd_gpubrdgpll_clk_div2, 0x0);
}

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

#if 0 /* HW simulation only*/
    SET_REG(TZPC_AID_0,  tzpc_page_table_walk_aid,       0x2a  );
    //dsim use AID   //*((UINT16P)(APMCU_RIUBASE+TZPC_AID_0 + 0x00*4 )) = 0x002a;
    SET_REG(TZPC_AID_0,  tzpc_gpu_aid,                   0x2a  );
    //dsim use AID  //*((UINT16P)(APMCU_RIUBASE+TZPC_AID_0 + 0x35*4 )) = 0x2a00;
    SET_REG(TZPC_AID_0,  tzpc_gpu_protected_aid,         0x2a  ); //dsim use AID
    //*((UINT16P)(APMCU_RIUBASE+TZPC_AID_0 + 0x36*4 )) = 0x002a;
#endif

    /* TINFO = "GPU CKG setting" */
    SET_REG(CKGEN00,    ckg_g_xtal_12m_gpu_par_gp,      0x0);
    //*((UINT16P)(APMCU_RIUBASE+CKGEN00 + 0x9e*4 )) = 0x0000;
    /* TINFO = "GPU CKG setting2" */
    SET_REG(CKGEN00,     ckg_g_xtal_24m_gpu_par_gp,      0x0);
    //*((UINT16P)(APMCU_RIUBASE+CKGEN00 + 0xa0*4 )) = 0x0000;
    /* TINFO = "GPU CKG setting3" */
    SET_REG(CKGEN00,     ckg_g_disp_mfdec_gpu_par_gp,    0x0);
    //*((UINT16P)(APMCU_RIUBASE+CKGEN00 + 0x49a*4 )) = 0x0000;
    SET_REG(CKGEN01,     ckg_g_mcu_nonpm_gpu_par_gp,     0x0);
    //*((UINT16P)(APMCU_RIUBASE+CKGEN01 + 0x414*4 )) = 0x0000;

    /* TINFO = "GPU SW_EN setting" */
    SET_REG(CKGEN00,     sw_en_gpu2gpu_par_gp,           0x1);
    //*((UINT16P)(APMCU_RIUBASE+CKGEN00 + 0x511*4 )) = 0xffff;
    SET_REG(CKGEN00,     sw_en_xtal_12m2met,             0x1);
    //*((UINT16P)(APMCU_RIUBASE+CKGEN00 + 0x513*4 )) = 0xffff;
    SET_REG(CKGEN00,     sw_en_xtal_24m2syscount,        0x1);
    //*((UINT16P)(APMCU_RIUBASE+CKGEN00 + 0x514*4 )) = 0xffff;
    SET_REG(CKGEN01,     sw_en_disp_mfdec2gpu_par_gp,    0x1);
    //*((UINT16P)(APMCU_RIUBASE+CKGEN01 + 0x559*4 )) = 0xffff;
    SET_REG(CKGEN01,     sw_en_mcu_nonpm2gpu_par_gp,     0x1);
    //*((UINT16P)(APMCU_RIUBASE+CKGEN01 + 0x6dd*4 )) = 0xffff;
    SET_REG(CKGEN01,     sw_en_xtal_24m2gpu_par_gp_mbist,0x1);
    //*((UINT16P)(APMCU_RIUBASE+CKGEN01 + 0x760*4 )) = 0xffff;

    /* TINFO = "GPUBRG init setting" */
    SET_REG(X32_GPU, riu_apb_en,                     0x1   );
#if defined(MTK_DTV_ZEBU)
    SET_REG(X32_GPU, miu0_start,                     0x0200);
    SET_REG(X32_GPU, miu0_end,                       0xffff);
#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, 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,              0x7   );
    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   );

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

    SET_REG(X32_GPU,     soft_reset,                     0x1   );

    SET_REG(GPU_GALS, slpprot_en_MST, 0x0);
    SET_REG(GPU_GALS, slpprot_en_SLV, 0x0);

    SET_REG(X32_GPU,     soft_reset,                     0x0   );
}

void init_registers(struct kbase_device* kbdev)
{
    init_gpubrgpll();
    init_gpu_bridge(kbdev);
#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)
{
    /* TINFO = "Power ON" */
 
    SET_REG(GPU_GALS, slpprot_en_MST, 0x0);
    SET_REG(GPU_GALS, slpprot_en_SLV, 0x0);

    /* 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)
    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!", mfdec_used_id);
#endif
        return;
    }
#endif

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

    /* TINFO = "Power OFF" */
    /* 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)
    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_MST, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_MST );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_MST is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_MST );
    }
    cnt = 0;
    SET_REG(GPU_GALS, slpprot_en_SLV, 0x1);
    val = GET_REG(GPU_GALS, slpprot_rdy_SLV );
    while (val != 1)
    {
        cnt++;
        if (cnt >= 100)
        {
            dev_err(kbdev->dev, "[%s][%d] GALS error!! slpprot_rdy_SLV is not equal to 1!!!\n", __func__, __LINE__);
            break;
        }
        udelay(100);
        val = GET_REG(GPU_GALS, slpprot_rdy_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_MST, 0x0);
    SET_REG(GPU_GALS, slpprot_en_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)
{
    return 0;
}
#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
