// 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_mt5876_reg.h"
#include <mtk_dtv_gpu_bridge.h>
#include <linux/delay.h>

#ifndef _KBASE_PLATFORM_MSTAR_MT5876_MFDEC_H_
#define _KBASE_PLATFORM_MSTAR_MT5876_MFDEC_H_

#define MAX_MFDEC_SLOT_NUM 16

#define FB_TYPE_L_BLD_BASE 0
#define FB_TYPE_L_BASE   1
#define FB_TYPE_PITCH    2
#define FB_TYPE_PROP     3
#define FB_TYPE_C_BLD_BASE   4
#define FB_TYPE_C_BASE   5
#define FB_TYPE_PROP_GPU     6

/* Encode Type, [1:0] tile mode, [2] compress */
#define ENCODE_TYPE_16x32 0
#define ENCODE_TYPE_VSD 3
#define ENCODE_TYPE_COMPRESS 4

/* For reg_fb_para_data of reg_prg_fb_type=3: frame buffer property */
#define FB_PROP_FLAG_LUMA10BPP                   (0x1 << 28)
#define FB_PROP_FLAG_CHROMA10BPP                 (0x1 << 29)
#define FB_PROP_FLAG_VSD8x4                      (0x1 << 31)
#define FB_PROP_FLAG_OUTPUT_EVEN_LINES_DATA      (0x1 << 30)
#define FB_PROP_FLAG_FB_BASE_REMAP_EN_BALANCE    (0x1 << 25)
#define FB_PROP_FLAG_FB_BASE_REMAP_EN_DDR4       (0x1 << 24)

#define BASE_OFFSET_16G_MASK                     0x300000000
#define BASE_ADDRESS_MASK                        0xFFFFFFFF

bridge_device mfdec_bridge;
const u8 max_mfdec_slot_num = MAX_MFDEC_SLOT_NUM;

#if defined(CONFIG_MALI_DEBUG)
#define mfdec_printk printk
#else
#define mfdec_printk(x...)
#endif

#define HW_AUTO_INVALIDATE_MODE 1

void init_mfdec_reg(void)
{
    mfdec_printk("[MFDec] %s()\n", __func__);

    /* Enable mfdec clock */
    SET_REG(CKGEN00, ckg_g_disp_mfdec, 0);            // bank: 0x1020, reg: 0x49a, bit[0]
    SET_REG(CKGEN00, ckg_g_disp_mfdec_gpu_par_gp, 0); // bank: 0x1020, reg: 0x49a, bit[8]
    SET_REG(CKGEN01, sw_en_disp_mfdec2gpu_par_gp, 1); // bank: 0x1030, reg: 0x559, bit[0]

    /***** GPU bridge init ******/
    /* 0: use shift to calculate (x, y) ; 1: use divider to calculate (x,y) */
    SET_REG(X32_GPU, mfdec_divider_en, 1);  // default: 1
    SET_REG(X32_GPU, mfdec_linear_mode, 0);  // bank:0x2ee9, reg:0x43, bit[0] /* Natt: support non-block linear mode only*/
    /* gpu initial reg_mfdec_off */
    SET_REG(X32_GPU, mfdec_off, 0); // reg: 0x66, bit [1]
    udelay(1);

    /* disp_mfdec ckgen setting on */
    SET_REG(CKGEN01, sw_en_xc_disp_mfdec2scip, 1); // clk_fbdec, 0x661, bit[0]
    SET_REG(CKGEN01, ckg_xc_disp_mfdec_scip, 0);   // clk_fbdec, 0x330, bit[0]
    SET_REG(CKGEN00, sw_en_smi2scip, 1);  //0x53B, bit[0]. Shared by B2R/B2R lite1/B2R lite2/GPU !!!!!

    SET_REG(MFDEC_BKA415, disp_mfdec_clk_gate, 0); // reg: 0x0, bit [12]
    SET_REG(MFDEC_BKA415, gpu_dec_sw_rst, 1);
    udelay(1);
    SET_REG(MFDEC_BKA415, gpu_dec_sw_rst, 0);

     /* gpu own disp_mfdec */
    SET_REG(MFDEC_BKA415, vde_xpu_sel, 1);             // reg:0x0, bit[6]    << check for detile case??
    SET_REG(MFDEC_BKA415, mfdec_xpu_sel, 1);           // reg:0x1, bit[0]    << check for detile case??
    SET_REG(MFDEC_BKA415, gpu_mfdec_map, 1);           // reg:0x1, bit[4], 1: use mfdec engine
    /* disp_mfdec init_en */ /* REG 0x6 =0x100 */
    SET_REG(MFDEC_BKA415, disp_mfdec_int_mask, 0);     // reg: 0x6, bit [7:0]
    SET_REG(MFDEC_BKA415, disp_mfdec_int_en, 1);       // reg: 0x6, bit [8]

#if HW_AUTO_INVALIDATE_MODE
    /* disp_mfdec gpu_main_ctrl: hw auto invalidate mode */
    SET_REG(MFDEC_BKA415, gpu_main_ctrl_mode, 1);
    /*  Reset GPU AID control registers */
    SET_REG(MFDEC_BKA415, gpu_aid_rst, 1);
    /* disp_mfdec gpu frame start */
    SET_REG(MFDEC_BKA415, dec_frame_start_xpu, 1);
#else
    mfdec_printk("[MFDec] %s(): sw invalidate mode\n", __func__);
    /* disp_mfdec gpu_main_ctrl: sw invalidate mode */
    SET_REG(MFDEC_BKA415, gpu_main_ctrl_mode, 3);
    /* invalidate cache to insure the correctness */
    SET_REG(MFDEC_BKA415, tagram_inv, 1);  // This is for mfdec decode frame cache
    SET_REG(MFDEC_BKA415, tagram_inv_gpu, 1);   // SW force mfdec cache tag ram invalidate for gpu path
#endif

}

