// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
/*
 * Copyright (c) 2022 MediaTek Inc.
 */

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

#ifndef _KBASE_PLATFORM_MTK_DTV_MT5873_MFDEC_H_
#define _KBASE_PLATFORM_MTK_DTV_MT5873_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                        0x3FFFFFFFF

bridge_device mfdec_bridge;
const u8 max_mfdec_slot_num = MAX_MFDEC_SLOT_NUM;

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

#define HW_AUTO_INVALIDATE_MODE 1

void init_mfdec_reg(void)
{
	u16 uckg_s_disp_mfdec = 0;

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

	/***** 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
	// bank:0x2ee9, reg:0x43, bit[0] /* Natt: support non-block linear mode only*/
	SET_REG(X32_GPU, mfdec_linear_mode, 0);
	/* gpu initial reg_mfdec_off */
	SET_REG(X32_GPU, mfdec_off, 0); // reg: 0x66, bit [1]
	udelay(1);

	/* Enable mfdec clock */
	//clk_fnclk
	//TOP_CKGEN
	SET_REG(CKGEN1035, ckg_g_xc_fn, 0);            // bank: 0x1035, reg: 0x34, bit[0]
	SET_REG(CKGEN1037, gate_xc_fn, 0);            // bank: 0x1037, reg: 0x21, bit[0]
	//SCFE_CKGEN
	SET_REG(CKGEN1035, ckg_g_xc_fn_scip, 0);            // bank: 0x1035, reg: 0x4C, bit[0]
	SET_REG(CKGEN103C, sw_en_xc_fn2scip, 1);            // bank: 0x103C, reg: 0x65, bit[1]

	/* clk_gpu_mfdec */
	SET_REG(CKGEN1029, ckg_g_disp_mfdec, 0); // bank: 0x1029, reg: 0x1A, bit[0]
	// bank: 0x1029, reg: 0x1A, bit[3:2]
	uckg_s_disp_mfdec = GET_REG(CKGEN1029, ckg_s_disp_mfdec);
	if (uckg_s_disp_mfdec == 1) // 1: 0
		SET_REG(CKGEN1029, ckg_s_disp_mfdec, 0); // bank: 0x1029, reg: 0x1A, bit[3:2]
	//SCFE_CKGEN
	SET_REG(CKGEN1036, ckg_g_xc_gpu_mfdec_scip, 0); // bank: 0x1036, reg: 0x30, bit[0]
	SET_REG(CKGEN103C, sw_en_xc_gpu_mfdec2scip, 1); // bank: 0x103C, reg: 0x61, bit[0]

	SET_REG(MFDEC_BKA415, gpu_dec_sw_rst, 1);  // reg: 0x1, bit [10]
	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
	// SW force mfdec cache tag ram invalidate for gpu path
	SET_REG(MFDEC_BKA415, tagram_inv_gpu, 1);
#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)
		dev_dbg(kbdev->dev, "[MFDec] soft_reset=1, pull down GPU reset.");
#endif
	}

	SET_REG(X32_GPU, mfdec_adr_idx, (id & 0xF));
	mfdec_printk("[MFDec] mfdec_adr_idx: 0x%04x\n", GET_REG(X32_GPU, mfdec_adr_idx));

	/* [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);
	mfdec_printk("[MFDec] video_pitch: 0x%04x\n", GET_REG(X32_GPU, video_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);
	mfdec_printk("[MFDec] mfdec_y_start_low: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_y_start_15_00));
	mfdec_printk("[MFDec] mfdec_y_start_high: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_y_start_21_16));
	mfdec_printk("[MFDec] mfdec_y_end_low: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_y_end_15_00));
	mfdec_printk("[MFDec] mfdec_y_end_high: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_y_end_21_16));
	mfdec_printk("[MFDec] mfdec_uv_start_low: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_uv_start_15_00));
	mfdec_printk("[MFDec] mfdec_uv_start_high: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_uv_start_21_16));
	mfdec_printk(kbdev, "[MFDec] mfdec_uv_end_low: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_uv_end_15_00));
	mfdec_printk("[MFDec] mfdec_uv_end_high: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_uv_end_21_16));

	/* Update & clean */
	SET_REG(X32_GPU, mfdec_adr_update,    0x1);
	mfdec_printk("[MFDec] mfdec_adr_update: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_adr_update));
	SET_REG(X32_GPU, mfdec_adr_update,    0x0);
	mfdec_printk("[MFDec] mfdec_adr_update: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_adr_update));

	/* 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));
	mfdec_printk("[MFDec] mfdec_valid: 0x%04x\n", GET_REG(X32_GPU, mfdec_valid));

#if defined(CONFIG_MALI_DEBUG) && !defined(MTK_DTV_ZEBU)
	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);
	mfdec_printk("[MFDec] prg_fb_idx: 0x%04x\n", GET_REG(MFDEC_BKA415, prg_fb_idx));

	/* Set frame buffer luma base */
	SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_L_BASE);
	//[21:6]: 64 byte unit
	SET_REG(MFDEC_BKA415, fb_para_data_0, (video_ybase & BASE_ADDRESS_MASK) >> 6);
	//[37:22]: 64 byte unit
	SET_REG(MFDEC_BKA415, fb_para_data_1, (video_ybase & BASE_ADDRESS_MASK) >> 22);
	luma_offset_to_16g = (video_ybase & BASE_OFFSET_16G_MASK) >> 30;
	//[ 7: 4] : luma base address offset to support miu upto 16G (for UMA)
	fb_property_lo |=  (luma_offset_to_16g << 4);
	udelay(1);
	mfdec_printk("[MFDec] prg_fb_type: 0x%04x\n", GET_REG(MFDEC_BKA415, prg_fb_type));
	mfdec_printk("[MFDec] fb_para_data_low: 0x%04x, real: 0x%04x\n",
		GET_REG(MFDEC_BKA415, fb_para_data_0), (u16)((video_ybase >> 6) & 0xFFFF));
	mfdec_printk("[MFDec] fb_para_data_high: 0x%04x, real: 0x%04x\n",
		GET_REG(MFDEC_BKA415, fb_para_data_1), (u16)((video_ybase >> 22) & 0xFFFF));

	/* Set frame buffer chroma base */
	SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_C_BASE);
	//[21:6]: 64 byte unit
	SET_REG(MFDEC_BKA415, fb_para_data_0, (video_uvbase  & BASE_ADDRESS_MASK) >> 6);
	//[37:22]: 64 byte unit
	SET_REG(MFDEC_BKA415, fb_para_data_1, (video_uvbase  & BASE_ADDRESS_MASK) >> 22);
	chroma_offset_to_16g = (video_uvbase & BASE_OFFSET_16G_MASK) >> 30;
	//[11:8] : chroma base address offset to support miu upto 16G (for UMA)
	fb_property_lo |=  (chroma_offset_to_16g << 8);
	udelay(1);
	mfdec_printk("[MFDec] prg_fb_type: 0x%04x\n",
		GET_REG(MFDEC_BKA415, prg_fb_type));
	mfdec_printk("[MFDec] fb_para_data_low: 0x%04x, real: 0x%04x\n",
		GET_REG(MFDEC_BKA415, fb_para_data_0), (u16)((video_uvbase >> 6) & 0xFFFF));
	mfdec_printk("[MFDec] fb_para_data_high: 0x%04x, real: 0x%04x\n",
		GET_REG(MFDEC_BKA415, fb_para_data_1), (u16)((video_uvbase >> 22) & 0xFFFF));

	/* Set frame buffer pitch */
	SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_PITCH);
	//pixel unit (32 pixel alignment)
	SET_REG(MFDEC_BKA415, fb_para_data_0, ((pitch + 0x1f)  >> 5) << 5);
	SET_REG(MFDEC_BKA415, fb_para_data_1, 0x0);
	udelay(1);
	mfdec_printk("[MFDec] prg_fb_type: 0x%04x\n",
		GET_REG(MFDEC_BKA415, prg_fb_type));
	mfdec_printk("[MFDec] fb_para_data_low: 0x%04x, real: 0x%04x\n",
		GET_REG(MFDEC_BKA415, fb_para_data_0),
		(u16)((((pitch + 0xf) >> 4) << 4) & 0xFFFF));
	mfdec_printk("[MFDec] fb_para_data_high: 0x%04x, real: 0x%04x\n",
		GET_REG(MFDEC_BKA415, fb_para_data_1), 0);
	/* Set frame buffer property */
	SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_PROP);

