// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
/*
 * Copyright (c) 2020 MediaTek Inc.
 */

#include <linux/delay.h>

#include "mtk_dmx_common.h"
#include "mtk_dmx_io.h"
#include "mtk_dmx_riu.h"
#include "mtk_dmx_rm.h"
#include "mtk_dmx_regs.h"
#include "mtk_dmx_pm.h"
#include "mtk_dmx_dev.h"
#include "mtk_dmx_ctrl.h"

#define FW_DMA_ADDR_ALIGN_SHIFT				(4)
#define MAGIC_NUMBER_STAND_FOR_TEE_ENABLE	(0xBAD7)
#define REG_OFFSET 4
#define FIFO_RESET_MAX_RETRY 20
#define FIFO_RESET_TIMEOUT_MIN 1000
#define FIFO_RESET_TIMEOUT_MAX 1050

static inline bool mtk_dmx_is_TEE_inited(void);

void mtk_dmx_ctrl_init(bool *bDmxTeeInited)
{
	*bDmxTeeInited = mtk_dmx_is_TEE_inited();
}

void mtk_dmx_ctrl_exit(void)
{

}

static inline bool mtk_dmx_is_TEE_inited(void)
{
	return ((u4IO32ReadFld(REG_TSP3_BASE + REG_0080_TSP3, TSP3_REG_HW_SEMAPHORE0_0080) ==
		   MAGIC_NUMBER_STAND_FOR_TEE_ENABLE) ? true : false);
}

void mtk_dmx_mcm_ctrl(bool bEnable)
{
	if (!mtk_dmx_is_TEE_inited()) {
		if (bEnable)
			vIO32WriteFld(REG_TSP5_BASE + REG_01FC_TSP5, 1,
						  TSP5_REG_MIU_MCM_CONFIG_01FC_0);
		else
			vIO32WriteFld(REG_TSP5_BASE + REG_01FC_TSP5, 0,
						  TSP5_REG_MIU_MCM_CONFIG_01FC_0);
	}
}

static void _init_LiveIn(struct mtk_dmx2dev *dmxdev)
{
	u16 tlv_num, i;

	// enable the patch of internal sync in "tsif"
	vIO32WriteFld(REG_TSP0_BASE + REG_0114_TSP0, 1, TSP0_REG_DATA_CHK_2T_0114);
	vIO32WriteFld(REG_TLV0_BASE + REG_0000_TSP_TLV, 1,
		TSP_TLV_REG_DATA_CHK_2T_0000);
	vIO32WriteFld(REG_TLV0_BASE + REG_0040_TSP_TLV, 1,
		TSP_TLV_REG_PATH1_DATA_CHK_2T_0040);
	vIO32WriteFld(REG_TLV0_BASE + REG_0080_TSP_TLV, 1,
		TSP_TLV_REG_PATH2_DATA_CHK_2T_0080);

	// enable path id check in source_id_parser
	vIO32WriteFld(REG_TSP6_BASE + REG_01F4_TSP6, 0,
				  TSP6_REG_DISABLE_PATH_ID_CHK_IN_SRC_ID_PARSER_01F4);

	// enable TSIF TSO block scheme
	vIO32WriteFldMulti(REG_TSP5_BASE + REG_0010_TSP5, 4,
	1, TSP5_REG_TSIF_TSO_BLK_EN_0010,
	1, TSP5_REG_TSIF1_TSO_BLK_EN_0010,
	1, TSP5_REG_TSIF2_TSO_BLK_EN_0010,
	1, TSP5_REG_TSIF_FI_TSO_BLK_EN_0010);

	// select 50% full as condition for tsif2tso fifo full
	vIO32WriteFld(REG_TSP5_BASE + REG_017C_TSP5, 1,
		TSP5_REG_TSIF_2TSO_FIFO_FULL_CONDITION_SEL_017C);

	// serial-in detection config
	vIO32WriteFld(REG_TSP0_BASE + REG_0110_TSP0, 1, TSP0_REG_SYNC_RISING_DETECT_0110);
	vIO32WriteFld(REG_TSP0_BASE + REG_0110_TSP0, 1, TSP0_REG_VALID_FALLING_DETECT_0110);

	// drop packet condition when dup cc & pusi flag
	vIO32WriteFldMulti(REG_TSP5_BASE + REG_0060_TSP5, 4,
	5, TSP5_REG_CC_PUSI_DROP_SEL_VID_0060,
	5, TSP5_REG_CC_PUSI_DROP_SEL_V3D_0060,
	5, TSP5_REG_CC_PUSI_DROP_SEL_AUD_0060,
	5, TSP5_REG_CC_PUSI_DROP_SEL_AUDB_0060);
	vIO32WriteFldMulti(REG_TSP5_BASE + REG_0064_TSP5, 2,
	5, TSP5_REG_CC_PUSI_DROP_SEL_AUDC_0064,
	5, TSP5_REG_CC_PUSI_DROP_SEL_AUDD_0064);

	// skip tei packet
	vIO32WriteFldMulti(REG_TSP0_BASE + REG_016C_TSP0, 3,
	1, TSP0_REG_TEI_SKIP_PKT_PID0_016C,
	1, TSP0_REG_TEI_SKIP_PKT_FILE_016C,
	1, TSP0_REG_TEI_SKIP_PKT_PID1_016C
	);
	vIO32WriteFld(REG_TSP0_BASE + REG_003C_TSP0, 1, TSP0_REG_TEI_SKIP_PKT2_003C);

	// TLV path ECO
	tlv_num = mtk_dmx_rm_get_hwcap_by_id(&dmxdev->rm, HWCAPS_TYPE_TLV);
#define TLV_REG_PATH_CONFIG_ECO 0x6
	for (i = TLV_TSIF_0; i < TLV_TSIF_0 + tlv_num; i++) {
		switch (i) {
		case TLV_TSIF_0:
			vIO32WriteFld(REG_TLV0_BASE + REG_0000_TSP_TLV
				, 1, TSP_TLV_REG_FORCE_SYNC_BYTE_0000);
			vIO32WriteFld(REG_TLV0_BASE + REG_0000_TSP_TLV
				, 1, TSP_TLV_REG_TLV_FIFO_BYPASS_0000);
			vIO32WriteFld(REG_TLV0_BASE + REG_0000_TSP_TLV
				, 1, TSP_TLV_REG_TLV_FIFO_EVER_FULL_CLR_0000);
			vIO32WriteFld(REG_TLV0_BASE + REG_0008_TSP_TLV
				, 0, TSP_TLV_REG_TLVIF_LEAF_BLOCK_EN_0008);
			vIO32WriteFld(REG_TLV0_BASE + REG_0008_TSP_TLV
				, 1, TSP_TLV_REG_TLV_IF_EN_FOR_SYNC_VLD_0008);
			vIO32WriteFld(REG_TLV0_BASE + REG_0038_TSP_TLV
				, TLV_REG_PATH_CONFIG_ECO
				, TSP_TLV_REG_TLV_PATH_CONFIG_0038);
			break;
		case TLV_TSIF_1:
			vIO32WriteFld(REG_TLV0_BASE + REG_0040_TSP_TLV
				, 1, TSP_TLV_REG_PATH1_FORCE_SYNC_BYTE_0040);
			vIO32WriteFld(REG_TLV0_BASE + REG_0040_TSP_TLV
				, 1, TSP_TLV_REG_PATH1_TLV_FIFO_BYPASS_0040);
			vIO32WriteFld(REG_TLV0_BASE + REG_0040_TSP_TLV
				, 1, TSP_TLV_REG_PATH1_TLV_FIFO_EVER_FULL_CLR_0040);
			vIO32WriteFld(REG_TLV0_BASE + REG_0048_TSP_TLV
				, 0, TSP_TLV_REG_PATH1_TLVIF_LEAF_BLOCK_EN_0048);
			vIO32WriteFld(REG_TLV0_BASE + REG_0048_TSP_TLV
				, 1, TSP_TLV_REG_PATH1_TLV_IF_EN_FOR_SYNC_VLD_0048);
			vIO32WriteFld(REG_TLV0_BASE + REG_0078_TSP_TLV
				, TLV_REG_PATH_CONFIG_ECO
				, TSP_TLV_REG_PATH1_TLV_PATH_CONFIG_0078);
			break;
		case TLV_TSIF_2:
			vIO32WriteFld(REG_TLV0_BASE + REG_0080_TSP_TLV
				, 1, TSP_TLV_REG_PATH2_FORCE_SYNC_BYTE_0080);
			vIO32WriteFld(REG_TLV0_BASE + REG_0080_TSP_TLV
				, 1, TSP_TLV_REG_PATH2_TLV_FIFO_BYPASS_0080);
			vIO32WriteFld(REG_TLV0_BASE + REG_0080_TSP_TLV
				, 1, TSP_TLV_REG_PATH2_TLV_FIFO_EVER_FULL_CLR_0080);
			vIO32WriteFld(REG_TLV0_BASE + REG_0088_TSP_TLV
				, 0, TSP_TLV_REG_PATH2_TLVIF_LEAF_BLOCK_EN_0088);
			vIO32WriteFld(REG_TLV0_BASE + REG_0088_TSP_TLV
				, 1, TSP_TLV_REG_PATH2_TLV_IF_EN_FOR_SYNC_VLD_0088);
			vIO32WriteFld(REG_TLV0_BASE + REG_00B8_TSP_TLV
				, TLV_REG_PATH_CONFIG_ECO
				, TSP_TLV_REG_PATH2_TLV_PATH_CONFIG_00B8);
			break;
		default:
			break;
		}
	}
}