void init_mfdec(struct kbase_device* kbdev)
{
    init_bridge_device(kbdev, &mfdec_bridge);
    init_mfdec_reg();
}

int get_mfdec_slot(struct kbase_device* kbdev, u8 *id)
{
    *id = acquire_slot(kbdev, &mfdec_bridge, MAX_MFDEC_SLOT_NUM);
    if (*id == 0xFF)
        return -1;
    else
        return 0;
}

int set_mfdec_bridge(struct kbase_device* kbdev, u8 id, u64 base, u32 height, u32 pitch)
{
    u32 size_y, size_uv;
    u64 base_uv;
    u16 valid_id = 0x0;

    mfdec_printk("[MFDec] %s() id=%d, base=0x%llx, height=%d, pitch=%d\n", __func__, id, base, height, pitch);

    /* Make sure soft_reset is pulled down when setting bridge registers.
     * The internal register cannot be updated if soft_reset is pulled up.
     */
    if (GET_REG(X32_GPU, soft_reset) == 0x1) {
        power_on(kbdev);
#if defined(CONFIG_MALI_DEBUG)
        printk("[MFDec] soft_reset=1, pull down GPU reset.");
#endif
    }

    SET_REG(X32_GPU, mfdec_adr_idx, (id & 0xF));

    /* [pitch] ex: 4K, 3840 or 4096(2^n)
      * divider mode : 16 bytes alignment  (Bank: 0x2ee9 Reg: 42, bit[14] 1: use divider)
      * non-divider mode : 2 ^ n bytes alignment
      */
    SET_REG(X32_GPU, video_pitch, pitch);

    /* Bifrost MMU table is bus address */
    size_y = ((pitch * height + 0xFFF) >> 12) << 12;
    base_uv = base + size_y;
    /* size of YUV_420SP(NV12) format */
    size_uv = ((2 * (pitch * height / 4) + 0xFFF) >> 12) << 12;

    /* Set start & end addr of luma & chroma (4K byte unit, bus address) */
    SET_REG(X32_GPU, mfdec_y_start_15_00, base >> 12);
    SET_REG(X32_GPU, mfdec_y_start_21_16, base >> 28);
    SET_REG(X32_GPU, mfdec_y_end_15_00, (base + size_y) >> 12);
    SET_REG(X32_GPU, mfdec_y_end_21_16, (base + size_y) >> 28);
    SET_REG(X32_GPU, mfdec_uv_start_15_00, base_uv >> 12);
    SET_REG(X32_GPU, mfdec_uv_start_21_16, base_uv >> 28);
    SET_REG(X32_GPU, mfdec_uv_end_15_00, (base_uv + size_uv) >> 12);
    SET_REG(X32_GPU, mfdec_uv_end_21_16, (base_uv + size_uv) >> 28);

    /* Update & clean */
    SET_REG(X32_GPU, mfdec_adr_update,    0x1);
    SET_REG(X32_GPU, mfdec_adr_update,    0x0);

    /* Set valid vector, do not clear any valid bit while GPU is working */
    valid_id = GET_REG(X32_GPU, mfdec_valid);
    valid_id |= (0x1 << id);
    SET_REG_NO_CLEAR(X32_GPU, mfdec_valid, (valid_id & 0xFFFF));

#if defined(CONFIG_MALI_DEBUG)
    dump_slot_status(kbdev);
#endif

    return 0;
}