#if defined(CONFIG_MALI_DEBUG)
	//[24] : frame buffer address re-map enable for DDR4
	if (flags & FB_PROP_FLAG_FB_BASE_REMAP_EN_DDR4)
		fb_property_hi |= (FB_PROP_FLAG_FB_BASE_REMAP_EN_DDR4 >> 16);
	//[25] : frame buffer address re-map enable for channel balance
	if (flags & FB_PROP_FLAG_FB_BASE_REMAP_EN_BALANCE)
		fb_property_hi |= (FB_PROP_FLAG_FB_BASE_REMAP_EN_BALANCE >> 16);
	//[30] : output even lines (top field) data
	if (flags & FB_PROP_FLAG_OUTPUT_EVEN_LINES_DATA)
		fb_property_hi |= (FB_PROP_FLAG_OUTPUT_EVEN_LINES_DATA >> 16);
	//[28] : Luma is 10bpp mode
	if (flags & FB_PROP_FLAG_LUMA10BPP)
		fb_property_hi |= (FB_PROP_FLAG_LUMA10BPP >> 16);
	//[29] : Chroma is 10bpp mode
	if (flags & FB_PROP_FLAG_CHROMA10BPP)
		fb_property_hi |= (FB_PROP_FLAG_CHROMA10BPP >> 16);
	//[31] : VSD 1:8x4, 0:8x2
	if (flags & FB_PROP_FLAG_VSD8x4)
		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");
		// [1:0] tile mode, [2] compress
		SET_REG(MFDEC_BKA415, fb_para_data_0, fb_property_lo | ENCODE_TYPE_16x32);
		// [29:28] bpp, [31] 8x4
		SET_REG(MFDEC_BKA415, fb_para_data_1, fb_property_hi);
		break;
	case ENCODE_TYPE_VSD:
		mfdec_printk("[MFDec] => ENCODE_TYPE_VSD\n");
		// [1:0] tile mode, [2] compress
		SET_REG(MFDEC_BKA415, fb_para_data_0, fb_property_lo | ENCODE_TYPE_VSD);
		// [29:28] bpp, [31] 8x4
		SET_REG(MFDEC_BKA415, fb_para_data_1, fb_property_hi);
		break;
	default:
		mfdec_printk("[MFDec] => Unsupported Encode Type!\n");
		break;
	}
	udelay(1);
	mfdec_printk("[MFDec] prg_fb_type: 0x%04x\n",
		GET_REG(MFDEC_BKA415, prg_fb_type));
	mfdec_printk("[MFDec] fb_para_data_low: 0x%04x\n",
		GET_REG(MFDEC_BKA415, fb_para_data_0));
	mfdec_printk("[MFDec] fb_para_data_high: 0x%04x\n",
		GET_REG(MFDEC_BKA415, fb_para_data_1));

	/* check gpu_active is meaningless in current mfdec driver architecture */
	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);

	/* Set frame buffer index */
	SET_REG(MFDEC_BKA415, prg_fb_idx, id);
	mfdec_printk("[MFDec] prg_fb_idx: 0x%04x\n",
		GET_REG(MFDEC_BKA415, prg_fb_idx));

	/* Set frame buffer bitlength base */
	SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_L_BLD_BASE);
	//[21:6]: 64 byte unit
	SET_REG(MFDEC_BKA415, fb_para_data_0, (BLDbase & BASE_ADDRESS_MASK)  >> 6);
	//[37:22]: 64 byte unit
	SET_REG(MFDEC_BKA415, fb_para_data_1, (BLDbase & BASE_ADDRESS_MASK) >> 22);
	bitlen_offset_to_16g = (BLDbase & BASE_OFFSET_16G_MASK) >> 30;
	 //[15:12] : bitlen base address offset to support miu upto 16G (for UMA)
	fb_property_lo |=  (bitlen_offset_to_16g << 12);
	udelay(1);
	mfdec_printk("[MFDec] prg_fb_type: 0x%04x\n",
		GET_REG(MFDEC_BKA415, prg_fb_type));
	mfdec_printk("[MFDec] fb_para_data_low: 0x%04x, real: 0x%04x\n",
		GET_REG(MFDEC_BKA415, fb_para_data_0), (u16)((BLDbase >> 6) & 0xFFFF));
	mfdec_printk("[MFDec] fb_para_data_high: 0x%04x, real: 0x%04x\n",
		GET_REG(MFDEC_BKA415, fb_para_data_1), (u16)((BLDbase >> 22) & 0xFFFF));

	SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_L_BASE);
	//[21:6]: 64 byte unit
	SET_REG(MFDEC_BKA415, fb_para_data_0, (video_ybase & BASE_ADDRESS_MASK) >> 6);
	//[37:22]: 64 byte unit
	SET_REG(MFDEC_BKA415, fb_para_data_1, (video_ybase & BASE_ADDRESS_MASK) >> 22);
	luma_offset_to_16g = (video_ybase & BASE_OFFSET_16G_MASK) >> 30;
	//[ 7: 4] : luma base address offset to support miu upto 16G (for UMA)
	fb_property_lo |=  (luma_offset_to_16g << 4);
	udelay(1);
	mfdec_printk("[MFDec] prg_fb_type: 0x%04x\n",
		GET_REG(MFDEC_BKA415, prg_fb_type));
	mfdec_printk("[MFDec] fb_para_data_low: 0x%04x, real: 0x%04x\n",
		GET_REG(MFDEC_BKA415, fb_para_data_0), (u16)((video_ybase >> 6) & 0xFFFF));
	mfdec_printk("[MFDec] fb_para_data_high: 0x%04x, real: 0x%04x\n",
		GET_REG(MFDEC_BKA415, fb_para_data_1), (u16)((video_ybase >> 22) & 0xFFFF));

	SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_C_BASE);
	//[21:6]: 64 byte unit
	SET_REG(MFDEC_BKA415, fb_para_data_0, (video_uvbase & BASE_ADDRESS_MASK) >> 6);
	//[37:22]: 64 byte unit
	SET_REG(MFDEC_BKA415, fb_para_data_1, (video_uvbase & BASE_ADDRESS_MASK) >> 22);
	chroma_offset_to_16g = (video_uvbase & BASE_OFFSET_16G_MASK) >> 30;
	//[11:8] : chroma base address offset to support miu upto 16G (for UMA
	fb_property_lo |=  (chroma_offset_to_16g << 8);
	udelay(1);
	mfdec_printk("[MFDec] prg_fb_type: 0x%04x\n",
		GET_REG(MFDEC_BKA415, prg_fb_type));
	mfdec_printk("[MFDec] fb_para_data_low: 0x%04x, real: 0x%04x\n",
		GET_REG(MFDEC_BKA415, fb_para_data_0), (u16)((video_uvbase >> 6) & 0xFFFF));
	mfdec_printk("[MFDec] fb_para_data_high: 0x%04x, real: 0x%04x\n",
		GET_REG(MFDEC_BKA415, fb_para_data_1), (u16)((video_uvbase >> 22) & 0xFFFF));

	/* Set frame buffer pitch */
	SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_PITCH);
	//pixel unit (128 pixel alignment)
	SET_REG(MFDEC_BKA415, fb_para_data_0, ((pitch + 0x7f) >> 7) << 6);
	SET_REG(MFDEC_BKA415, fb_para_data_1, 0x0);
	udelay(1);
	mfdec_printk("[MFDec] prg_fb_type: 0x%04x\n",
		GET_REG(MFDEC_BKA415, prg_fb_type));
	mfdec_printk("[MFDec] fb_para_data_low: 0x%04x, real: 0x%04x\n",
		GET_REG(MFDEC_BKA415, fb_para_data_0), (u16)((((pitch + 0xf) >> 4) << 4) & 0xFFFF));
	mfdec_printk("[MFDec] fb_para_data_high: 0x%04x, real: 0x%04x\n",
		GET_REG(MFDEC_BKA415, fb_para_data_1), 0);

	/* Set frame buffer property */
	SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_PROP);
	// [1:0] tile mode, [2] compress
	SET_REG(MFDEC_BKA415, fb_para_data_0, fb_property_lo | ENCODE_TYPE_COMPRESS);