static void _init_FileIn(void)
{
	// fix 192 mode timer equal to 0 issue
	vIO32WriteFld(REG_TSP5_BASE + REG_0018_TSP5, 1, TSP5_REG_FIX_192_TIMER_0_EN_0018);

	// speed up 192 flow control when lose lock
	vIO32WriteFld(REG_TSP6_BASE + REG_01F4_TSP6, 1, TSP6_REG_FIX_192_UNLOCK_HANG_EN_01F4);

	// file-in match_cnt function
	vIO32WriteFld(REG_TSP5_BASE + REG_001C_TSP5, 1, TSP5_REG_MATCH_CNT_FILEIN_EN_001C);
	vIO32WriteFld(REG_TSP5_BASE + REG_001C_TSP5, 0xF, TSP5_REG_MATCH_CNT_THRESHOLD_001C);
}

static void _init_VQ_and_SEC(bool iommu)
{
	// Bad initial value of TSP_CTRL1
	// Suppose Standby mode for TSP should NOT be enabled.
	// Enabling TSP standby mode cause TSP section registers (SRAM in AEON) malfunction.
	// Disable it by SW at this stage.
	vIO32WriteFld(REG_TSP0_BASE + REG_01FC_TSP0, 0, TSP0_REG_STANDBY_01FC);

	// Set 1 to disable all SRAM in TSP for low power mode automatically
	vIO32WriteFld(REG_TSP1_BASE + REG_0020_TSP1, 1, TSP1_REG_HW_STANDBY_MODE_0020);

	// prevent from byte enable bug, bit1~3 must enable togather
	vIO32WriteFldMulti(REG_TSP0_BASE + REG_0114_TSP0, 2,
	1, TSP0_REG_ALT_TS_SIZE_0114,
	1, TSP0_REG_RD_LOAD_DIS_0114);

	// HW bug: set 1 to let TSP fit with MIU protocol
	vIO32WriteFld(REG_TSP5_BASE + REG_01F8_TSP5, 1, TSP5_REG_VQ_IDLE_CNT_CONFIG_01F8_9);

	// set 1 to enable the section data go through pingpong buffer
	vIO32WriteFld(REG_TSP1_BASE + REG_01C8_TSP1, 1, TSP1_REG_VQ2PINGPONG_EN_01C8);

	// set 1 to flush out the data staying in the pipe
	vIO32WriteFld(REG_TSP1_BASE + REG_01C8_TSP1, 1, TSP1_REG_RM_PKT_DEMUX_PIPE_01C8);

	// force VQ pinpong buffer to flush and disable all live paths block mechanism
	vIO32WriteFld(REG_TSP1_BASE + REG_0018_TSP1, 1, TSP1_REG_RM_PINPON_LIMIT_0018);
	vIO32WriteFld(REG_TSP1_BASE + REG_001C_TSP1, 1, TSP1_REG_RM_DMA_GLITCH_001C);

	// ECO bit for section DMA burst mode
	vIO32WriteFld(REG_TSP1_BASE + REG_0024_TSP1, 1, TSP1_REG_SEC_DMA_BURST_EN_0024);

	// prevent SRAM collision
	vIO32WriteFld(REG_TSP3_BASE + REG_0050_TSP3, 1, TSP3_REG_HW3_CONFIG0_0050_0);

	// VQ parameters
	vIO32WriteFld(REG_TSP1_BASE + REG_008C_TSP1, 0x0C, TSP1_REG_VQ0_FORCEFIRE_CNT_1K_008C);
	vIO32WriteFld(REG_TSP1_BASE + REG_0174_TSP1, 0x0C, TSP1_REG_VQ1_FORCEFIRE_CNT_1K_0174);
	vIO32WriteFld(REG_TSP1_BASE + REG_0194_TSP1, 0x0C, TSP1_REG_VQ2_FORCEFIRE_CNT_1K_0194);

	if (iommu) {
		vIO32WriteFld(REG_TSP6_BASE + REG_01F4_TSP6, 2, TSP6_REG_SECFLT_EXT_MODE_01F4);
		vIO32WriteFld(REG_TSP1_BASE + REG_00FC_TSP1, 2, TSP1_REG_ORZ2MI_ADDR_EXT_00FC);
	}
}

static void _init_AV(void)
{
	// set 1 to remove duplicate video/audio packets
	vIO32WriteFldMulti(REG_TSP1_BASE + REG_0024_TSP1, 6,
	1, TSP1_REG_DUP_PKT_SKIP_V_0024,
	1, TSP1_REG_DUP_PKT_SKIP_V3D_0024,
	1, TSP1_REG_DUP_PKT_SKIP_A_0024,
	1, TSP1_REG_DUP_PKT_SKIP_AD_0024,
	1, TSP1_REG_DUP_PKT_SKIP_AD_C_0024,
	1, TSP1_REG_DUP_PKT_SKIP_AD_D_0024);

    // PUSI 3 byte mode
	vIO32WriteFld(REG_TSP3_BASE + REG_0050_TSP3, 1, TSP3_REG_HW3_CONFIG0_0050_RESERVED_1);

	// drop scrambled packets
	vIO32WriteFldMulti(REG_TSP3_BASE + REG_0054_TSP3, 6,
	1, TSP3_REG_HW3_CONFIG1_0054_0,
	1, TSP3_REG_HW3_CONFIG1_0054_1,
	1, TSP3_REG_HW3_CONFIG1_0054_2,
	1, TSP3_REG_HW3_CONFIG1_0054_3,
	1, TSP3_REG_HW3_CONFIG1_0054_4,
	1, TSP3_REG_HW3_CONFIG1_0054_5);

	// drop a/v/pvr data in leaf fifo when fifo full
	vIO32WriteFld(REG_TSP5_BASE + REG_017C_TSP5, 1, TSP5_REG_LEAF_DROP_DATA_ENABLE_017C);
}