int set_mfdec_detile(struct kbase_device* kbdev, u8 id, u64 video_ybase, u64 video_uvbase, u32 pitch, u32 tile_mode, u32 flags)
{
    /* frame buffer property */
    u16 fb_property_lo = 0;
    u16 fb_property_hi = 0;
    u16 luma_offset_to_16g = 0;
    u16 chroma_offset_to_16g = 0;

    mfdec_printk("[MFDec] %s() id=%d, video_ybase=0x%llx, video_uvbase=0x%llx, pitch=%d, tile=%d, flags=0x%x\n",
                    __func__, id, video_ybase, video_uvbase, pitch, tile_mode, flags);

    /* Set frame buffer index */
    SET_REG(MFDEC_BKA415, prg_fb_idx, id);

    /* Set frame buffer luma base */
    SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_L_BASE);
    SET_REG(MFDEC_BKA415, fb_para_data_0, (video_ybase & BASE_ADDRESS_MASK) >> 6);    //[21:6]: 64 byte unit
    SET_REG(MFDEC_BKA415, fb_para_data_1, (video_ybase & BASE_ADDRESS_MASK) >> 22); //[37:22]: 64 byte unit
    luma_offset_to_16g = (video_ybase & BASE_OFFSET_16G_MASK) >> 30;
    fb_property_lo |=  (luma_offset_to_16g << 4); //[ 7: 4] : luma base address offset to support miu upto 16G (for UMA)
    udelay(1);

    /* Set frame buffer chroma base */
    SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_C_BASE);
    SET_REG(MFDEC_BKA415, fb_para_data_0, (video_uvbase  & BASE_ADDRESS_MASK) >> 6);    //[21:6]: 64 byte unit
    SET_REG(MFDEC_BKA415, fb_para_data_1, (video_uvbase  & BASE_ADDRESS_MASK) >> 22); //[37:22]: 64 byte unit
    chroma_offset_to_16g = (video_uvbase & BASE_OFFSET_16G_MASK) >> 30;
    fb_property_lo |=  (chroma_offset_to_16g << 8); //[11:8] : chroma base address offset to support miu upto 16G (for UMA)
    udelay(1);

    /* Set frame buffer pitch */
    SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_PITCH);
    SET_REG(MFDEC_BKA415, fb_para_data_0, ((pitch + 0xf)  >> 4) << 4); //pixel unit (16pixel alignment)
    SET_REG(MFDEC_BKA415, fb_para_data_1, 0x0);
    udelay(1);
    /* Set frame buffer property */
    SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_PROP);

#if defined(CONFIG_MALI_DEBUG)
    if (flags & FB_PROP_FLAG_FB_BASE_REMAP_EN_DDR4)                   //[24] : frame buffer address re-map enable for DDR4
        fb_property_hi |= (FB_PROP_FLAG_FB_BASE_REMAP_EN_DDR4 >> 16);
    if (flags & FB_PROP_FLAG_FB_BASE_REMAP_EN_BALANCE)                //[25] : frame buffer address re-map enable for channel balance
        fb_property_hi |= (FB_PROP_FLAG_FB_BASE_REMAP_EN_BALANCE >> 16);
    if (flags & FB_PROP_FLAG_OUTPUT_EVEN_LINES_DATA)                  //[30] : output even lines (top field) data
        fb_property_hi |= (FB_PROP_FLAG_OUTPUT_EVEN_LINES_DATA >> 16);
    if (flags & FB_PROP_FLAG_LUMA10BPP)                               //[28] : Luma is 10bpp mode
        fb_property_hi |= (FB_PROP_FLAG_LUMA10BPP >> 16);
    if (flags & FB_PROP_FLAG_CHROMA10BPP)                             //[29] : Chroma is 10bpp mode
        fb_property_hi |= (FB_PROP_FLAG_CHROMA10BPP >> 16);
    if (flags & FB_PROP_FLAG_VSD8x4)                                  //[31] : VSD 1:8x4, 0:8x2
        fb_property_hi |= (FB_PROP_FLAG_VSD8x4 >> 16);

    mfdec_printk("[MFDec] => fb_property_lo = 0x%8x\n", fb_property_lo);
    mfdec_printk("[MFDec] => fb_property_hi = 0x%8x\n", fb_property_hi);
#else
    fb_property_hi |= (flags >> 16);
#endif

    switch (tile_mode)
    {
    case ENCODE_TYPE_16x32:
        mfdec_printk("[MFDec] => ENCODE_TYPE_16x32\n");
        SET_REG(MFDEC_BKA415, fb_para_data_0, fb_property_lo | ENCODE_TYPE_16x32); // [1:0] tile mode, [2] compress
        SET_REG(MFDEC_BKA415, fb_para_data_1, fb_property_hi);  // [29:28] bpp, [31] 8x4
        break;

    case ENCODE_TYPE_VSD:
        mfdec_printk("[MFDec] => ENCODE_TYPE_VSD\n");
        SET_REG(MFDEC_BKA415, fb_para_data_0, fb_property_lo |ENCODE_TYPE_VSD); // [1:0] tile mode, [2] compress
        SET_REG(MFDEC_BKA415, fb_para_data_1, fb_property_hi);  // [29:28] bpp, [31] 8x4
        break;

    default:
        mfdec_printk("[MFDec] => Unsupported Encode Type!\n");
        break;
    }
    udelay(1);

	/* check gpu_active is meaningless in current mfdec driver architecture */