#if defined(CONFIG_MALI_DEBUG)
	//[24] : frame buffer address re-map enable for DDR4
	if (flags & FB_PROP_FLAG_FB_BASE_REMAP_EN_DDR4)
		fb_property_hi |= (FB_PROP_FLAG_FB_BASE_REMAP_EN_DDR4 >> 16);
	//[25] : frame buffer address re-map enable for channel balance
	if (flags & FB_PROP_FLAG_FB_BASE_REMAP_EN_BALANCE)
		fb_property_hi |= (FB_PROP_FLAG_FB_BASE_REMAP_EN_BALANCE >> 16);
	//[30] : output even lines (top field) data
	if (flags & FB_PROP_FLAG_OUTPUT_EVEN_LINES_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);
	mfdec_printk("[MFDec] prg_fb_type: 0x%04x\n",
		GET_REG(MFDEC_BKA415, prg_fb_type));
	mfdec_printk("[MFDec] fb_para_data_low: 0x%04x\n",
		GET_REG(MFDEC_BKA415, fb_para_data_0));
	mfdec_printk("[MFDec] fb_para_data_high: 0x%04x\n",
		GET_REG(MFDEC_BKA415, fb_para_data_1));

	/* check gpu_active is meaningless in current mfdec driver architecture */
	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
	// SW force mfdec cache tag ram invalidate for gpu path
	SET_REG(MFDEC_BKA415, tagram_inv_gpu, 1);
}

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)
{
	dev_dbg(kbdev->dev, "[MFDec] mfdec_off      = 0x%x\n", GET_REG(X32_GPU, mfdec_off));
	dev_dbg(kbdev->dev, "[MFDec] mfdec_used_id  = 0x%x\n", mfdec_used_id);
	dev_dbg(kbdev->dev, "[MFDec] valid bit      = 0x%04x\n", GET_REG(X32_GPU, mfdec_valid));
	dev_dbg(kbdev->dev, "[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);

	dev_dbg(kbdev->dev, "[MFDec] dump mfdec register ...\n");
	dev_dbg(kbdev->dev, "[MFDec] mfdec_dbus_l: 0x%04x\n",
		GET_REG(MFDEC_BKA415, mfdec_dbus_l));
	dev_dbg(kbdev->dev, "[MFDec] mfdec_dbus_h: 0x%04x\n",
		GET_REG(MFDEC_BKA415, mfdec_dbus_h));

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

	SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_L_BASE);
	dev_dbg(kbdev->dev, "[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);
	dev_dbg(kbdev->dev, "[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);
	dev_dbg(kbdev->dev, "[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);
	dev_dbg(kbdev->dev, "[MFDEC] PROP    = 0x%x %x\n",
		GET_REG(MFDEC_BKA415, fb_para_data_1), GET_REG(MFDEC_BKA415, fb_para_data_0));


	dev_dbg(kbdev->dev, "[MFDec] dump bridge register ...\n");
	SET_REG(X32_GPU, mfdec_bri_status_sel_1, 0);
	dev_dbg(kbdev->dev, "[MFDec] mfdec_bri_status_sel_1: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_bri_status_sel_1));
	dev_dbg(kbdev->dev, "[MFDec] mfdec_status_1: 0x%04x\n", GET_REG(X32_GPU, mfdec_status_1));
	dev_dbg(kbdev->dev, "[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);
	dev_dbg(kbdev->dev, "[MFDec] mfdec_bri_status_sel_1: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_bri_status_sel_1));
	dev_dbg(kbdev->dev, "[MFDec] mfdec_status_1: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_status_1));
	dev_dbg(kbdev->dev, "[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);
	dev_dbg(kbdev->dev, "[MFDec] mfdec_bri_status_sel_1: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_bri_status_sel_1));
	dev_dbg(kbdev->dev, "[MFDec] mfdec_status_1: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_status_1));
	dev_dbg(kbdev->dev, "[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);
	dev_dbg(kbdev->dev, "[MFDec] mfdec_adr_idx: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_adr_idx));
	SET_REG(X32_GPU, mfdec_bri_status_sel_0, 0);
	dev_dbg(kbdev->dev, "[MFDec] mfdec_bri_status_sel_0: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_bri_status_sel_0));
	dev_dbg(kbdev->dev, "[MFDec] mfdec_y_start[15: 0]: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_status_0));
	dev_dbg(kbdev->dev, "[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);
	dev_dbg(kbdev->dev, "[MFDec] mfdec_bri_status_sel_0: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_bri_status_sel_0));
	dev_dbg(kbdev->dev, "[MFDec] mfdec_y_end[15: 0]: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_status_0));
	dev_dbg(kbdev->dev, "[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);
	dev_dbg(kbdev->dev, "[MFDec] mfdec_bri_status_sel_0: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_bri_status_sel_0));
	dev_dbg(kbdev->dev, "[MFDec] mfdec_uv_start[15: 0]: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_status_0));
	dev_dbg(kbdev->dev, "[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);
	dev_dbg(kbdev->dev, "[MFDec] mfdec_bri_status_sel_0: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_bri_status_sel_0));
	dev_dbg(kbdev->dev, "[MFDec] mfdec_uv_end[15: 0]: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_status_0));
	dev_dbg(kbdev->dev, "[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);
	dev_dbg(kbdev->dev, "[MFDec] mfdec_bri_status_sel_0: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_bri_status_sel_0));
	dev_dbg(kbdev->dev, "[MFDec] mfdec_pitch[15: 0]: 0x%04x\n",
		GET_REG(X32_GPU, mfdec_status_0));

	dev_dbg(kbdev->dev, "[MFDec] bridge_idle status[5:1]: 0x%04x\n",
		GET_REG(X32_GPU, bridge_idle));
	SET_REG(X32_GPU, g3d_bri_status_sel, 0);
	dev_dbg(kbdev->dev, "[MFDec] g3d_bri_status_sel: (brg_trans) 0x%04x\n",
		GET_REG(X32_GPU, g3d_bri_status_sel));
	dev_dbg(kbdev->dev, "[MFDec] g3d_bri_status_0: 0x%04x\n",
		GET_REG(X32_GPU, g3d_bri_status_0));
	dev_dbg(kbdev->dev, "[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);
	dev_dbg(kbdev->dev, "[MFDec] g3d_bri_status_sel: (rsi_w_debug0) 0x%04x\n",
		GET_REG(X32_GPU, g3d_bri_status_sel));
	dev_dbg(kbdev->dev, "[MFDec] g3d_bri_status_0: 0x%04x\n",
		GET_REG(X32_GPU, g3d_bri_status_0));
	dev_dbg(kbdev->dev, "[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);
	dev_dbg(kbdev->dev, "[MFDec] g3d_bri_status_sel: (rsi_w_debug1) 0x%04x\n",
		GET_REG(X32_GPU, g3d_bri_status_sel));
	dev_dbg(kbdev->dev, "[MFDec] g3d_bri_status_0: 0x%04x\n",
		GET_REG(X32_GPU, g3d_bri_status_0));
	dev_dbg(kbdev->dev, "[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);
	dev_dbg(kbdev->dev, "[MFDec] g3d_bri_status_sel: (rsi_w_debug2) 0x%04x\n",
		GET_REG(X32_GPU, g3d_bri_status_sel));
	dev_dbg(kbdev->dev, "[MFDec] g3d_bri_status_0: 0x%04x\n",
		GET_REG(X32_GPU, g3d_bri_status_0));
	dev_dbg(kbdev->dev, "[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);
	dev_dbg(kbdev->dev, "[MFDec] g3d_bri_status_sel: (rsi_w_debug3) 0x%04x\n",
		GET_REG(X32_GPU, g3d_bri_status_sel));
	dev_dbg(kbdev->dev, "[MFDec] g3d_bri_status_0: 0x%04x\n",
		GET_REG(X32_GPU, g3d_bri_status_0));
	dev_dbg(kbdev->dev, "[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);
	dev_dbg(kbdev->dev, "[MFDec] g3d_bri_status_sel: (rsi_r_debug0) 0x%04x\n",
		GET_REG(X32_GPU, g3d_bri_status_sel));
	dev_dbg(kbdev->dev, "[MFDec] g3d_bri_status_0: 0x%04x\n",
		GET_REG(X32_GPU, g3d_bri_status_0));
	dev_dbg(kbdev->dev, "[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);
	dev_dbg(kbdev->dev, "[MFDec] g3d_bri_status_sel: (rsi_r_debug1) 0x%04x\n",
		GET_REG(X32_GPU, g3d_bri_status_sel));
	dev_dbg(kbdev->dev, "[MFDec] g3d_bri_status_0: 0x%04x\n",
		GET_REG(X32_GPU, g3d_bri_status_0));
	dev_dbg(kbdev->dev, "[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;

	dev_dbg(kbdev->dev,
	"[MFDec] | id | v | fake_y_start | fake_uv_end | pch | vdec_y | vdec_c | BLD_y | BLD_c | pch2 | fb_prop |\n");

	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);
		// 64 byte unit
		BLDbase = (BLDbase << 22) | (GET_REG(MFDEC_BKA415, fb_para_data_0) << 6);
		SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_C_BLD_BASE);
		BLDuvbase = GET_REG(MFDEC_BKA415, fb_para_data_1);
		// 64 byte unit
		BLDuvbase = (BLDuvbase << 22) | (GET_REG(MFDEC_BKA415, fb_para_data_0) << 6);
		SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_L_BASE);
		video_ybase = GET_REG(MFDEC_BKA415, fb_para_data_1);
		// 64 byte unit
		video_ybase = (video_ybase << 22) | (GET_REG(MFDEC_BKA415, fb_para_data_0) << 6);
		SET_REG(MFDEC_BKA415, prg_fb_type, FB_TYPE_C_BASE);
		video_uvbase = GET_REG(MFDEC_BKA415, fb_para_data_1);
		// 64 byte unit
		video_uvbase = (video_uvbase << 22) | (GET_REG(MFDEC_BKA415, fb_para_data_0) << 6);
		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);

		dev_dbg(kbdev->dev,
		"[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_MTK_DTV_MT5873_MFDEC_H_ */