void mtk_dmx_init_hw(struct mtk_dmx2dev *mtkdev)
{
	bool iommu = (mtkdev->rm.memmap->list[MMAP_BUF_TYPE_SEC]->heaptype == HEAP_IOMMU
		|| mtkdev->rm.memmap->list[MMAP_BUF_TYPE_SEC]->heaptype == HEAP_IOMMU_POOL)
		? true : false;

	// SW reset
	vIO32WriteFld(REG_TSP0_BASE + REG_01E8_TSP0, 0, TSP0_REG_SW_RSTZ_01E8);
	vIO32WriteFld(REG_TSP0_BASE + REG_01E8_TSP0, 1, TSP0_REG_SW_RSTZ_01E8);

	// ECO
	vIO32WriteFldMulti(REG_TSP3_BASE + REG_008C_TSP3, 7,
	1, TSP3_REG_ECO0_008C_0,
	1, TSP3_REG_ECO0_008C_1,
	1, TSP3_REG_ECO0_008C_4,
	1, TSP3_REG_ECO0_008C_5,
	1, TSP3_REG_ECO0_008C_10,
	1, TSP3_REG_ECO0_008C_11,
	1, TSP3_REG_ECO0_008C_14);

	vIO32WriteFldMulti(REG_TSP5_BASE + REG_0030_TSP5,
	7,
	1, TSP5_REG_NMATCH_DIS_0030,
	1, TSP5_REG_SCR_BIT_AFTER_CA_0030,
	1, TSP5_REG_ECO_TS_SYNC_OUT_DELAY_0030,
	1, TSP5_REG_ECO_TS_SYNC_OUT_REVERSE_BLOCK_0030,
	1, TSP5_REG_ECO_FIQ_INPUT_0030,
	1, TSP5_REG_SECFLT_CTRL_DMA_DIS_0030,
	1, TSP5_REG_PKT_CONVERTER_FIRST_SYNC_VALID_MASK_EN_0030);

	// if the incoming packet is a only adaptation field packet,
	// the scramble status will not be updated
	vIO32WriteFld(REG_TSP1_BASE + REG_0070_TSP1, 1, TSP1_REG_BLK_AF_SCRMB_BIT_0070);

	// STC 64 bit mode
	vIO32WriteFld(REG_TSP1_BASE + REG_0024_TSP1, 1, TSP1_REG_SYS_TIME_MODE_0024);

	// update match_scr_start_code (not consider scramble control bits)
	vIO32WriteFld(REG_TSP3_BASE + REG_0164_TSP3, 0, TSP3_REG_MATCH_SCR_START_CODE_SCR_EN_0164);

	_init_VQ_and_SEC(iommu);
	_init_AV();
	_init_LiveIn(mtkdev);
	_init_FileIn();
}

bool mtk_dmx_load_fw(u64 paddr, u32 size)
{
	u16 dma_addr_L, dma_addr_H;

	// disable TSP mcu
	vIO32WriteFld(REG_TSP0_BASE + REG_01E8_TSP0, 0, TSP0_REG_NOEA_ENABLE_01E8);

	// cpu base addr
	RegWrite4B(REG_TSP0_BASE + REG_0180_TSP0, REG_TSP0_BASE + REG_0184_TSP0, 0);

	// DMA read addr[19:4]
	dma_addr_L = (u16)(paddr >> (MIU_BUS + FW_DMA_ADDR_ALIGN_SHIFT));
	vIO32Write2B(REG_TSP0_BASE + REG_01E0_TSP0, dma_addr_L);

	// DMA read addr[35:20]
	dma_addr_H = (u16)(paddr >> (MIU_BUS + FW_DMA_ADDR_ALIGN_SHIFT + 16));
	vIO32Write2B(REG_TSP1_BASE + REG_0028_TSP1, dma_addr_H);

	// DMA read size (64 KB)
	vIO32Write2B(REG_TSP0_BASE + REG_01E4_TSP0, 0x4000);

	// DMA start
	vIO32WriteFldMulti(REG_TSP0_BASE + REG_01E8_TSP0, 2,
	0, TSP0_REG_DMA_RSTART_01E8,
	0, TSP0_REG_DMA_DONE_01E8);

	vIO32WriteFld(REG_TSP0_BASE + REG_01E8_TSP0, 1, TSP0_REG_DMA_RSTART_01E8);

	while (!u4IO32ReadFld(REG_TSP0_BASE + REG_01E8_TSP0, TSP0_REG_DMA_DONE_01E8));

	vIO32WriteFldMulti(REG_TSP0_BASE + REG_01E8_TSP0, 2,
	0, TSP0_REG_DMA_RSTART_01E8,
	0, TSP0_REG_DMA_DONE_01E8);

	RegWrite4B(REG_TSP0_BASE + REG_0188_TSP0, REG_TSP0_BASE + REG_018C_TSP0, 0);
	RegWrite4B(REG_TSP0_BASE + REG_0190_TSP0,
		REG_TSP0_BASE + REG_0194_TSP0, 0xffff0000);
	RegWrite4B(REG_TSP0_BASE + REG_0198_TSP0, REG_TSP0_BASE + REG_019C_TSP0, 0);
	RegWrite4B(REG_TSP0_BASE + REG_01A0_TSP0,
		REG_TSP0_BASE + REG_01A4_TSP0, 0xffff0000);

	// enable TSP mcu
	vIO32WriteFld(REG_TSP0_BASE + REG_01E8_TSP0, 1, TSP0_REG_NOEA_ENABLE_01E8);

	return mtk_dmx_check_fw_alive();
}

bool mtk_dmx_check_fw_alive(void)
{
	u32 msg_0 = 0;

	if (!send_mcu_cmd(MCU_CMD_ALIVE, &msg_0, NULL))
		return false;

	return (msg_0 == MCU_CMD_ALIVE) ? true : false;
}

static void mtk_dmx_set_vq_buffer(u16 eng_id, u64 vq_addr, u32 vq_size)
{
	REG16 __iomem *base_offset, *size_offset;

	switch (eng_id) {
	case TSIF_0:
		base_offset = REG_TSP1_BASE + REG_0080_TSP1;
		size_offset = REG_TSP1_BASE + REG_0088_TSP1;
		break;
	case TSIF_FI:
		base_offset = REG_TSP1_BASE + REG_0158_TSP1;
		size_offset = REG_TSP1_BASE + REG_0170_TSP1;
		break;
	case TSIF_1:
		base_offset = REG_TSP1_BASE + REG_0178_TSP1;
		size_offset = REG_TSP1_BASE + REG_0190_TSP1;
		break;
	case TSIF_2:
		base_offset = REG_TSP1_BASE + REG_01D0_TSP1;
		size_offset = REG_TSP1_BASE + REG_01D8_TSP1;
		break;
	case TLV_TSIF_0:
		base_offset = REG_TLV1_BASE + REG_0120_TSP_TLV2;
		size_offset = REG_TLV1_BASE + REG_0128_TSP_TLV2;
		break;
	case TLV_TSIF_1:
		base_offset = REG_TLV1_BASE + REG_0140_TSP_TLV2;
		size_offset = REG_TLV1_BASE + REG_0148_TSP_TLV2;
		break;
	case TLV_TSIF_2:
		base_offset = REG_TLV1_BASE + REG_0160_TSP_TLV2;
		size_offset = REG_TLV1_BASE + REG_0168_TSP_TLV2;
		break;
	default:
		return;
	}

	RegWrite4B(base_offset, base_offset + 4, (u32)(vq_addr >> MIU_BUS));
	vIO32Write2B(size_offset, (u16)(vq_size / VQ_PACKET_UNIT_LENGTH));
}