#if 0
    udelay(50); // delay 9T to make sure that mfdec is ready.
    //Todo: check gpu_active = 1?
    if (GET_REG(MFDEC_BKA415, gpu_active) != 1)
    {
        mfdec_printk("[WARN!!!!!!!!!!!!][MFDec] GPU should be active!! But gpu_active is 0x%04x. \n", GET_REG(MFDEC_BKA415, gpu_active));
    }
#endif

    return 0;
}

int set_mfdec_decode(struct kbase_device* kbdev, u8 id, u64 video_ybase, u64 video_uvbase, u64 BLDbase, u64 BLDuvbase, u32 pitch, u32 codec_type, u32 flags)
{
    /* frame buffer property */
    u16 fb_property_lo = 0;
    u16 fb_property_hi = 0;
    u16 bitlen_offset_to_16g = 0;
    u16 luma_offset_to_16g = 0;
    u16 chroma_offset_to_16g = 0;

    mfdec_printk("[MFDec] %s() id=%d, video_ybase=0x%llx, video_uvbase=0x%llx, BLDbase=0x%llx, BLDuvbase=0x%llx, pitch=%d, codec_type=%d, flags=0x%x\n",
                    __func__, id, video_ybase, video_uvbase, BLDbase,  BLDuvbase, pitch, codec_type, flags);

#if 0
    if (0 == GET_REG(MFDEC_BKA415, mfdec_xpu_sel)) // ToDo: check Reg 0x01 bit[0:2]
    {
        printk(KERN_DEBUG "!!![Mali] XPU_SEL = 0, Re-init GPU-MFDEC\n");
        init_mfdec_reg();
    }
#endif

    /* Set frame buffer index */
    SET_REG(MFDEC_BKA415, prg_fb_idx, id);

    /* Set frame buffer bitlength base */
    SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_L_BLD_BASE);
    SET_REG(MFDEC_BKA415, fb_para_data_0, (BLDbase & BASE_ADDRESS_MASK)  >> 6);  //[21:6]: 64 byte unit
    SET_REG(MFDEC_BKA415, fb_para_data_1, (BLDbase & BASE_ADDRESS_MASK) >> 22); //[29:22]: 64 byte unit
    bitlen_offset_to_16g = (BLDbase & BASE_OFFSET_16G_MASK) >> 30;
    fb_property_lo |=  (bitlen_offset_to_16g << 12); //[15:12] : bitlen base address offset to support miu upto 16G (for UMA)
    udelay(1);

	/*
	SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_C_BLD_BASE);
    SET_REG(MFDEC_BKA415, fb_para_data_0, (BLDuvbase & BASE_ADDRESS_MASK) >> 6);   //[21:6]: 64 byte unit
    SET_REG(MFDEC_BKA415, fb_para_data_1, (BLDuvbase & BASE_ADDRESS_MASK) >> 22); //[29:22]: 64 byte unit
    udelay(1);
    printk("[MFDec] prg_fb_type: 0x%04x\n", GET_REG(MFDEC_BKA415, prg_fb_type));
    printk("[MFDec] fb_para_data_low: 0x%04x, real: 0x%04x\n", GET_REG(MFDEC_BKA415, fb_para_data_0), (u16)((BLDuvbase >> 6) & 0xFFFF));
    printk("[MFDec] fb_para_data_high: 0x%04x, real: 0x%04x\n", GET_REG(MFDEC_BKA415, fb_para_data_1),(u16)((BLDuvbase >> 22) & 0xFFFF));
    */

    SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_L_BASE);
    SET_REG(MFDEC_BKA415, fb_para_data_0, (video_ybase & BASE_ADDRESS_MASK) >> 6);     //[21:6]: 64 byte unit
    SET_REG(MFDEC_BKA415, fb_para_data_1, (video_ybase & BASE_ADDRESS_MASK) >> 22); //[29:22]: 64 byte unit
    luma_offset_to_16g = (video_ybase & BASE_OFFSET_16G_MASK) >> 30;
    fb_property_lo |=  (luma_offset_to_16g << 4); //[ 7: 4] : luma base address offset to support miu upto 16G (for UMA)
    udelay(1);
    SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_C_BASE);
    SET_REG(MFDEC_BKA415, fb_para_data_0, (video_uvbase & BASE_ADDRESS_MASK) >> 6);   //[21:6]: 64 byte unit
    SET_REG(MFDEC_BKA415, fb_para_data_1, (video_uvbase & BASE_ADDRESS_MASK) >> 22); //[29:22]: 64 byte unit
    chroma_offset_to_16g = (video_uvbase & BASE_OFFSET_16G_MASK) >> 30;
    fb_property_lo |=  (chroma_offset_to_16g << 8); //[11:8] : chroma base address offset to support miu upto 16G (for UMA
    udelay(1);
    /* Set frame buffer pitch */
    SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_PITCH);
    SET_REG(MFDEC_BKA415, fb_para_data_0, ((pitch + 0x7f) >> 7) << 6); //pixel unit (16pixel alignment)
    SET_REG(MFDEC_BKA415, fb_para_data_1, 0x0);
    udelay(1);
    /* Set frame buffer property */
    SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_PROP);
    SET_REG(MFDEC_BKA415, fb_para_data_0, fb_property_lo | ENCODE_TYPE_COMPRESS); // [1:0] tile mode, [2] compress

#if defined(CONFIG_MALI_DEBUG)
    if (flags & FB_PROP_FLAG_FB_BASE_REMAP_EN_DDR4)      //[24] : frame buffer address re-map enable for DDR4
        fb_property_hi |= (FB_PROP_FLAG_FB_BASE_REMAP_EN_DDR4 >> 16);
    if (flags & FB_PROP_FLAG_FB_BASE_REMAP_EN_BALANCE) //[25] : frame buffer address re-map enable for channel balance
        fb_property_hi |= (FB_PROP_FLAG_FB_BASE_REMAP_EN_BALANCE >> 16);
    if (flags & FB_PROP_FLAG_OUTPUT_EVEN_LINES_DATA)     //[30] : output even lines (top field) data
        fb_property_hi |= (FB_PROP_FLAG_OUTPUT_EVEN_LINES_DATA >> 16);
    if (flags & FB_PROP_FLAG_LUMA10BPP)                             //[28] : Luma is 10bpp mode
        fb_property_hi |= (FB_PROP_FLAG_LUMA10BPP >> 16);
    if (flags & FB_PROP_FLAG_CHROMA10BPP)                        //[29] : Chroma is 10bpp mode
        fb_property_hi |= (FB_PROP_FLAG_CHROMA10BPP >> 16);
    if (flags & FB_PROP_FLAG_VSD8x4)                                  //[31] : VSD 1:8x4, 0:8x2
        fb_property_hi |= (FB_PROP_FLAG_VSD8x4 >> 16);
    mfdec_printk("[MFDec] => fb_property_lo = 0x%8x\n", fb_property_lo);
    mfdec_printk("[MFDec] => fb_property_hi = 0x%8x\n", fb_property_hi);
#else
    fb_property_hi |= (flags >> 16);
#endif

    SET_REG(MFDEC_BKA415, fb_para_data_1, fb_property_hi);   // [29:28] bpp, [31] 8x4
    udelay(1);

	/* check gpu_active is meaningless in current mfdec driver architecture */
#if 0
    udelay(50); // delay 9T to make sure that mfdec is ready.
    //Todo: check gpu_active = 1?
    if (GET_REG(MFDEC_BKA415, gpu_active) != 1)
    {
        mfdec_printk("[WARN!!!!!!!!!!!!][MFDec] GPU should be active!! But gpu_active is 0x%04x. \n", GET_REG(MFDEC_BKA415, gpu_active));
    }
#endif

    return 0;
}

void invalidate_mfdec_cache(struct kbase_device* kbdev)
{
    /* disp_mfdec gpu_main_ctrl: sw invalidate mode */
    SET_REG(MFDEC_BKA415, gpu_main_ctrl_mode, 3);
    /* invalidate cache to insure the correctness */
    SET_REG(MFDEC_BKA415, tagram_inv, 1);  // This is for mfdec decode frame cache
    SET_REG(MFDEC_BKA415, tagram_inv_gpu, 1);   // SW force mfdec cache tag ram invalidate for gpu path
}

void reset_mfdec_slot_reg(struct kbase_device* kbdev, u8 id)
{
    mfdec_printk("[MFDec] %s() id=%d\n", __func__ , id);

    if (id >= MAX_MFDEC_SLOT_NUM)
        return;

    /* Set invalid vector */
    CLEAR_REG_VAL(X32_GPU, mfdec_valid, (0x1 << id));
}

void release_mfdec_slot(struct kbase_device* kbdev, u8 id)
{
    release_slot(kbdev, &mfdec_bridge, id);
}