static void mtk_dmx_reset_vq_buffer(u16 eng_id)
{
	REG16 __iomem *ctrl_offset;
	u32 vq_reset;

	switch (eng_id) {
	case TSIF_0:
		ctrl_offset = REG_TSP1_BASE + REG_008C_TSP1;
		vq_reset = TSP1_REG_VQ0_RESET_008C;
		break;
	case TSIF_FI:
		ctrl_offset = REG_TSP1_BASE + REG_0174_TSP1;
		vq_reset = TSP1_REG_VQ1_RESET_0174;
		break;
	case TSIF_1:
		ctrl_offset = REG_TSP1_BASE + REG_0194_TSP1;
		vq_reset = TSP1_REG_VQ2_RESET_0194;
		break;
	case TSIF_2:
		ctrl_offset = REG_TSP1_BASE + REG_01DC_TSP1;
		vq_reset = TSP1_REG_VQ3_RESET_01DC;
		break;
	case TLV_TSIF_0:
		ctrl_offset = REG_TLV1_BASE + REG_012C_TSP_TLV2;
		vq_reset = TSP_TLV2_REG_VQ_RESET_012C;
		break;
	case TLV_TSIF_1:
		ctrl_offset = REG_TLV1_BASE + REG_014C_TSP_TLV2;
		vq_reset = TSP_TLV2_REG_VQ5_RESET_014C;
		break;
	case TLV_TSIF_2:
		ctrl_offset = REG_TLV1_BASE + REG_016C_TSP_TLV2;
		vq_reset = TSP_TLV2_REG_VQ6_RESET_016C;
		break;
	default:
		return;
	}

	vIO32WriteFld(ctrl_offset, 1, vq_reset);
	vIO32WriteFld(ctrl_offset, 0, vq_reset);
}

void mtk_dmx_set_vq_buffers(u64 paddr, u32 size, u16 vq_num)
{
	u16 i;
	u64 vq_addr = paddr;
	u32 vq_size = ((size / vq_num) >> MIU_BUS) << MIU_BUS; // miu alignment

	for (i = 0; i < vq_num; i++, vq_addr += vq_size)
		mtk_dmx_set_vq_buffer(i, vq_addr, vq_size);
}

void mtk_dmx_enable_vq_buffers(u16 vq_num)
{
	u16 i;

	for (i = 0; i < vq_num; i++)
		mtk_dmx_reset_vq_buffer(i);

	vIO32WriteFld(REG_TSP1_BASE + REG_01C8_TSP1, 1, TSP1_REG_VQ_EN_01C8);
}

void mtk_dmx_interrupt_ctrl(bool bEnable)
{
	// enable AEON -> ACPU interrupt
	if (bEnable) {
		mtk_dmx_clear_sw_interrupt_status();
		vIO32WriteFld(REG_TSP0_BASE + REG_01F8_TSP0, 1, TSP0_REG_INT_EN_01F8_5);
	} else {
		vIO32WriteFld(REG_TSP0_BASE + REG_01F8_TSP0, 0, TSP0_REG_INT_EN_01F8_5);
	}
}

void mtk_dmx_ntp_reset(int path)
{
#define NTP_RESET_CONFIG_MASK0 0x0002
#define NTP_RESET_CONFIG_MASK1 0x0040
#define NTP_RESET_CONFIG_MASK2 0x0800
	u16 value_reset_low, value_reset_high, value_reset0, value_reset1;

	// reset ntp filter config
	switch (path) {
	case TLV_TSIF_0:
		value_reset_low = u2IO32Read2B(REG_TLV0_BASE + REG_01AC_TSP_TLV);
		value_reset_high = u2IO32Read2B(REG_TLV0_BASE + REG_01B0_TSP_TLV);
		value_reset0 = value_reset_low & ~(NTP_RESET_CONFIG_MASK0);
		value_reset1 = value_reset_low | NTP_RESET_CONFIG_MASK0;
		vIO32Write2B(REG_TLV0_BASE + REG_01AC_TSP_TLV, value_reset1);
		vIO32Write2B(REG_TLV0_BASE + REG_01B0_TSP_TLV, value_reset_high);
		vIO32Write2B(REG_TLV0_BASE + REG_01AC_TSP_TLV, value_reset0);
		vIO32Write2B(REG_TLV0_BASE + REG_01B0_TSP_TLV, value_reset_high);
		break;
	case TLV_TSIF_1:
		value_reset_low = u2IO32Read2B(REG_TLV0_BASE + REG_01AC_TSP_TLV);
		value_reset_high = u2IO32Read2B(REG_TLV0_BASE + REG_01B0_TSP_TLV);
		value_reset0 = value_reset_low & ~(NTP_RESET_CONFIG_MASK1);
		value_reset1 = value_reset_low | NTP_RESET_CONFIG_MASK1;
		vIO32Write2B(REG_TLV0_BASE + REG_01AC_TSP_TLV, value_reset1);
		vIO32Write2B(REG_TLV0_BASE + REG_01B0_TSP_TLV, value_reset_high);
		vIO32Write2B(REG_TLV0_BASE + REG_01AC_TSP_TLV, value_reset0);
		vIO32Write2B(REG_TLV0_BASE + REG_01B0_TSP_TLV, value_reset_high);
		break;
	case TLV_TSIF_2:
		value_reset_low = u2IO32Read2B(REG_TLV0_BASE + REG_01AC_TSP_TLV);
		value_reset_high = u2IO32Read2B(REG_TLV0_BASE + REG_01B0_TSP_TLV);
		value_reset0 = value_reset_low & ~(NTP_RESET_CONFIG_MASK2);
		value_reset1 = value_reset_low | NTP_RESET_CONFIG_MASK2;
		vIO32Write2B(REG_TLV0_BASE + REG_01AC_TSP_TLV, value_reset1);
		vIO32Write2B(REG_TLV0_BASE + REG_01B0_TSP_TLV, value_reset_high);
		vIO32Write2B(REG_TLV0_BASE + REG_01AC_TSP_TLV, value_reset0);
		vIO32Write2B(REG_TLV0_BASE + REG_01B0_TSP_TLV, value_reset_high);
		break;
	default:
		break;
	}
}

void mtk_dmx_ntp_interrupt_ctrl(int path, bool bEnable)
{
	u16 value, mask;

	switch (path) {
	case TLV_TSIF_0:
		mask = NTP_INTERRUPT_0;
		break;
	case TLV_TSIF_1:
		mask = NTP_INTERRUPT_1;
		break;
	case TLV_TSIF_2:
		mask = NTP_INTERRUPT_2;
		break;
	default:
		return;
	}

	value = u2IO32Read2B(REG_TLV0_BASE + REG_018C_TSP_TLV) | TLV_INTERRUPT_MASK;
	if (bEnable)
		value |= mask;
	else
		value &= ~mask;
	vIO32Write2B(REG_TLV0_BASE + REG_0188_TSP_TLV, value);

	// reset ntp filter config
	mtk_dmx_ntp_reset(path);
}

u32 mtk_dmx_get_sw_interrupt_status(void)
{
	return RegRead4B(REG_TSP0_BASE + REG_00E0_TSP0, REG_TSP0_BASE + REG_00E4_TSP0);
}

bool mtk_dmx_get_pcr_interrupt_status(u16 filter_id)
{
	u32 bit_pos;

	switch (filter_id) {
	case PCR_0:
		bit_pos = TSP1_REG_INT2_FLAG_01B0_11;
		break;
	case PCR_1:
		bit_pos = TSP1_REG_INT2_FLAG_01B0_10;
		break;
	default:
		return false;
	}

	return u4IO32ReadFld(REG_TSP1_BASE + REG_01B0_TSP1, bit_pos);
}

bool mtk_dmx_get_ntp_interrupt_status(u16 filter_id)
{
	bool status = false;
	u16 value = u4IO32ReadFld(REG_TLV0_BASE + REG_018C_TSP_TLV,
		TSP_TLV_REG_INTERRUPT_TLV1_018C_15_8);

	switch (filter_id) {
	case TLV_TSIF_0:
		status = (value & 0x10) == 0x10;
		break;
	case TLV_TSIF_1:
		status = (value & 0x20) == 0x20;
		break;
	case TLV_TSIF_2:
		status = (value & 0x40) == 0x40;
		break;
	default:
		return status;
	}

	return status;
}

void mtk_dmx_clear_sw_interrupt_status(void)
{
	RegWrite4B(REG_TSP0_BASE + REG_00E0_TSP0, REG_TSP0_BASE + REG_00E4_TSP0, 0);
	vIO32WriteFld(REG_TSP0_BASE + REG_01F8_TSP0, 0, TSP0_REG_INT_STATUS_01F8_13);
}

void mtk_dmx_clear_pcr_interrupt_status(u16 filter_id)
{
	u32 bit_pos;

	switch (filter_id) {
	case PCR_0:
		bit_pos = TSP1_REG_INT2_FLAG_01B0_11;
	break;
	case PCR_1:
		bit_pos = TSP1_REG_INT2_FLAG_01B0_10;
		break;
	default:
		return;
	}

	vIO32WriteFld(REG_TSP1_BASE + REG_01B0_TSP1, 0, bit_pos);
}

void mtk_dmx_clear_ntp_interrupt_status(u16 filter_id)
{
#define NTP0_CLR_OFFSET 12
#define NTP1_CLR_OFFSET 13
#define NTP2_CLR_OFFSET 14
	u16 value = u2IO32Read2B(REG_TLV0_BASE + REG_018C_TSP_TLV);

	switch (filter_id) {
	case TLV_TSIF_0:
		value &= ~(1 << NTP0_CLR_OFFSET);
		break;
	case TLV_TSIF_1:
		value &= ~(1 << NTP1_CLR_OFFSET);
		break;
	case TLV_TSIF_2:
		value &= ~(1 << NTP2_CLR_OFFSET);
		break;
	default:
		return;
	}

	vIO32Write2B(REG_TLV0_BASE + REG_0188_TSP_TLV, value);
}

static bool _is_afifo_empty(u16 eng_id)
{
	REG16 __iomem *offset;
	u32 fld;

	switch (eng_id) {
	case AFIFO_0:
		offset = REG_TSP0_BASE + REG_00DC_TSP0;
		fld = TSP0_REG_AFIFO_STATUS_00DC_8;
		break;
	case AFIFO_1:
		offset = REG_TSP0_BASE + REG_00DC_TSP0;
		fld = TSP0_REG_AFIFOB_STATUS_00DC_12;
		break;
	case AFIFO_2:
		offset = REG_TSP1_BASE + REG_0180_TSP1;
		fld = TSP1_REG_AV_FIFO_ST3_0180_0;
		break;
	case AFIFO_3:
		offset = REG_TSP1_BASE + REG_0180_TSP1;
		fld = TSP1_REG_AV_FIFO_ST3_0180_4;
		break;
	default:
		return 0;
	}

	return (u32)(u4IO32ReadFld(offset, fld));
}

void mtk_dmx_reset_afifo(u16 eng_id, bool bReset)
{
	REG16 __iomem *offset;
	u32 nr;
	u32 retry = FIFO_RESET_MAX_RETRY;

	switch (eng_id) {
	case AFIFO_0:
		offset = REG_TSP1_BASE + REG_001C_TSP1;
		nr = TSP1_REG_RESET_AFIFO_001C;
		break;
	case AFIFO_1:
		offset = REG_TSP1_BASE + REG_001C_TSP1;
		nr = TSP1_REG_RESET_AFIFOB_001C;
		break;
	case AFIFO_2:
		offset = REG_TSP1_BASE + REG_01CC_TSP1;
		nr = TSP1_REG_RESET_AFIFOC_01CC;
		break;
	case AFIFO_3:
		offset = REG_TSP1_BASE + REG_01CC_TSP1;
		nr = TSP1_REG_RESET_AFIFOD_01CC;
		break;
	default:
		return;
	}

	if (bReset) {
		vIO32WriteFld(offset, 1, nr);

		do {
			usleep_range(FIFO_RESET_TIMEOUT_MIN
				, FIFO_RESET_TIMEOUT_MAX);
			retry--;
		} while (!_is_afifo_empty(eng_id) && retry != 0);

		if (retry == 0)
			MTK_DMX_ERR("AFifo reset timeout\n");

		MTK_DMX_INFO("AFifo reset done, try count: %d\n", FIFO_RESET_MAX_RETRY-retry);
	} else
		vIO32WriteFld(offset, 0, nr);
}

static bool _is_vfifo_empty(u16 eng_id)
{
	u32 fld;

	switch (eng_id) {
	case VFIFO_0:
		fld = TSP0_REG_VFIFO_STATUS_00DC_4;
		break;
	case VFIFO_1:
		fld = TSP0_REG_VFIFO_3D_STATUS_00DC_0;
		break;
	default:
		return 0;
	}

	return u4IO32ReadFld(REG_TSP0_BASE + REG_00DC_TSP0, fld);
}

void mtk_dmx_reset_vfifo(u16 eng_id, bool bReset)
{
	REG16 __iomem *offset;
	u32 nr;
	u32 retry = FIFO_RESET_MAX_RETRY;

	switch (eng_id) {
	case VFIFO_0:
		offset = REG_TSP1_BASE + REG_001C_TSP1;
		nr = TSP1_REG_RESET_VFIFO_001C;
		break;
	case VFIFO_1:
		offset = REG_TSP1_BASE + REG_001C_TSP1;
		nr = TSP1_REG_RESET_VFIFO_3D_001C;
		break;
	default:
		return;
	}

	if (bReset) {
		vIO32WriteFld(offset, 1, nr);

		do {
			usleep_range(FIFO_RESET_TIMEOUT_MIN
				, FIFO_RESET_TIMEOUT_MAX);
			retry--;
		} while (!_is_vfifo_empty(eng_id) && retry != 0);

		if (retry == 0)
			MTK_DMX_ERR("VFifo reset timeout\n");

		MTK_DMX_INFO("VFifo reset done, try count: %d\n", FIFO_RESET_MAX_RETRY-retry);
	} else {
		vIO32WriteFld(offset, 0, nr);
	}
}