void print_debug_status(struct kbase_device* kbdev)
{
    printk("[MFDec] mfdec_off      = 0x%x\n", GET_REG(X32_GPU, mfdec_off));
    printk("[MFDec] mfdec_used_id  = 0x%x\n", mfdec_used_id);
    printk("[MFDec] valid bit      = 0x%04x\n", GET_REG(X32_GPU, mfdec_valid));
    printk("[MFDec] GPU idle       = 0x%x\n", GET_REG(X32_GPU, gpu_bridge_idle));

    /* enable mfdec debug bus register */
    SET_REG(MFDEC_BKA415, mfdec_dbus_sel, 6);

    printk("[MFDec] dump mfdec register ...\n");
    printk("[MFDec] mfdec_dbus_l: 0x%04x\n", GET_REG(MFDEC_BKA415, mfdec_dbus_l));
    printk("[MFDec] mfdec_dbus_h: 0x%04x\n", GET_REG(MFDEC_BKA415, mfdec_dbus_h));

    /* Check the MFDEC bank status */
    printk("[MFDEC] INDEX  = 0x%x\n", GET_REG(MFDEC_BKA415, prg_fb_idx));

    SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_L_BASE);
    printk("[MFDEC] Y_BASE (64 byte unit)   = 0x%04x %04x\n", GET_REG(MFDEC_BKA415, fb_para_data_1), GET_REG(MFDEC_BKA415, fb_para_data_0));

    SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_C_BASE);
    printk("[MFDEC] C_BASE (64 byte unit)   = 0x%04x %04x\n", GET_REG(MFDEC_BKA415, fb_para_data_1), GET_REG(MFDEC_BKA415, fb_para_data_0));

    SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_PITCH);
    printk("[MFDEC] PITCH  (16 pixel align) = 0x%x %x\n", GET_REG(MFDEC_BKA415, fb_para_data_1), GET_REG(MFDEC_BKA415, fb_para_data_0));

    SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_PROP);
    printk("[MFDEC] PROP    = 0x%x %x\n", GET_REG(MFDEC_BKA415, fb_para_data_1), GET_REG(MFDEC_BKA415, fb_para_data_0));


    printk("[MFDec] dump bridge register ...\n");
    SET_REG(X32_GPU, mfdec_bri_status_sel_1, 0);
    printk("[MFDec] mfdec_bri_status_sel_1: 0x%04x\n", GET_REG(X32_GPU, mfdec_bri_status_sel_1));
    printk("[MFDec] mfdec_status_1: 0x%04x\n", GET_REG(X32_GPU, mfdec_status_1));
    printk("[MFDec] mfdec_status_1_31_16: 0x%04x\n", GET_REG(X32_GPU, mfdec_status_1_31_16));
    SET_REG(X32_GPU, mfdec_bri_status_sel_1, 1);
    printk("[MFDec] mfdec_bri_status_sel_1: 0x%04x\n", GET_REG(X32_GPU, mfdec_bri_status_sel_1));
    printk("[MFDec] mfdec_status_1: 0x%04x\n", GET_REG(X32_GPU, mfdec_status_1));
    printk("[MFDec] mfdec_status_1_31_16: 0x%04x\n", GET_REG(X32_GPU, mfdec_status_1_31_16));
    SET_REG(X32_GPU, mfdec_bri_status_sel_1, 2);
    printk("[MFDec] mfdec_bri_status_sel_1: 0x%04x\n", GET_REG(X32_GPU, mfdec_bri_status_sel_1));
    printk("[MFDec] mfdec_status_1: 0x%04x\n", GET_REG(X32_GPU, mfdec_status_1));
    printk("[MFDec] mfdec_status_1_31_16: 0x%04x\n", GET_REG(X32_GPU, mfdec_status_1_31_16));

    SET_REG(X32_GPU, mfdec_adr_idx, 0);
    printk("[MFDec] mfdec_adr_idx: 0x%04x\n", GET_REG(X32_GPU, mfdec_adr_idx));
    SET_REG(X32_GPU, mfdec_bri_status_sel_0, 0);
    printk("[MFDec] mfdec_bri_status_sel_0: 0x%04x\n", GET_REG(X32_GPU, mfdec_bri_status_sel_0));
    printk("[MFDec] mfdec_y_start[15: 0]: 0x%04x\n", GET_REG(X32_GPU, mfdec_status_0));
    printk("[MFDec] mfdec_y_start[20:16]: 0x%04x\n", GET_REG(X32_GPU, mfdec_status_0_31_16));
    SET_REG(X32_GPU, mfdec_bri_status_sel_0, 1);
    printk("[MFDec] mfdec_bri_status_sel_0: 0x%04x\n", GET_REG(X32_GPU, mfdec_bri_status_sel_0));
    printk("[MFDec] mfdec_y_end[15: 0]: 0x%04x\n", GET_REG(X32_GPU, mfdec_status_0));
    printk("[MFDec] mfdec_y_end[20:16]: 0x%04x\n", GET_REG(X32_GPU, mfdec_status_0_31_16));
    SET_REG(X32_GPU, mfdec_bri_status_sel_0, 2);
    printk("[MFDec] mfdec_bri_status_sel_0: 0x%04x\n", GET_REG(X32_GPU, mfdec_bri_status_sel_0));
    printk("[MFDec] mfdec_uv_start[15: 0]: 0x%04x\n", GET_REG(X32_GPU, mfdec_status_0));
    printk("[MFDec] mfdec_uv_start[20:16]: 0x%04x\n", GET_REG(X32_GPU, mfdec_status_0_31_16));
    SET_REG(X32_GPU, mfdec_bri_status_sel_0, 3);
    printk("[MFDec] mfdec_bri_status_sel_0: 0x%04x\n", GET_REG(X32_GPU, mfdec_bri_status_sel_0));
    printk("[MFDec] mfdec_uv_end[15: 0]: 0x%04x\n", GET_REG(X32_GPU, mfdec_status_0));
    printk("[MFDec] mfdec_uv_end[20:16]: 0x%04x\n", GET_REG(X32_GPU, mfdec_status_0_31_16));
    SET_REG(X32_GPU, mfdec_bri_status_sel_0, 4);
    printk("[MFDec] mfdec_bri_status_sel_0: 0x%04x\n", GET_REG(X32_GPU, mfdec_bri_status_sel_0));
    printk("[MFDec] mfdec_pitch[15: 0]: 0x%04x\n", GET_REG(X32_GPU, mfdec_status_0));

    printk("[MFDec] bridge_idle status[5:1]: 0x%04x\n", GET_REG(X32_GPU, bridge_idle));
    SET_REG(X32_GPU, g3d_bri_status_sel, 0);
    printk("[MFDec] g3d_bri_status_sel: (brg_trans) 0x%04x\n", GET_REG(X32_GPU, g3d_bri_status_sel));
    printk("[MFDec] g3d_bri_status_0: 0x%04x\n", GET_REG(X32_GPU, g3d_bri_status_0));
    printk("[MFDec] g3d_bri_status_0_31_16: 0x%04x\n", GET_REG(X32_GPU, g3d_bri_status_0_31_16));
    SET_REG(X32_GPU, g3d_bri_status_sel, 1);
    printk("[MFDec] g3d_bri_status_sel: (rsi_w_debug0) 0x%04x\n", GET_REG(X32_GPU, g3d_bri_status_sel));
    printk("[MFDec] g3d_bri_status_0: 0x%04x\n", GET_REG(X32_GPU, g3d_bri_status_0));
    printk("[MFDec] g3d_bri_status_0_31_16: 0x%04x\n", GET_REG(X32_GPU, g3d_bri_status_0_31_16));
    SET_REG(X32_GPU, g3d_bri_status_sel, 2);
    printk("[MFDec] g3d_bri_status_sel: (rsi_w_debug1) 0x%04x\n", GET_REG(X32_GPU, g3d_bri_status_sel));
    printk("[MFDec] g3d_bri_status_0: 0x%04x\n", GET_REG(X32_GPU, g3d_bri_status_0));
    printk("[MFDec] g3d_bri_status_0_31_16: 0x%04x\n", GET_REG(X32_GPU, g3d_bri_status_0_31_16));
    SET_REG(X32_GPU, g3d_bri_status_sel, 3);
    printk("[MFDec] g3d_bri_status_sel: (rsi_w_debug2) 0x%04x\n", GET_REG(X32_GPU, g3d_bri_status_sel));
    printk("[MFDec] g3d_bri_status_0: 0x%04x\n", GET_REG(X32_GPU, g3d_bri_status_0));
    printk("[MFDec] g3d_bri_status_0_31_16: 0x%04x\n", GET_REG(X32_GPU, g3d_bri_status_0_31_16));
    SET_REG(X32_GPU, g3d_bri_status_sel, 4);
    printk("[MFDec] g3d_bri_status_sel: (rsi_w_debug3) 0x%04x\n", GET_REG(X32_GPU, g3d_bri_status_sel));
    printk("[MFDec] g3d_bri_status_0: 0x%04x\n", GET_REG(X32_GPU, g3d_bri_status_0));
    printk("[MFDec] g3d_bri_status_0_31_16: 0x%04x\n", GET_REG(X32_GPU, g3d_bri_status_0_31_16));
    SET_REG(X32_GPU, g3d_bri_status_sel, 5);
    printk("[MFDec] g3d_bri_status_sel: (rsi_r_debug0) 0x%04x\n", GET_REG(X32_GPU, g3d_bri_status_sel));
    printk("[MFDec] g3d_bri_status_0: 0x%04x\n", GET_REG(X32_GPU, g3d_bri_status_0));
    printk("[MFDec] g3d_bri_status_0_31_16: 0x%04x\n", GET_REG(X32_GPU, g3d_bri_status_0_31_16));
    SET_REG(X32_GPU, g3d_bri_status_sel, 6);
    printk("[MFDec] g3d_bri_status_sel: (rsi_r_debug1) 0x%04x\n", GET_REG(X32_GPU, g3d_bri_status_sel));
    printk("[MFDec] g3d_bri_status_0: 0x%04x\n", GET_REG(X32_GPU, g3d_bri_status_0));
    printk("[MFDec] g3d_bri_status_0_31_16: 0x%04x\n", GET_REG(X32_GPU, g3d_bri_status_0_31_16));

}