void mtk_dmx_reset_tso(void)
{
	REG16 __iomem *offset;
	u32 nr;

	offset = REG_TSO0_BASE + REG_0000_TSO;
	nr = TSO0_REG_SW_RSTZ_0000_0;
	vIO32WriteFld(offset, 0, nr);
	usleep_range(10, 20);
	vIO32WriteFld(offset, 1, nr);
}

u32 mtk_dmx_get_video_drop_cnt(u16 eng_id)
{
	REG16 __iomem *offset;
	u32 load_bit;

	switch (eng_id) {
	case VFIFO_0:
		offset = REG_TSP4_BASE + REG_0014_TSP4;
		load_bit = TSP4_REG_DROP_PKT_CNT_V_LOAD_01EC;
		break;
	case VFIFO_1:
		offset = REG_TSP4_BASE + REG_0018_TSP4;
		load_bit = TSP4_REG_DROP_PKT_CNT_V3D_LOAD_01EC;
		break;
	default:
		return 0;
	}

	vIO32WriteFld(REG_TSP4_BASE + REG_01FC_TSP4, 1, TSP4_REG_DROP_PKT_MODE_01FC);
	vIO32WriteFld(REG_TSP4_BASE + REG_01EC_TSP4, 1, load_bit);

	return (u32)(u2IO32Read2B(offset));
}

u32 mtk_dmx_get_audio_drop_cnt(u16 eng_id)
{
	REG16 __iomem *offset;
	u32 load_bit;

	switch (eng_id) {
	case AFIFO_0:
		offset = REG_TSP4_BASE + REG_001C_TSP4;
		load_bit = TSP4_REG_DROP_PKT_CNT_A_LOAD_01EC;
		break;
	case AFIFO_1:
		offset = REG_TSP4_BASE + REG_0020_TSP4;
		load_bit = TSP4_REG_DROP_PKT_CNT_AD_LOAD_01EC;
		break;
	case AFIFO_2:
		offset = REG_TSP4_BASE + REG_0024_TSP4;
		load_bit = TSP4_REG_DROP_PKT_CNT_ADC_LOAD_01EC;
		break;
	case AFIFO_3:
		offset = REG_TSP4_BASE + REG_0028_TSP4;
		load_bit = TSP4_REG_DROP_PKT_CNT_ADD_LOAD_01EC;
		break;
	default:
		return 0;
	}

	vIO32WriteFld(REG_TSP4_BASE + REG_01FC_TSP4, 1, TSP4_REG_DROP_PKT_MODE_01FC);
	vIO32WriteFld(REG_TSP4_BASE + REG_01EC_TSP4, 1, load_bit);

	return (u32)(u2IO32Read2B(offset));
}

u32 mtk_dmx_get_video_dis_conti_cnt(u16 eng_id)
{
	REG16 __iomem *offset;
	u32 load_bit;

	switch (eng_id) {
	case VFIFO_0:
		offset = REG_TSP4_BASE + REG_0014_TSP4;
		load_bit = TSP4_REG_DIS_CNTR_V_LOAD_01EC;
		break;
	case VFIFO_1:
		offset = REG_TSP4_BASE + REG_0018_TSP4;
		load_bit = TSP4_REG_DIS_CNTR_V3D_LOAD_01EC;
		break;
	default:
		return 0;
	}

	vIO32WriteFld(REG_TSP4_BASE + REG_01FC_TSP4, 0, TSP4_REG_DROP_PKT_MODE_01FC);
	vIO32WriteFld(REG_TSP4_BASE + REG_01EC_TSP4, 1, load_bit);

	return (u32)(u2IO32Read2B(offset));
}

u32 mtk_dmx_get_audio_dis_conti_cnt(u16 eng_id)
{
	REG16 __iomem *offset;
	u32 load_bit;

	switch (eng_id) {
	case AFIFO_0:
		offset = REG_TSP4_BASE + REG_001C_TSP4;
		load_bit = TSP4_REG_DIS_CNTR_A_LOAD_01EC;
		break;
	case AFIFO_1:
		offset = REG_TSP4_BASE + REG_0020_TSP4;
		load_bit = TSP4_REG_DIS_CNTR_AD_LOAD_01EC;
		break;
	case AFIFO_2:
		offset = REG_TSP4_BASE + REG_0024_TSP4;
		load_bit = TSP4_REG_DIS_CNTR_ADC_LOAD_01EC;
		break;
	case AFIFO_3:
		offset = REG_TSP4_BASE + REG_0028_TSP4;
		load_bit = TSP4_REG_DIS_CNTR_ADD_LOAD_01EC;
		break;
	default:
		return 0;
	}

	vIO32WriteFld(REG_TSP4_BASE + REG_01FC_TSP4, 0, TSP4_REG_DROP_PKT_MODE_01FC);
	vIO32WriteFld(REG_TSP4_BASE + REG_01EC_TSP4, 1, load_bit);

	return (u32)(u2IO32Read2B(offset));
}

u32 mtk_dmx_get_video_pkt_cnt(u16 eng_id)
{
	REG16 __iomem *offset;
	u32 load_bit;

	switch (eng_id) {
	case VFIFO_0:
		offset = REG_TSP4_BASE + REG_0038_TSP4;
		load_bit = TSP4_REG_V_PKT_CNT_LOAD_01E8;
		break;
	case VFIFO_1:
		offset = REG_TSP4_BASE + REG_005C_TSP4;
		load_bit = TSP4_REG_V3D_PKT_CNT_LOAD_01E8;
		break;
	default:
		return 0;
	}

	vIO32WriteFld(REG_TSP4_BASE + REG_01FC_TSP4, 0, TSP4_REG_AV_PKT_SRC_SEL_01FC);
	vIO32WriteFld(REG_TSP4_BASE + REG_01E8_TSP4, 1, load_bit);

	return (u32)(u2IO32Read2B(offset));
}

u32 mtk_dmx_get_audio_pkt_cnt(u16 eng_id)
{
	REG16 __iomem *offset;
	u32 load_bit;
	bool bSel = true;

	switch (eng_id) {
	case AFIFO_0:
		offset = REG_TSP4_BASE + REG_0038_TSP4;
		load_bit = TSP4_REG_A_PKT_CNT_LOAD_01E8;
		break;
	case AFIFO_1:
		offset = REG_TSP4_BASE + REG_005C_TSP4;
		load_bit = TSP4_REG_AD_PKT_CNT_LOAD_01E8;
		break;
	case AFIFO_2:
		offset = REG_TSP4_BASE + REG_0064_TSP4;
		load_bit = TSP4_REG_ADC_PKT_CNT_LOAD_01E8;
		bSel = false;
		break;
	case AFIFO_3:
		offset = REG_TSP4_BASE + REG_0064_TSP4;
		load_bit = TSP4_REG_ADD_PKT_CNT_LOAD_01E8;
		break;
	default:
		return 0;
	}

	if (bSel)
		vIO32WriteFld(REG_TSP4_BASE + REG_01FC_TSP4, 1, TSP4_REG_AV_PKT_SRC_SEL_01FC);
	else
		vIO32WriteFld(REG_TSP4_BASE + REG_01FC_TSP4, 0, TSP4_REG_AV_PKT_SRC_SEL_01FC);

	vIO32WriteFld(REG_TSP4_BASE + REG_01E8_TSP4, 1, load_bit);

	return (u32)(u2IO32Read2B(offset));
}

u32 mtk_dmx_get_video_fifo_level(u16 eng_id)
{
	u32 fld;

	switch (eng_id) {
	case VFIFO_0:
		fld = TSP0_REG_VFIFO_STATUS_00DC_7_6;
		break;
	case VFIFO_1:
		fld = TSP0_REG_VFIFO_3D_STATUS_00DC_3_2;
		break;
	default:
		return 0;
	}

	return (u32)(u4IO32ReadFld(REG_TSP0_BASE + REG_00DC_TSP0, fld));
}

u32	mtk_dmx_get_video_fifo_empty_bit(u16 eng_id)
{
	u32 fld;

	switch (eng_id) {
	case VFIFO_0:
		fld = TSP0_REG_VFIFO_STATUS_00DC_4;
		break;
	case VFIFO_1:
		fld = TSP0_REG_VFIFO_3D_STATUS_00DC_0;
		break;
	default:
		return 0;
	}

	return (u32)(u4IO32ReadFld(REG_TSP0_BASE + REG_00DC_TSP0, fld));
}

u32	mtk_dmx_get_video_fifo_full_bit(u16 eng_id)
{
	u32 fld;

	switch (eng_id) {
	case VFIFO_0:
		fld = TSP0_REG_VFIFO_STATUS_00DC_5;
		break;
	case VFIFO_1:
		fld = TSP0_REG_VFIFO_3D_STATUS_00DC_1;
		break;
	default:
		return 0;
	}

	return (u32)(u4IO32ReadFld(REG_TSP0_BASE + REG_00DC_TSP0, fld));
}

u32 mtk_dmx_get_audio_fifo_level(u16 eng_id)
{
	REG16 __iomem *offset;
	u32 fld;

	switch (eng_id) {
	case AFIFO_0:
		offset = REG_TSP0_BASE + REG_00DC_TSP0;
		fld = TSP0_REG_AFIFO_STATUS_00DC_11_10;
		break;
	case AFIFO_1:
		offset = REG_TSP0_BASE + REG_00DC_TSP0;
		fld = TSP0_REG_AFIFOB_STATUS_00DC_15_14;
		break;
	case AFIFO_2:
		offset = REG_TSP1_BASE + REG_0180_TSP1;
		fld = TSP1_REG_AV_FIFO_ST3_0180_3_2;
		break;
	case AFIFO_3:
		offset = REG_TSP1_BASE + REG_0180_TSP1;
		fld = TSP1_REG_AV_FIFO_ST3_0180_7_6;
		break;
	default:
		return 0;
	}

	return (u32)(u4IO32ReadFld(offset, fld));
}

u32	mtk_dmx_get_audio_fifo_empty_bit(u16 eng_id)
{
	REG16 __iomem *offset;
	u32 fld;

	switch (eng_id) {
	case AFIFO_0:
		offset = REG_TSP0_BASE + REG_00DC_TSP0;
		fld = TSP0_REG_AFIFO_STATUS_00DC_8;
		break;
	case AFIFO_1:
		offset = REG_TSP0_BASE + REG_00DC_TSP0;
		fld = TSP0_REG_AFIFOB_STATUS_00DC_12;
		break;
	case AFIFO_2:
		offset = REG_TSP1_BASE + REG_0180_TSP1;
		fld = TSP1_REG_AV_FIFO_ST3_0180_0;
		break;
	case AFIFO_3:
		offset = REG_TSP1_BASE + REG_0180_TSP1;
		fld = TSP1_REG_AV_FIFO_ST3_0180_4;
		break;
	default:
		return 0;
	}

	return (u32)(u4IO32ReadFld(offset, fld));
}

u32	mtk_dmx_get_audio_fifo_full_bit(u16 eng_id)
{
	REG16 __iomem *offset;
	u32 fld;

	switch (eng_id) {
	case AFIFO_0:
		offset = REG_TSP0_BASE + REG_00DC_TSP0;
		fld = TSP0_REG_AFIFO_STATUS_00DC_9;
		break;
	case AFIFO_1:
		offset = REG_TSP0_BASE + REG_00DC_TSP0;
		fld = TSP0_REG_AFIFOB_STATUS_00DC_13;
		break;
	case AFIFO_2:
		offset = REG_TSP1_BASE + REG_0180_TSP1;
		fld = TSP1_REG_AV_FIFO_ST3_0180_1;
		break;
	case AFIFO_3:
		offset = REG_TSP1_BASE + REG_0180_TSP1;
		fld = TSP1_REG_AV_FIFO_ST3_0180_5;
		break;
	default:
		return 0;
	}

	return (u32)(u4IO32ReadFld(offset, fld));
}

void mtk_dmx_set_ntp_base_point(u32 base)
{
	RegWrite4B(REG_TLV0_BASE + REG_01C0_TSP_TLV,
		REG_TLV0_BASE + REG_01C8_TSP_TLV, base);
}

void mtk_dmx_set_leap_ind_eq_mode(u16 ind, bool add, bool sub)
{
	switch (ind) {
	case 1:
		vIO32WriteFld(REG_TLV0_BASE + REG_01D8_TSP_TLV, add?1:0,
			TSP_TLV_REG_LEAP_IND_EQ1_ADD_01D8);
		vIO32WriteFld(REG_TLV0_BASE + REG_01D8_TSP_TLV, sub?1:0,
			TSP_TLV_REG_LEAP_IND_EQ1_SUB_01D8);
		break;
	case 2:
		vIO32WriteFld(REG_TLV0_BASE + REG_01D8_TSP_TLV, add?1:0,
			TSP_TLV_REG_LEAP_IND_EQ2_ADD_01D8);
		vIO32WriteFld(REG_TLV0_BASE + REG_01D8_TSP_TLV, sub?1:0,
			TSP_TLV_REG_LEAP_IND_EQ2_SUB_01D8);
		break;
	default:
		break;
	}
}

void mtk_dmx_set_sec_dmaw_protect(u64 paddr, u32 size, u16 protect_num, bool bEnable)
{
	REG16 __iomem *lbnd_offset, *ubnd_offset;
	REG16 __iomem *offset;
	u32 lbnd, ubnd;

	switch (protect_num) {
	case DMAW1:
		lbnd_offset = REG_TSP1_BASE + REG_0060_TSP1;
		ubnd_offset = REG_TSP1_BASE + REG_0068_TSP1;
		break;
	case DMAW2:
		lbnd_offset = REG_TSP1_BASE + REG_00A8_TSP1;
		ubnd_offset = REG_TSP1_BASE + REG_00B0_TSP1;
		break;
	case DMAW3:
		lbnd_offset = REG_TSP1_BASE + REG_00B8_TSP1;
		ubnd_offset = REG_TSP1_BASE + REG_00C0_TSP1;
		break;
	case DMAW4:
		lbnd_offset = REG_TSP5_BASE + REG_01D8_TSP5;
		ubnd_offset = REG_TSP5_BASE + REG_01E0_TSP5;
		break;
	case DMAW5:
		lbnd_offset = REG_TSP5_BASE + REG_01E8_TSP5;
		ubnd_offset = REG_TSP5_BASE + REG_01F0_TSP5;
		break;
	default:
		return;
	}
	lbnd = (u32)(paddr >> MIU_BUS);
	ubnd = (u32)((paddr+size) >> MIU_BUS);
	RegWrite4B(lbnd_offset, lbnd_offset + REG_OFFSET, lbnd);
	RegWrite4B(ubnd_offset, ubnd_offset + REG_OFFSET, ubnd);

	offset = REG_TSP0_BASE + REG_0168_TSP0;
	vIO32WriteFld(offset, bEnable?1:0, TSP0_REG_SEC_DMAW_PROTECT_EN_0168);

	offset = REG_TSP1_BASE + REG_0070_TSP1;
	vIO32WriteFld(offset, 1, TSP1_REG_DMAW_WADDR_ERR_SRC_SEL_0070);

	//send_mcu_cmd(MCU_CMD_SET_LUBND_EN, &lbnd, &ubnd);
	//if ((lbnd != (u32)(paddr >> MIU_BUS)) && (ubnd != (u32)((paddr+size) >> MIU_BUS)))
	//	printk("%s %d update FW DMAW LUBND fail!!",__FUNCTION__, __LINE__);

}