void dump_slot_status(struct kbase_device* kbdev)
{
    u32 i, pitch, fb_prop, mfdec_pitch;
    u64 status_base_start, status_base_end;
    u64 video_ybase, video_uvbase, BLDbase, BLDuvbase;
    char *row1[] = {"id", "v", "fake_y_start", "fake_uv_end", "pch", "vdec_y", "vdec_c", "BLD_y", "BLD_c", "pch2", "fb_prop"};

    printk("[MFDec] | %2s | %1s | %11s| %11s | %5s | %10s | %10s | %10s | %10s | %4s | %10s |\n", row1[0], row1[1], row1[2], row1[3], row1[4], row1[5], row1[6], row1[7], row1[8], row1[9], row1[10]);

    for (i=0;i<MAX_MFDEC_SLOT_NUM;i++)
    {
        SET_REG(X32_GPU, mfdec_adr_idx, i);

        // read gpu_bridge status register: mfdec_y_start
        SET_REG(X32_GPU, mfdec_bri_status_sel_0, 0);
        status_base_start = (GET_REG(X32_GPU, mfdec_status_0_31_16));
        status_base_start = (status_base_start << 28) | (GET_REG(X32_GPU, mfdec_status_0) << 12);

        // read gpu_bridge status register: mfdec_uv_end
        SET_REG(X32_GPU, mfdec_bri_status_sel_0, 3);
        status_base_end = (GET_REG(X32_GPU, mfdec_status_0_31_16));
        status_base_end = (status_base_end << 28) | (GET_REG(X32_GPU, mfdec_status_0) << 12);

        // read gpu_bridge status register: pitch
        SET_REG(X32_GPU, mfdec_bri_status_sel_0, 4);
        pitch = GET_REG(X32_GPU, mfdec_status_0);

        // read mfdec registers
        SET_REG(MFDEC_BKA415, prg_fb_idx, i);

        SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_L_BLD_BASE);
        BLDbase = GET_REG(MFDEC_BKA415, fb_para_data_1);
        BLDbase = (BLDbase << 22) | (GET_REG(MFDEC_BKA415, fb_para_data_0) << 6);  // 64 byte unit
        SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_C_BLD_BASE);
        BLDuvbase = GET_REG(MFDEC_BKA415, fb_para_data_1);
        BLDuvbase = (BLDuvbase << 22) | (GET_REG(MFDEC_BKA415, fb_para_data_0) << 6);  // 64 byte unit
        SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_L_BASE);
        video_ybase = GET_REG(MFDEC_BKA415, fb_para_data_1);
        video_ybase = (video_ybase << 22) | (GET_REG(MFDEC_BKA415, fb_para_data_0) << 6);  // 64 byte unit
        SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_C_BASE);
        video_uvbase = GET_REG(MFDEC_BKA415, fb_para_data_1);
        video_uvbase = (video_uvbase << 22) | (GET_REG(MFDEC_BKA415, fb_para_data_0) << 6);  // 64 byte unit
        SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_PITCH);
        mfdec_pitch = GET_REG(MFDEC_BKA415, fb_para_data_1) << 16 | GET_REG(MFDEC_BKA415, fb_para_data_0);
        SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_PROP);
        fb_prop = GET_REG(MFDEC_BKA415, fb_para_data_1) << 16 | GET_REG(MFDEC_BKA415, fb_para_data_0);

        printk("[MFDec] | %2d | %1d | 0x%09llx | 0x%09llx | %5d | 0x%08llx | 0x%08llx | 0x%08llx | 0x%08llx | %4d | 0x%08x |\n", i,
                (GET_REG(X32_GPU, mfdec_valid) >> i) & 0x1, status_base_start, status_base_end, pitch, video_ybase, video_uvbase, BLDbase, BLDuvbase, mfdec_pitch, fb_prop);
    }

}

#endif /* _KBASE_PLATFORM_MSTAR_MT5876_MFDEC_H_ */