// not verify
void mtk_dmx_set_pvr_dmaw_protect(u64 start_paddr, u64 end_paddr, u16 eng_id, bool bEnable)
{
	REG16 __iomem *lbnd_offset, *ubnd_offset;
	REG16 __iomem *en_offset;
	u32 fld;

	switch (eng_id) {
	case PVR_1:
		lbnd_offset = REG_TSP1_BASE + REG_0050_TSP1;
		ubnd_offset = REG_TSP1_BASE + REG_0058_TSP1;
		en_offset = REG_TSP0_BASE + REG_0168_TSP0;
		fld = TSP0_REG_PVR1_DMAW_PROTECT_EN_0168;
		break;
	case PVR_2:
		lbnd_offset = REG_TSP1_BASE + REG_00C8_TSP1;
		ubnd_offset = REG_TSP1_BASE + REG_00D0_TSP1;
		en_offset = REG_TSP0_BASE + REG_0168_TSP0;
		fld = TSP0_REG_PVR2_DMAW_PROTECT_EN_0168;
		break;
	case PVR_3:
		lbnd_offset = REG_TSP7_BASE + REG_0038_TSP7;
		ubnd_offset = REG_TSP7_BASE + REG_0040_TSP7;
		en_offset = REG_TSP7_BASE + REG_0034_TSP7;
		fld = TSP7_REG_PVR_DMAW_PROTECT_EN_0034;
		break;
	case PVR_4:
		lbnd_offset = REG_TSP7_BASE + REG_00B8_TSP7;
		ubnd_offset = REG_TSP7_BASE + REG_00C0_TSP7;
		en_offset = REG_TSP7_BASE + REG_00B4_TSP7;
		fld = TSP7_REG_PVR4_DMAW_PROTECT_EN_00B4;
		break;
	default:
		return;
	}

	RegWrite4B(lbnd_offset, lbnd_offset + REG_OFFSET, (u32)(start_paddr >> MIU_BUS));
	RegWrite4B(ubnd_offset, ubnd_offset + REG_OFFSET, (u32)(end_paddr >> MIU_BUS));

	vIO32WriteFld(en_offset, bEnable?1:0, fld);
}

void mtk_dmx_get_debug(u32 dbg_sel)
{
	u32 debug_msg;

	vIO32Write2B(REG_TSP0_BASE + REG_01F4_TSP0, dbg_sel);
	//usleep_range(10, 20);
	debug_msg = RegRead4B(REG_TSP0_BASE + REG_01A8_TSP0, REG_TSP0_BASE + REG_01AC_TSP0);
	MTK_DMX_INFO("debug_sel = 0x%x debug = 0x%x\n", dbg_sel, debug_msg);
}

void mtk_dmx_dump_debug(void)
{
#define DEBUG_SEL_START 0x570
#define DEBUG_SEL_END 0x5A0
#define SECFLT_NUM 192
	u16 filter_id;
	u32 u32pidL, u32pidH;
	int i = DEBUG_SEL_START;
	u64 readpa, start_pa, end_pa, write_pa, current_pa = 0;

	for (i = DEBUG_SEL_START ; i < DEBUG_SEL_END ; i++)
		mtk_dmx_get_debug(i);

	for (filter_id = 0 ; filter_id < SECFLT_NUM ; filter_id++) {
		u32pidL = indirect_read(PIDFLT_L_ADDR(filter_id));
		u32pidH = indirect_read(PIDFLT_H_ADDR(filter_id));
		MTK_DMX_INFO("pidH = 0x%x pidL = 0x%x\n", u32pidH, u32pidL);
		mtk_dmx_sec_filter_read_addr(filter_id, &readpa, false);
		mtk_dmx_sec_filter_start_addr(filter_id, &start_pa, false);
		mtk_dmx_sec_filter_end_addr(filter_id, &end_pa, false);
		mtk_dmx_sec_filter_write_addr(filter_id, &write_pa, false);
		mtk_dmx_sec_filter_current_addr(filter_id, &current_pa, false);
		MTK_DMX_INFO("sec_flt id %d: start 0x%llx read 0x%llx\n"
				, filter_id, start_pa, readpa);
		MTK_DMX_INFO("write 0x%llx current 0x%llx end 0x%llx\n"
				, write_pa, current_pa, end_pa);
	}
}

void mtk_dmx_set_sram(bool bSet)
{
#define SRAM_DBG_EN 0x0001
#define SRAM_DBG_START 0x0004
#define SRAM_DBG_RW 0x0008
#define SRAM_DBG_CLEAR 0x0000
#define SRAM_DEPTH 0xfff
	u16 u16addr;
	u32 u32SRAM_RData;
	REG16 __iomem *sram_ctrl, *dbg_addr, *dbg_wdata, *dbg_rdata;

	sram_ctrl = REG_TSP5_BASE + REG_01A4_TSP5;
	dbg_addr = REG_TSP5_BASE + REG_01A8_TSP5;
	dbg_wdata = REG_TSP5_BASE + REG_01AC_TSP5;
	dbg_rdata = REG_TSP5_BASE + REG_01B4_TSP5;
	reg16_mask_write(sram_ctrl, SRAM_DBG_EN, 1);
	for (u16addr = 0 ; u16addr < SRAM_DEPTH ; u16addr++) {
		vIO32Write2B(dbg_addr, u16addr);
		if (bSet) {
			reg16_mask_write(sram_ctrl, SRAM_DBG_RW, SRAM_DBG_RW);
			RegWrite4B(dbg_wdata, dbg_wdata+REG_OFFSET, 0x00000000);
			reg16_mask_write(sram_ctrl, SRAM_DBG_START, SRAM_DBG_START);
		} else {
			reg16_mask_write(sram_ctrl, SRAM_DBG_RW, SRAM_DBG_CLEAR);
			reg16_mask_write(sram_ctrl, SRAM_DBG_START, SRAM_DBG_START);
			u32SRAM_RData = RegRead4B(dbg_rdata, dbg_rdata+REG_OFFSET);
			MTK_DMX_INFO("0x%x u32SRAM_RData = 0x%x\n", u16addr, u32SRAM_RData);
		}
	}
	reg16_mask_write(sram_ctrl, SRAM_DBG_EN, SRAM_DBG_CLEAR);
}

