// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
/*
 * MediaTek	Inc. (C) 2020. All rights	reserved.
 */

//-------------------------------------------------------------------------------------------------
//  Include Files
//-------------------------------------------------------------------------------------------------
#include "halDMD_EXTERN_ISDBT.h"
#include <linux/vmalloc.h>
#define VMALLOC(x) vmalloc(x)
#define VFREE(x) vfree(x)

#if !defined MTK_PROJECT
#ifdef MSOS_TYPE_LINUX_KERNEL
#include <linux/kernel.h>
#include <linux/string.h>
#else
#include <math.h>
#include <stdio.h>
#endif
#endif

#if DMD_ISDBT_UTOPIA_EN || DMD_ISDBT_UTOPIA2_EN || DMD_ISDBT_3PARTY_MSPI_EN
//#include "../demod_spi/demod_spi.h"
#endif // #if DMD_ISDBT_UTOPIA_EN || DMD_ISDBT_UTOPIA2_EN || DMD_ISDBT_3PARTY_MSPI_EN

#if DMD_ISDBT_3PARTY_EN
// Please add header files needed by 3 party platform
#endif

#ifdef MSOS_TYPE_LINUX_KERNEL
#if DMD_ISDBT_UTOPIA_EN || DMD_ISDBT_UTOPIA2_EN
#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");
#endif
#endif

//-------------------------------------------------------------------------------------------------
//  Driver Compiler Options
//-------------------------------------------------------------------------------------------------

#if defined(_MSC_VER) || defined(__BORLANDC__)
#pragma comment(linker, "/alternatename:MDrv_DMD_ISDBT_Initial_Hal_Interface=_DEFAULT_CMD")
#endif

#ifndef BIN_RELEASE
#define BIN_RELEASE 0
#endif

#define DMD_ISDBT_CHIP_AMAZON 0x01
#define DMD_ISDBT_CHIP_BRASILIA 0x02
#define DMD_ISDBT_CHIP_YAMATO 0x03

#define yamato

#if defined(amazon)
#define DMD_ISDBT_CHIP_VERSION DMD_ISDBT_CHIP_AMAZON
#elif defined(brasilia)
#define DMD_ISDBT_CHIP_VERSION DMD_ISDBT_CHIP_BRASILIA
#elif defined(yamato)
#define DMD_ISDBT_CHIP_VERSION DMD_ISDBT_CHIP_YAMATO
#else
#define DMD_ISDBT_CHIP_VERSION DMD_ISDBT_CHIP_AMAZON
#endif

//-------------------------------------------------------------------------------------------------
//  Local Defines
//-------------------------------------------------------------------------------------------------

#define USE_DEFAULT_CHECK_TIME 1

#ifdef CONFIG_UTOPIA_PROC_DBG_SUPPORT
#define HAL_EXTERN_ISDBT_DBINFO(y) y
#else
#define HAL_EXTERN_ISDBT_DBINFO(y) y
#endif

#define SRAM_BASE 0x8000

#define FW_PRI_XDATA_BASE 0x4008

#if DMD_ISDBT_CHIP_VERSION == DMD_ISDBT_CHIP_YAMATO
#define REG_IIC_BYPASS 0x100910
#define REG_ALL_PAD_FL 0x100950
#define REG_ALL_PAD_IN 0x100951
#define REG_MCU_RST 0x100B32
#define REG_DMD_SEL 0x103C26
#define REG_I2C_MUX 0x103C28
#define WDT_REG_BASE 0x103000
#define MCU_REG_BASE 0x101000
#define TOP_REG_BASE 0x100900
#define DIG_REG_BASE 0x100B00
#define DMDANA_REG_BASE 0x100A00
#define REG_GPIO_EN 0x100951
#define REG_GPIO_LEVEL 0x1009CA
#define REG_GPIO_SET 0x1009C6
#define REG_GPIO_OUT 0x1009C8
#define REG_SSPI_EN 0x100976
#define REG_SSPI_MUX 0x100974
#define REG_PAD_MODE_SEL 0x100A33
#define REG_ADC_OUT_SEL 0x100A03
#else
#define REG_IIC_BYPASS 0x0910
#define REG_ALL_PAD_FL 0x0950
#define REG_ALL_PAD_IN 0x0951
#define REG_MCU_RST 0x0B32
#define REG_DMD_SEL 0x3C26
#define REG_I2C_MUX 0x3C28
#define WDT_REG_BASE 0x3000
#define MCU_REG_BASE 0x1000
#define TOP_REG_BASE 0x0900
#define DIG_REG_BASE 0x0B00
#define DMDANA_REG_BASE 0x0A00
#define REG_GPIO_EN 0x0951
#define REG_GPIO_LEVEL 0x09CA
#define REG_GPIO_SET 0x09C6
#define REG_GPIO_OUT 0x09C8
#define REG_SSPI_EN 0x0976
#define REG_SSPI_MUX 0x0974
#define REG_PAD_MODE_SEL 0x0A33
#define REG_ADC_OUT_SEL 0x0A03
#endif

#if DMD_ISDBT_CHIP_VERSION == DMD_ISDBT_CHIP_AMAZON
#define REG_ISDBT_LOCK_STATUS 0x2AF5
#define REG_ISDBT_LOCK_STATUS2 0x20C3
#define ISDBT_FE_REG_BASE 0x3E00
#define ISDBT_TDP_REG_BASE 0x0E00
#define ISDBT_FDP_REG_BASE 0x0F00
#define ISDBT_FDPEXT_REG_BASE 0x1400
#define ISDBT_OUTER_REG_BASE 0x1100
#define DEFAULT_ICFO_CHECK_TIME 300
#define DEFAULT_FEC_CHECK_TIME 2000
#elif DMD_ISDBT_CHIP_VERSION == DMD_ISDBT_CHIP_BRASILIA
#define REG_ISDBT_LOCK_STATUS 0x11F5
#define REG_ISDBT_LOCK_STATUS2 0x20C3
#define ISDBT_FE_REG_BASE 0x2800
#define ISDBT_TDP_REG_BASE 0x1400
#define ISDBT_FDP_REG_BASE 0x1500
#define ISDBT_FDPEXT_REG_BASE 0x1600
#define ISDBT_OUTER_REG_BASE 0x1700
#define DEFAULT_ICFO_CHECK_TIME 500
#define DEFAULT_FEC_CHECK_TIME 1500
#elif DMD_ISDBT_CHIP_VERSION == DMD_ISDBT_CHIP_YAMATO
#define REG_ISDBT_LOCK_STATUS 0x11F5
#define REG_ISDBT_LOCK_STATUS2 0x20C3
#define ISDBT_FE_REG_BASE 0x2800
#define ISDBT_TDP_REG_BASE 0x1400
#define ISDBT_FDP_REG_BASE 0x1500
#define ISDBT_FDPEXT_REG_BASE 0x1600
#define ISDBT_OUTER_REG_BASE 0x1700
#define DEFAULT_ICFO_CHECK_TIME 100
#define DEFAULT_FEC_CHECK_TIME 1500
#define CHIP_ID 0xEE
#else
#define REG_ISDBT_LOCK_STATUS 0x2AF5
#define REG_ISDBT_LOCK_STATUS2 0x20C3
#define ISDBT_FE_REG_BASE 0x3E00
#define ISDBT_TDP_REG_BASE 0x0E00
#define ISDBT_FDP_REG_BASE 0x0F00
#define ISDBT_FDPEXT_REG_BASE 0x1400
#define ISDBT_OUTER_REG_BASE 0x1100
#define DEFAULT_ICFO_CHECK_TIME 300
#define DEFAULT_FEC_CHECK_TIME 2000
#endif

#define LOAD_CODE_I2C_BLOCK_NUM 0x400

#define I2C_SLAVE_ID \
	((((MS_U16)(pRes->sdmd_isdbt_initdata.i2c_slave_bus & 0x3F)) << 8) | \
	pRes->sdmd_isdbt_initdata.i2c_slave_addr)

#define SPI_DEVICE_BUFFER_SIZE 256

#define BOOT_FROM_SRAM 0

// SSPI COMMAND
#define RIU_W_CMD 0x1A
#define RIU_W1_CMD 0x1D
#define RIU_R_CMD 0x18
#define RIU_R1_CMD 0x1C
#define RIU_RT_CMD 0x11
#define RIU_R1T_CMD 0x15
#define MIU_W_CMD 0x25
#define MIU_R_CMD 0x20
#define MIU_ST_CMD 0x21
#define CFG_W_CMD 0x05
#define CFG_R_CMD 0x00

#if (DMD_ISDBT_CHIP_VERSION >= DMD_ISDBT_CHIP_BRASILIA)
#define DMD_ISDBT_TBVA_EN 0 // 1
#define SOC_LIKE_EXT_DMD 1
#define USE_PSRAM_32KB 1
#define USE_T2_MERGED_FEND 1
#else
#define DMD_ISDBT_TBVA_EN 0
#define SOC_LIKE_EXT_DMD 0
#define USE_PSRAM_32KB 0
#define USE_T2_MERGED_FEND 0
#endif

#if (DMD_ISDBT_CHIP_VERSION == DMD_ISDBT_CHIP_YAMATO)
#define IS_MULTI_DMD 1
#define IS_MULTI_MCU 1
#else
#define IS_MULTI_DMD 0
#define IS_MULTI_MCU 0
#endif

#if DMD_ISDBT_CHIP_VERSION == DMD_ISDBT_CHIP_AMAZON
#define EXT_IOCTL_CMD HAL_EXTERN_ISDBT_IOCTL_CMD_0
#elif DMD_ISDBT_CHIP_VERSION == DMD_ISDBT_CHIP_BRASILIA
#define EXT_IOCTL_CMD HAL_EXTERN_ISDBT_IOCTL_CMD_1
#elif DMD_ISDBT_CHIP_VERSION == DMD_ISDBT_CHIP_YAMATO
#define EXT_IOCTL_CMD HAL_EXTERN_ISDBT_IOCTL_CMD_2
#else
#define EXT_IOCTL_CMD HAL_EXTERN_ISDBT_IOCTL_CMD_0
#endif

//-------------------------------------------------------------------------------------------------
//  Local Variables
//-------------------------------------------------------------------------------------------------

static MS_U8 id;
static MS_BOOL _HAL_EXTERN_ISDBT_SetSerialControl(void);
static struct dmd_isdbt_resdata *pRes;

static MS_U8 *pExtChipChNum;
static MS_U8 *pExtChipChId;
static MS_U8 *pExtChipI2cCh;

static struct dmd_isdbt_sys_ptr sys;

static const MS_U8 EXTERN_ISDBT_table[] = {
#include "DMD_EXTERN_ISDBT.dat"
};
static const MS_U8 EXTERN_ISDBT_8M_table[] = {
#include "DMD_EXTERN_ISDBT_8M.dat"
};

#ifndef UTPA2
static const float _LogApproxTableX[80] = { 1.00, 1.30, 1.69, 2.20, 2.86,
	3.71, 4.83, 6.27, 8.16, 10.60, 13.79, 17.92, 23.30, 30.29, 39.37,
	51.19, 66.54, 86.50, 112.46, 146.19, 190.05, 247.06, 321.18, 417.54,
	542.80, 705.64, 917.33, 1192.53, 1550.29, 2015.38, 2620.00, 3405.99,
	4427.79, 5756.13, 7482.97, 9727.86, 12646.22, 16440.08, 21372.11,
	27783.74, 36118.86, 46954.52, 61040.88, 79353.15, 103159.09, 134106.82,
	174338.86, 226640.52, 294632.68, 383022.48, 497929.22, 647307.99,
	841500.39, 1093950.50, 1422135.65, 1848776.35, 2403409.25, 3124432.03,
	4061761.64, 5280290.13, 6864377.17, 8923690.32, 11600797.42, 15081036.65,
	19605347.64, 25486951.94, 33133037.52, 43072948.77, 55994833.40, 72793283.42,
	94631268.45, 123020648.99, 159926843.68, 207904896.79, 270276365.82,
	351359275.57, 456767058.24, 593797175.72, 771936328.43, 1003517226.96 };

static const float _LogApproxTableY[80] = { 0.00, 0.11, 0.23, 0.34, 0.46, 0.57,
	0.68, 0.80, 0.91, 1.03, 1.14, 1.25, 1.37, 1.48, 1.60, 1.71, 1.82, 1.94,
	2.05, 2.16, 2.28, 2.39, 2.51, 2.62, 2.73, 2.85, 2.96, 3.08, 3.19, 3.30,
	3.42, 3.53, 3.65, 3.76, 3.87, 3.99, 4.10, 4.22, 4.33, 4.44, 4.56, 4.67,
	4.79, 4.90, 5.01, 5.13, 5.24, 5.36, 5.47, 5.58, 5.70, 5.81, 5.93, 6.04,
	6.15, 6.27, 6.38, 6.49, 6.60, 6.72, 6.83, 6.95, 7.06, 7.17, 7.29, 7.40,
	7.52, 7.63, 7.74, 7.86, 7.97, 8.08, 8.20, 8.31, 8.43, 8.54, 8.65, 8.77,
	8.88, 9.00 };
#else
static const MS_U32 _LogApproxTableX[58] = {
	1, 2, 3, 4, 6, 8, 10, 13, 17, 23, // 10
	30, 39, 51, 66, 86, 112, 146, 190, 247, 321, // 10
	417, 542, 705, 917, 1192, 1550, 2015, 2620, 3405, 4427, // 10
	5756, 7482, 9727, 12646, 16440, 21372, 27783, 36118, 46954, 61040, // 10
	79353, 103159, 134106, 174338, 226640, 294632, 383022, 497929, 647307, 841500, // 10
	1093950, 1422135, 1848776, 2403409, 3124432, 4061761, 5280290, 6160384 // 8
};

static const MS_U16 _LogApproxTableY[58] = { 0, 30, 47, 60, 77, 90, 100, 111, 123,
	136, 147, 159, 170, 181, 193, 204, 216, 227, 239, 250, 262, 273, 284, 296,
	307, 319, 330, 341, 353, 364, 376, 387, 398, 410, 421, 432, 444, 455, 467,
	478, 489, 501, 512, 524, 535, 546, 558, 569, 581, 592, 603, 615, 626, 638,
	649, 660, 672, 678 };
#endif

//-------------------------------------------------------------------------------------------------
//  Global Variables
//-------------------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------------------
//  Local Functions
//-------------------------------------------------------------------------------------------------
static MS_BOOL _HAL_EXTERN_ISDBT_Read_PKT_ERR(
		enum en_isdbt_layer eLayerIndex, MS_U16 *pu16PacketErr);

#ifndef UTPA2

#ifndef MSOS_TYPE_LINUX
static float Log10Approx(float flt_x)
{
	MS_U8 indx = 0;

	do {
		if (flt_x < _LogApproxTableX[indx])
			break;
		indx++;
	} while (indx < 79); // stop at indx = 80

	return _LogApproxTableY[indx];
}
#endif

static MS_U16 _CALCULATE_SQI(float fber)
{
	float flog_ber;
	MS_U16 u16SQI;

#ifdef MSOS_TYPE_LINUX
	flog_ber = (float)log10((double)fber);
#else
	if (fber != 0.0)
		flog_ber = (float)(-1.0 * Log10Approx((double)(1.0 / fber)));
	else
		flog_ber = -8.0; // when fber=0 means u16SQI=100
#endif

	// PRINT("dan fber = %f\n", fber);
	// PRINT("dan flog_ber = %f\n", flog_ber);
	// Part 2: transfer ber value to u16SQI value.
	if (flog_ber <= (-7.0))
		u16SQI = 100;
	else if (flog_ber < -6.0)
		u16SQI = (90 + (((-6.0) - flog_ber) / ((-6.0) - (-7.0)) * (100 - 90)));
	else if (flog_ber < -5.5)
		u16SQI = (80 + (((-5.5) - flog_ber) / ((-5.5) - (-6.0)) * (90 - 80)));
	else if (flog_ber < -5.0)
		u16SQI = (70 + (((-5.0) - flog_ber) / ((-5.0) - (-5.5)) * (80 - 70)));
	else if (flog_ber < -4.5)
		u16SQI = (60 + (((-4.5) - flog_ber) / ((-4.5) - (-5.0)) * (70 - 50)));
	else if (flog_ber < -4.0)
		u16SQI = (50 + (((-4.0) - flog_ber) / ((-4.0) - (-4.5)) * (60 - 50)));
	else if (flog_ber < -3.5)
		u16SQI = (40 + (((-3.5) - flog_ber) / ((-3.5) - (-4.0)) * (50 - 40)));
	else if (flog_ber < -3.0)
		u16SQI = (30 + (((-3.0) - flog_ber) / ((-3.0) - (-3.5)) * (40 - 30)));
	else if (flog_ber < -2.5)
		u16SQI = (20 + (((-2.5) - flog_ber) / ((-2.5) - (-3.0)) * (30 - 20)));
	else if (flog_ber < -2.0)
		u16SQI = (0 + (((-2.0) - flog_ber) / ((-2.0) - (-2.5)) * (20 - 0)));
	else
		u16SQI = 0;

	return u16SQI;
}

#else // #ifndef UTPA2

static MS_U16 Log10Approx(MS_U32 flt_x)
{
	MS_U8 indx = 0;

	do {
		if (flt_x < _LogApproxTableX[indx])
			break;
		indx++;
	} while (indx < 57); // stop at indx = 58

	return _LogApproxTableY[indx];
}

static MS_U16 _CALCULATE_SQI(MS_U32 BerValue, MS_U32 BerPeriod)
{
	MS_U16 u16SQI = 0;

	// BerPeriod = 188*8*128*32 = 6160384
	// Log10Approx(6160384) = 678

	if (BerValue == 0)
		u16SQI = 100;
	else if (BerValue * 1000000 < BerPeriod)
		u16SQI = ((9000 + (-600 + 678 - Log10Approx(BerValue)) * 10) / 100);
	else if (BerValue * 316228 < BerPeriod)
		u16SQI = ((8000 + (-550 + 678 - Log10Approx(BerValue)) * 20) / 100);
	else if (BerValue * 100000 < BerPeriod)
		u16SQI = ((7000 + (-500 + 678 - Log10Approx(BerValue)) * 20) / 100);
	else if (BerValue * 31623 < BerPeriod)
		u16SQI = ((6000 + (-450 + 678 - Log10Approx(BerValue)) * 20) / 100);
	else if (BerValue * 10000 < BerPeriod)
		u16SQI = ((5000 + (-400 + 678 - Log10Approx(BerValue)) * 20) / 100);
	else if (BerValue * 3162 < BerPeriod)
		u16SQI = ((4000 + (-350 + 678 - Log10Approx(BerValue)) * 20) / 100);
	else if (BerValue * 1000 < BerPeriod)
		u16SQI = ((3000 + (-300 + 678 - Log10Approx(BerValue)) * 20) / 100);
	else if (BerValue * 316 < BerPeriod)
		u16SQI = ((2000 + (-250 + 678 - Log10Approx(BerValue)) * 20) / 100);
	else if (BerValue * 100 < BerPeriod)
		u16SQI = ((0 + (-200 + 678 - Log10Approx(BerValue)) * 40) / 100);
	else
		u16SQI = 0;

	return u16SQI;
}

#endif // #ifndef UTPA2

static MS_BOOL _I2C_Channel_Set(MS_U8 ch_num)
{
	MS_BOOL bRet = TRUE;
	MS_U8 Data[5] = { 0x53, 0x45, 0x52, 0x44, 0x42 };

	// Exit
	Data[0] = 0x34;
	bRet &= pRes->sdmd_isdbt_initdata.i2c_writebytes(I2C_SLAVE_ID, 0, NULL, 1, Data);
	Data[0] = (ch_num & 0x01) ? 0x36 : 0x45;
	bRet &= pRes->sdmd_isdbt_initdata.i2c_writebytes(I2C_SLAVE_ID, 0, NULL, 1, Data);

	// Init
	Data[0] = 0x53;
	bRet &= pRes->sdmd_isdbt_initdata.i2c_writebytes(I2C_SLAVE_ID, 0, NULL, 5, Data);
	Data[0] = (ch_num & 0x04) ? 0x80 : 0x81;
	bRet &= pRes->sdmd_isdbt_initdata.i2c_writebytes(I2C_SLAVE_ID, 0, NULL, 1, Data);

	if ((ch_num == 4) || (ch_num == 5) || (ch_num == 1))
		Data[0] = 0x82;
	else
		Data[0] = 0x83;

	bRet &= pRes->sdmd_isdbt_initdata.i2c_writebytes(I2C_SLAVE_ID, 0, NULL, 1, Data);

	if ((ch_num == 4) || (ch_num == 5))
		Data[0] = 0x85;
	else
		Data[0] = 0x84;

	bRet &= pRes->sdmd_isdbt_initdata.i2c_writebytes(I2C_SLAVE_ID, 0, NULL, 1, Data);
	Data[0] = (ch_num & 0x01) ? 0x51 : 0x53;
	bRet &= pRes->sdmd_isdbt_initdata.i2c_writebytes(I2C_SLAVE_ID, 0, NULL, 1, Data);
	Data[0] = (ch_num & 0x01) ? 0x37 : 0x7F;
	bRet &= pRes->sdmd_isdbt_initdata.i2c_writebytes(I2C_SLAVE_ID, 0, NULL, 1, Data);
	Data[0] = 0x35;
	bRet &= pRes->sdmd_isdbt_initdata.i2c_writebytes(I2C_SLAVE_ID, 0, NULL, 1, Data);
	Data[0] = 0x71;
	bRet &= pRes->sdmd_isdbt_initdata.i2c_writebytes(I2C_SLAVE_ID, 0, NULL, 1, Data);

#if IS_MULTI_MCU
	*(pExtChipI2cCh) = ch_num;
#endif

	return bRet;
}

static MS_BOOL _I2C_Channel_Change(MS_U8 ch_num)
{
	MS_BOOL bRet = TRUE;
	MS_U8 Data[5] = { 0x53, 0x45, 0x52, 0x44, 0x42 };

	Data[0] = (ch_num & 0x01) ? 0x81 : 0x80;
	bRet &= pRes->sdmd_isdbt_initdata.i2c_writebytes(I2C_SLAVE_ID, 0, 0, 1, Data);
	Data[0] = (ch_num & 0x02) ? 0x83 : 0x82;
	bRet &= pRes->sdmd_isdbt_initdata.i2c_writebytes(I2C_SLAVE_ID, 0, 0, 1, Data);
	Data[0] = (ch_num & 0x04) ? 0x85 : 0x84;
	bRet &= pRes->sdmd_isdbt_initdata.i2c_writebytes(I2C_SLAVE_ID, 0, 0, 1, Data);

#if IS_MULTI_MCU
	*(pExtChipI2cCh) = ch_num;
#endif

	return bRet;
}

static MS_BOOL _I2C_READ_BYTE(MS_U32 u32Addr, MS_U8 *pu8Data)
{
#if IS_MULTI_MCU
	MS_U8 i2cCh = *(pExtChipI2cCh);
#endif

	MS_BOOL bRet = TRUE;
	MS_U8 u8MsbData[5] = { 0 };

	u8MsbData[0] = 0x10;
	u8MsbData[1] = 0x00;
	u8MsbData[2] = (u32Addr >> 16) & 0xff;
	u8MsbData[3] = (u32Addr >> 8) & 0xff;
	u8MsbData[4] = u32Addr & 0xff;

#if IS_MULTI_MCU
	if (i2cCh != 0) {
		if (i2cCh != 3 && u8MsbData[2] != 0x00)
			_I2C_Channel_Change(3); // For HK
		else if (i2cCh != 5 && u8MsbData[2] == 0x00)
			_I2C_Channel_Change(5); // For DMD

		if (*pExtChipI2cCh == 5)
			u8MsbData[2] = *(pExtChipChId) << 5;
	}
#endif

	u8MsbData[0] = 0x35;
	bRet &= pRes->sdmd_isdbt_initdata.i2c_writebytes(I2C_SLAVE_ID, 0, 0, 1, u8MsbData);

	u8MsbData[0] = 0x10;
	bRet &= pRes->sdmd_isdbt_initdata.i2c_writebytes(I2C_SLAVE_ID, 0, 0, 5, u8MsbData);
	bRet &= pRes->sdmd_isdbt_initdata.i2c_readbytes(I2C_SLAVE_ID, 0, 0, 1, pu8Data);

	u8MsbData[0] = 0x34;
	bRet &= pRes->sdmd_isdbt_initdata.i2c_writebytes(I2C_SLAVE_ID, 0, 0, 1, u8MsbData);

	return bRet;
}

static MS_BOOL _I2C_WRITE_BYTE(MS_U32 u32Addr, MS_U8 u8Data)
{
#if IS_MULTI_MCU
	MS_U8 i2cCh = *(pExtChipI2cCh);
#endif

	MS_BOOL bRet = TRUE;
	MS_U8 u8MsbData[6] = { 0 };

	u8MsbData[0] = 0x10;
	u8MsbData[1] = 0x00;
	u8MsbData[2] = (u32Addr >> 16) & 0xff;
	u8MsbData[3] = (u32Addr >> 8) & 0xff;
	u8MsbData[4] = u32Addr & 0xff;
	u8MsbData[5] = u8Data;

#if IS_MULTI_MCU
	if (i2cCh != 0) {
		if (i2cCh != 3 && u8MsbData[2] != 0x00)
			_I2C_Channel_Change(3); // For HK
		else if (i2cCh != 5 && u8MsbData[2] == 0x00)
			_I2C_Channel_Change(5); // For DMD

		if (*pExtChipI2cCh == 5)
			u8MsbData[2] = *(pExtChipChId) << 5;
	}
#endif

	u8MsbData[0] = 0x35;
	bRet &= pRes->sdmd_isdbt_initdata.i2c_writebytes(I2C_SLAVE_ID, 0, 0, 1, u8MsbData);
	u8MsbData[0] = 0x10;
	bRet &= pRes->sdmd_isdbt_initdata.i2c_writebytes(I2C_SLAVE_ID, 0, 0, 6, u8MsbData);
	u8MsbData[0] = 0x34;
	bRet &= pRes->sdmd_isdbt_initdata.i2c_writebytes(I2C_SLAVE_ID, 0, 0, 1, u8MsbData);

	return bRet;
}

static MS_BOOL _I2C_WRITE_BYTES(MS_U16 u16Addr, MS_U8 *u8Data, MS_U16 u16Len)
{
#if IS_MULTI_MCU
	MS_U8 i2cCh = *(pExtChipI2cCh);
#endif

	MS_BOOL bRet = TRUE;
	MS_U16 index;
	MS_U8 *Data = VMALLOC(sizeof(MS_U8) * (LOAD_CODE_I2C_BLOCK_NUM + 5));

	if (Data == NULL)
		return FALSE;

	Data[0] = 0x10;
	Data[1] = 0x00;
	Data[2] = 0x00;
	Data[3] = (u16Addr >> 8) & 0xff;
	Data[4] = u16Addr & 0xff;

#if IS_MULTI_DMD
	if (i2cCh != 0) {
		if (i2cCh != 3 && Data[2] != 0x00)
			_I2C_Channel_Change(3); // For HK
		else if (i2cCh != 5 && Data[2] == 0x00)
			_I2C_Channel_Change(5); // For DMD

		if (*pExtChipI2cCh == 5)
			Data[2] = *(pExtChipChId) << 5;
	}
#endif

	for (index = 0; index < u16Len; index++)
		Data[5 + index] = u8Data[index];

	Data[0] = 0x35;
	bRet &= pRes->sdmd_isdbt_initdata.i2c_writebytes(I2C_SLAVE_ID, 0, 0, 1, Data);
	Data[0] = 0x10;
	bRet &= pRes->sdmd_isdbt_initdata.i2c_writebytes(I2C_SLAVE_ID, 0, 0, (5 + u16Len), Data);
	Data[0] = 0x34;
	bRet &= pRes->sdmd_isdbt_initdata.i2c_writebytes(I2C_SLAVE_ID, 0, 0, 1, Data);

	VFREE(Data);

	return bRet;
}

static MS_BOOL _WRITE_MBX(MS_U16 u16Addr, MS_U8 u8Data)
{
	MS_BOOL bResult = TRUE;
	MS_U8 u8ReadData, u8Cnt;

	// Reg
	bResult &= _I2C_WRITE_BYTE(0x0B02, (MS_U8)u16Addr);
	// Reg
	bResult &= _I2C_WRITE_BYTE(0x0B03, (MS_U8)(u16Addr >> 8));
	// Write data length
	bResult &= _I2C_WRITE_BYTE(0x0B01, 0x01);
	// Write data
	bResult &= _I2C_WRITE_BYTE(0x0B50, u8Data);
	// Trigger write operation
	bResult &= _I2C_WRITE_BYTE(0x0B00, 0x01);

	u8ReadData = 0x00;
	u8Cnt = 0;
	while ((_I2C_READ_BYTE(0x0B00, &u8ReadData) == TRUE) && ((u8ReadData & 0x01) == 0x01)) {
		if (u8Cnt > 100) {
			pr_info("[%s][%d] *pExtChipChId = %d, MBX WRITE TIME OUT\n",
				__func__, __LINE__, *pExtChipChId);
			return FALSE;
		}
		u8Cnt++;

		sys.delayms(1);
	}

	return bResult;
}

static MS_BOOL _READ_MBX(MS_U16 u16Addr, MS_U8 *pu8Data)
{
	MS_BOOL bResult = TRUE;
	MS_U8 u8ReadData = 0;
	MS_U8 u8Cnt = 0;

	// Reg
	bResult &= _I2C_WRITE_BYTE(0x0B02, (MS_U8)u16Addr);
	// Reg
	bResult &= _I2C_WRITE_BYTE(0x0B03, (MS_U8)(u16Addr >> 8));
	// Read data length
	bResult &= _I2C_WRITE_BYTE(0x0B01, 0x01);
	// Trigger read operation
	bResult &= _I2C_WRITE_BYTE(0x0B00, 0x02);

	u8ReadData = 0x00;
	u8Cnt = 0;
	while ((_I2C_READ_BYTE(0x0B00, &u8ReadData) == TRUE) && ((u8ReadData & 0x02) == 0x02)) {
		if (u8Cnt > 100) {
			pr_info("[%s][%d] *pExtChipChId = %d, MBX READ TIME OUT\n",
				__func__, __LINE__, *pExtChipChId);
			return FALSE;
		}
		u8Cnt++;

		sys.delayms(1);
	}

	bResult &= _I2C_READ_BYTE(0x0B50, pu8Data); // Read data

	return bResult;
}

static void _HAL_EXTERN_ISDBT_InitClk(void)
{
	MS_U8 dmd_id = (id & 0x0F);
	MS_U8 chip_id = (id >> 4);
	MS_U8 data;
#if !defined(MSOS_TYPE_LINUX_KERNEL) && (DMD_ISDBT_UTOPIA_EN || DMD_ISDBT_UTOPIA2_EN)
	MS_U8 i;
	dmd_isdbt_ioctl_data ioData;
#endif

#if USE_DEFAULT_CHECK_TIME
	pRes->sdmd_isdbt_initdata.isdbt_fec_lock_check_time = DEFAULT_FEC_CHECK_TIME;
	pRes->sdmd_isdbt_initdata.isdbt_icfo_ch_exist_check_time = DEFAULT_ICFO_CHECK_TIME;
#endif

	_I2C_READ_BYTE(TOP_REG_BASE, &data);
	pr_info("[%s][%d] *pExtChipChId = %d, data = 0x%X\n",
		__func__, __LINE__, *pExtChipChId, data);

	if (data == 0xDA)
		*(pExtChipChNum) = 2;
	else
		*(pExtChipChNum) = 1;

	while (chip_id)
		dmd_id -= *(pExtChipChNum - (chip_id--));

	*(pExtChipChId) = dmd_id;
}

#if DMD_ISDBT_UTOPIA_EN || DMD_ISDBT_UTOPIA2_EN || DMD_ISDBT_3PARTY_MSPI_EN
static MS_BOOL _SSPI_CFG_READNonPM(MS_U8 u8Offset)
{
	return TRUE;
}

static MS_BOOL _SSPI_Init(MS_U8 u8DeviceNum)
{
	return TRUE;
}

static MS_BOOL _SSPI_MIU_Writes(MS_U32 u32Addr, MS_U8 *pdata, MS_U16 u16Size)
{
	//return DEMOD_SPI_WRITE_BYTES(u32Addr, pdata, u16Size, SPI_SPEED_LOW);
	return TRUE;
}

static MS_BOOL _SSPI_MIU_Reads(MS_U32 u32Addr, MS_U8 *pdata, MS_U16 u16Size)
{
	return TRUE;
}

static MS_BOOL _SSPI_RIU_Write8(MS_U32 u32Addr, MS_U8 data)
{
	//return DEMOD_SPI_WRITE_BYTE(u32Addr, data, SPI_SPEED_LOW);
	return TRUE;
}

static MS_BOOL _SSPI_RIU_Read8(MS_U32 u32Addr, MS_U8 *pdata)
{
	//return DEMOD_SPI_READ_BYTE(u32Addr, pdata, SPI_SPEED_LOW);
	return TRUE;
}
#endif // #if DMD_ISDBT_UTOPIA_EN || DMD_ISDBT_UTOPIA2_EN || DMD_ISDBT_3PARTY_MSPI_EN

#if IS_MULTI_DMD
static MS_BOOL _SEL_DMD(void)
{
	MS_BOOL bRet = TRUE;

	bRet &= _I2C_Channel_Change(3);
	bRet &= _I2C_WRITE_BYTE(REG_DMD_SEL, *(pExtChipChId));
	return bRet;
}
#endif

#if DMD_ISDBT_UTOPIA_EN || DMD_ISDBT_UTOPIA2_EN || DMD_ISDBT_3PARTY_MSPI_EN
static MS_BOOL _MPLL_INIT(MS_BOOL (*fpReadReg)(MS_U32 u32Addr, MS_U8 *pu8Data),
		MS_BOOL (*fpWriteReg)(MS_U32 u32Addr, MS_U8 pu8Data))
{
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data = 0;

	pr_info("[%s][%d] *pExtChipChId = %d,__entry__\n",
		__func__, __LINE__);

	bRet &= fpReadReg(0x100900 + 0x09 * 2 + 0, &u8Data);
	if (u8Data != 0x33) {
		// MPLL not init yet

		// ================================================================
		//  Initialize DMD_ANA_MISC
		// ================================================================

		// [0]	 : reg_tst_ldo25i"
		// [1]	 : reg_tst_ldo25q"
		// [5:4] : reg_tst_ldo25i_selfb
		// [7:6] : reg_tst_ldo25q_selfb
		// [8]	 : reg_pd_dm2p5ldoi = 1'b0"
		// [9]	 : reg_pd_dm2p5ldoq = 1'b0"
		// `RIU_W((`RIUBASE_ADCPLL>>1)+7'h4f, 2'b11, 16'h0000);
		// `RIU_W((`RIUBASE_ADCPLL>>1)+7'h4f, 2'b11, 16'h0000);
		bRet &= fpWriteReg(0x100A00 + 0x4F * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100A00 + 0x4F * 2 + 1, 0x00);
		// wriu 0x100a9f 0x00
		// wriu 0x100a9e 0x00

		// [0]	    : reg_tst_ldo11_clk"
		// [1]	    : reg_tst_ldo26"
		// [2]	    : reg_tst_ldo11_cmp"
		// [3]	    : reg_pd_dm1p1ldo_clk = 1'b0"
		// [4]	    : reg_pd_dm1p1ldo_cmp = 1'b0"
		// [6:5]    : reg_tst_ldo26_selfb
		// [7]	    : reg_pd_dm2p6ldo = 1'b0"
		// [9:8]    : reg_tst_ldo11_cmp_selfb
		// [11:10]  : reg_tst_ldo11_clk_selfb
		// `RIU_W((`RIUBASE_ADCPLL>>1)+7'h4e, 2'b11, 16'h0000);
		// `RIU_W((`RIUBASE_ADCPLL>>1)+7'h4e, 2'b11, 16'h0000);
		bRet &= fpWriteReg(0x100A00 + 0x4E * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100A00 + 0x4E * 2 + 1, 0x00);
		// wriu 0x100a9d 0x00
		// wriu 0x100a9c 0x00

		// [0]   : reg_ana_setting_enable
		// [6:4] : reg_ana_setting_sel
		// `RIU_W((`RIUBASE_ADCPLL>>1)+7'h51, 2'b11, 16'h0041);
		// `RIU_W((`RIUBASE_ADCPLL>>1)+7'h51, 2'b11, 16'h0041);
		bRet &= fpWriteReg(0x100A00 + 0x51 * 2 + 0, 0x41);
		bRet &= fpWriteReg(0x100A00 + 0x51 * 2 + 1, 0x00);
		// wriu 0x100aa3 0x00
		// wriu 0x100aa2 0x41

		// ISDBT : 24*36/12=72 MHz
		// Set MPLL_LOOP_DIV_FIRST and SECOND
		// [1:0] : reg_mpll_loop_div_first : feedback divider
		//         00:div by 1
		//         01:div by 2
		//         10:div by 4
		//         11:div by 8
		// [15:8]: reg_mpll_loop_div_second : feedback divider, div by binary data number
		// `RIU_W((`RIUBASE_ADCPLL>>1)+7'h33, 2'b11, 16'h1201);
		// `RIU_W((`RIUBASE_ADCPLL>>1)+7'h33, 2'b11, 16'h1201);
		bRet &= fpWriteReg(0x100A00 + 0x33 * 2 + 0, 0x01);
		bRet &= fpWriteReg(0x100A00 + 0x33 * 2 + 1, 0x12);
		// wriu 0x100a67 0x12
		// wriu 0x100a66 0x01

		// [2:0] : reg_mpll_ictrl   set 3'h3	charge pump current control"
		// [3]   : reg_mpll_in_sel  set 1'h0	1.8V or 3.3V reference clock domain select
		// (1'b0=0==>3.3 V reference clock domain)"
		// [4]   : reg_mpll_xtal2adc_sel select the XTAL clock bypass to MPLL_ADC_CLK"
		// [5]   : reg_mpll_xtal2next_pll_sel	crystal clock bypass to next PLL select"
		// [6]   : reg_mpll_vco_offset		set VCO initial offset frequency"
		// [7]   : reg_mpll_pd gated reference clock and power down PLL analog_3v: 1=power
		// down"
		// [10:9]: reg_xtal_sel			XTAL driven strength select"
		// [11]  : reg_mpll_porst set 1'b1 MPLL input power on reset, connect to reg as
		// MPLL_RESET"
		// [12]  : reg_mpll_reset   set 1'b1	PLL software reset; 1:reset"
		// [13]  : reg_pd_dmpll_clk		XTAL to MPLL clock reference power down"
		// [14]  : reg_pd_3p3_1  set 1'b0	XTAL to CLK_24M_3P3_1 power down"
		// [15]  : reg_pd_3p3_2  set 1'b0	XTAL to CLK_24M_3P3_2 power down"
		// `RIU_W((`RIUBASE_ADCPLL>>1)+7'h35, 2'b11, 16'h1803);
		// `RIU_W((`RIUBASE_ADCPLL>>1)+7'h35, 2'b11, 16'h1803);
		bRet &= fpWriteReg(0x100A00 + 0x35 * 2 + 0, 0x03);
		bRet &= fpWriteReg(0x100A00 + 0x35 * 2 + 1, 0x18);
		// wriu 0x100a6b 0x18
		// wriu 0x100a6a 0x03
		// #20;
		// wait 0
		// `RIU_W((`RIUBASE_ADCPLL>>1)+7'h35, 2'b11, 16'h0003);
		// `RIU_W((`RIUBASE_ADCPLL>>1)+7'h35, 2'b11, 16'h0003);
		bRet &= fpWriteReg(0x100A00 + 0x35 * 2 + 0, 0x03);
		bRet &= fpWriteReg(0x100A00 + 0x35 * 2 + 1, 0x00);
		// wriu 0x100a6b 0x00
		// wriu 0x100a6a 0x03

		// Set MPLL_ADC_DIV_SEL: divide ADC clock to 24Mhz(24*36/12M)
		// [0]   : reg_mpll_clk_dp_pd	(no use)"
		// [1]   : reg_adc_clk_pd
		// [2]   : reg_mpll_div2_pd
		// [3]   : reg_mpll_div3_pd
		// [4]   : reg_mpll_div4_pd
		// [5]   : reg_mpll_div8_pd
		// [6]   : reg_mpll_div10_pd
		// [13:8]: reg_mpll_adc_div_sel set 6'd36	"
		// `RIU_W((`RIUBASE_ADCPLL>>1)+7'h30, 2'b11, 16'h0c00);
		// `RIU_W((`RIUBASE_ADCPLL>>1)+7'h30, 2'b11, 16'h0c00);
		bRet &= fpWriteReg(0x100A00 + 0x30 * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100A00 + 0x30 * 2 + 1, 0x0C);
		// wriu 0x100a61 0x0c
		// wriu 0x100a60 0x00

		// =================================================================
		//  Start demod atop ADC setting (1ADC)
		// =================================================================

		// Set IMUXS QMUXS
		// I channel input mux control:
		// [0]   : reg_adc_pwdni  => I channel ADC power down (no use)
		// [1]   : reg_adc_pwdnq  => Q channel ADC power down (no use)
		// [2]   : reg_imux_clpz  => I channel clamp enable. 0:enable, 1:disable
		// [3]   : reg_qmux_clpz  => Q channel clamp enable. 0:enable, 1:disable
		// I channel input mux control:
		// [6:4] : reg_imuxs
		//         3'b000 : I channel ADC calibration mode input
		//         3'b001 : VIF signal from VIFPGA
		//         3'b100 : DVB or ATSC mode input from PAD_I(Q)P(M)
		// Q channel input mux control:
		// [10:8]: reg_qmuxs
		//         3'b000 : Q channel ADC calibration mode input
		//         3'b001 : VIF signal from VIFPGA
		//         3'b010 : SSIF signal from PAD_SIFP(M)
		//         3'b100 : DVB or ATSC mode input from PAD_I(Q)P(M)
		// [12]  : reg_iq_swap     0
		// [13]  : reg_iqclk_sel   0: ADC_CLK
		// [14]  : reg_lincal_bypass
		// [15]  : reg_power_sel
		// `RIU_W((`RIUBASE_ADCPLL>>1)+7'h01, 2'b11, 16'h0440);
		// `RIU_W((`RIUBASE_ADCPLL>>1)+7'h01, 2'b11, 16'h0440);
		bRet &= fpWriteReg(0x100A00 + 0x01 * 2 + 0, 0x40);
		bRet &= fpWriteReg(0x100A00 + 0x01 * 2 + 1, 0x04);
		// wriu 0x100a03 0x04
		// wriu 0x100a02 0x40

		// Set enable ADC clock
		// [0]  : reg_pwdn_adci(1:power down) set 1'b0
		// [1]  : reg_pwdn_adcq(1:power down) set 1'b0
		// [2]  : reg_pwdn_clpbuf             set 1'b0
		// [3]  : reg_adc_refv_s
		// [6:4]: reg_adc_bias_ctrl
		// [9:8]: reg_amp_gain
		// `RIU_W((`RIUBASE_ADCPLL>>1)+7'h0c, 2'b11, 16'h0000);
		// `RIU_W((`RIUBASE_ADCPLL>>1)+7'h0c, 2'b11, 16'h0000);
		bRet &= fpWriteReg(0x100A00 + 0x0C * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100A00 + 0x0C * 2 + 1, 0x00);
		// wriu 0x100a19 0x00
		// wriu 0x100a18 0x00

		// =================================================================
		//  Turn RFAGC/IFAGC
		// =================================================================
		// checked by scott
		// [0]	: reg_ifagc_t_enable	    // for others"
		// [1]	: reg_ifagc_t_odmode"
		// [2]	: reg_ifagc_t_data_sel"
		// [4]	: reg_ifagc_t_force_enable"
		// [5]	: reg_ifagc_t_force_value"
		// [8]	: reg_ifagc_s_enable	    // for S/S2 only"
		// [9]	: reg_ifagc_s_odmode"
		// [10]	: reg_ifagc_s_data_sel"
		// [12]	: reg_ifagc_s_force_enable"
		// [13]	: reg_ifagc_s_force_value"
		// `RIU_W((`RIUBASE_ADCPLL>>1)+7'h18, 2'b01, 16'h0100);
		// `RIU_W((`RIUBASE_ADCPLL>>1)+7'h18, 2'b01, 16'h0100);
		// wriu 0x100a30 0x00

		// ==============================================================
		// Start TOP CLKGEN initial setting ......
		// ==============================================================
		// [0]	    : reg_xtal_en"
		// [1]	    : reg_xtal_en_slave"
		// [4]	    : reg_dmpll_en_0"
		// [5]	    : reg_dmpll_en_1"
		// [8]	    : reg_clk_pd_iic"
		// [10]	    : reg_clk_pd_all"
		// `RIU_W((`RIUBASE_TOP>>1)+7'h09, 2'b11, 16'h0133);
		// `RIU_W((`RIUBASE_TOP>>1)+7'h09, 2'b11, 16'h0133);
		bRet &= fpWriteReg(0x100900 + 0x09 * 2 + 0, 0x33);
		bRet &= fpWriteReg(0x100900 + 0x09 * 2 + 1, 0x01);
		// wriu 0x100913 0x01
		// wriu 0x100912 0x33

		// [3:0]    : reg_ckg_adcd
		// [7:4]    : reg_ckg_sadc  (no use)
		// [11:8]   : reg_ckg_iicm
		// [13:12]  : reg_ckg_sbus
		// `RIU_W((`RIUBASE_TOP>>1)+7'h0a, 2'b11, 16'h0010);
		// `RIU_W((`RIUBASE_TOP>>1)+7'h0a, 2'b11, 16'h0010);
		bRet &= fpWriteReg(0x100900 + 0x0A * 2 + 0, 0x10);
		bRet &= fpWriteReg(0x100900 + 0x0A * 2 + 1, 0x00);
		// wriu 0x100915 0x00
		// wriu 0x100914 0x10

		// [5:0]	reg_ckg_mcu"
		// [0]  : disable clock
		// [1]  : invert clock
		// [4:2]:
		//        000:108MHz
		//        001:86MHz
		//        010:72MHz
		//        011:54MHz
		//        100:172.8MHz
		//        101:48MHz
		//        110:24MHz
		//        111:12MHz
		// [6]	reg_power_good_mask"
		// [11:8]	reg_ckg_inner"
		// `RIU_W((`RIUBASE_TOP>>1)+7'h0b, 2'b11, 16'h0000);
		// `RIU_W((`RIUBASE_TOP>>1)+7'h0b, 2'b11, 16'h0000);
		bRet &= fpWriteReg(0x100900 + 0x0B * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100900 + 0x0B * 2 + 1, 0x00);
		// wriu 0x100917 0x00
		// wriu 0x100916 0x00

		// [3:0]    : reg_ckg_dvbtm_adc
		// `RIU_W((`RIUBASE_TOP>>1)+7'h10, 2'b11, 16'h0000);
		// `RIU_W((`RIUBASE_TOP>>1)+7'h10, 2'b11, 16'h0000);
		bRet &= fpWriteReg(0x100900 + 0x10 * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100900 + 0x10 * 2 + 1, 0x00);
		// wriu 0x100921 0x00
		// wriu 0x100920 0x00

		// [1:0]    : reg_ckg_miu_demod
		// [15:8]   : reg_ckg_miu
		// `RIU_W((`RIUBASE_TOP>>1)+7'h19, 2'b10, 16'h0000);
		// `RIU_W((`RIUBASE_TOP>>1)+7'h19, 2'b10, 16'h0000);
		bRet &= fpWriteReg(0x100900 + 0x19 * 2 + 1, 0x00);
		// wriu 0x100933 0x00

		// [10:8]   : reg_ckg_syn_miu
		// [14:12]  : reg_ckg_syn_ts
		// `RIU_W((`RIUBASE_TOP>>1)+7'h1b, 2'b10, 16'h0000);
		// `RIU_W((`RIUBASE_TOP>>1)+7'h1b, 2'b10, 16'h0000);
		bRet &= fpWriteReg(0x100900 + 0x1B * 2 + 1, 0x00);
		// wriu 0x100937 0x00

		// [4:0]    : reg_ckg_bist
		// [11:8]   : reg_ckg_adcd_d2
		// `RIU_W((`RIUBASE_TOP>>1)+7'h1c, 2'b11, 16'h0000);
		// `RIU_W((`RIUBASE_TOP>>1)+7'h1c, 2'b11, 16'h0000);
		bRet &= fpWriteReg(0x100900 + 0x1C * 2 + 1, 0x00);
		bRet &= fpWriteReg(0x100900 + 0x1C * 2 + 1, 0x00);
		// wriu 0x100939 0x00
		// wriu 0x100938 0x00

		// [3:0]    : reg_ckg_dmdmcu
		// [7:4]    : reg_ckg_dmdxtali
		// [11:8]   : reg_ckg_live
		// `RIU_W((`RIUBASE_TOP>>1)+7'h1d, 2'b11, 16'h0000);
		// `RIU_W((`RIUBASE_TOP>>1)+7'h1d, 2'b11, 16'h0000);
		bRet &= fpWriteReg(0x100900 + 0x1D * 2 + 1, 0x00);
		bRet &= fpWriteReg(0x100900 + 0x1D * 2 + 1, 0x00);
		// wriu 0x10093b 0x00
		// wriu 0x10093a 0x00
	}

	return bRet;
}
#endif

static MS_BOOL _DDR_PLL_INIT(MS_BOOL (*fpReadReg)(MS_U32 u32Addr, MS_U8 *pu8Data),
		MS_BOOL (*fpWriteReg)(MS_U32 u32Addr, MS_U8 pu8Data))
{
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data = 0;

	pr_info("[%s][%d] *pExtChipChId = %d, __entry__\n",
			__func__, __LINE__);

	bRet &= fpReadReg(0x100E00 + 0x18 * 2 + 0, &u8Data);
	if (u8Data != 0xBA) {
		// DDRPLL not init yet

		//--------------------
		// set DDRPLL0 200MHZ
		//--------------------
		// wriu -w	0x100e1a  0x0400
		bRet &= fpWriteReg(0x100E00 + 0x0D * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100E00 + 0x0D * 2 + 1, 0x04);
		// wriu -w	0x100e36  0x4009 //update 8/6
		bRet &= fpWriteReg(0x100E00 + 0x1B * 2 + 0, 0x09);
		bRet &= fpWriteReg(0x100E00 + 0x1B * 2 + 1, 0x40);
		// wriu -w	0x100e34  0x0000
		bRet &= fpWriteReg(0x100E00 + 0x1A * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100E00 + 0x1A * 2 + 1, 0x00);
		// wriu -w	0x100e30  0xE8BA //DDRPLL  =  2133 MHZ - 1%
		bRet &= fpWriteReg(0x100E00 + 0x18 * 2 + 0, 0xBA);
		bRet &= fpWriteReg(0x100E00 + 0x18 * 2 + 1, 0xE8);
		// wriu -w	0x100e32  0x0022 //DDRPLL  =  2133 MHZ - 1%
		bRet &= fpWriteReg(0x100E00 + 0x19 * 2 + 0, 0x22);
		bRet &= fpWriteReg(0x100E00 + 0x19 * 2 + 1, 0x00);
		// wriu -w	0x100e22  0x2000
		bRet &= fpWriteReg(0x100E00 + 0x11 * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100E00 + 0x11 * 2 + 1, 0x20);
		// wriu -w	0x100e24  0x2000
		bRet &= fpWriteReg(0x100E00 + 0x12 * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100E00 + 0x12 * 2 + 1, 0x20);
		// wriu -w	0x100e24  0x3000
		bRet &= fpWriteReg(0x100E00 + 0x12 * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100E00 + 0x12 * 2 + 1, 0x30);
		// wriu -w	0x100e24  0x2000
		bRet &= fpWriteReg(0x100E00 + 0x12 * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100E00 + 0x12 * 2 + 1, 0x20);
		// wait 1
		sys.delayms(1);
		// wriu -w	0x100e1a  0x0000
		bRet &= fpWriteReg(0x100E00 + 0x0D * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100E00 + 0x0D * 2 + 1, 0x00);

		//------------------
		// Wait PLL Stable
		//------------------
		// wait 10
		sys.delayms(10);
		// wriu -w	0x100d02  0x0010
		bRet &= fpWriteReg(0x100D00 + 0x01 * 2 + 0, 0x10);
		bRet &= fpWriteReg(0x100D00 + 0x01 * 2 + 1, 0x00);
		// wriu -w	0x100d04  0x01c8 //rd_timing
		bRet &= fpWriteReg(0x100D00 + 0x02 * 2 + 0, 0xC8);
		bRet &= fpWriteReg(0x100D00 + 0x02 * 2 + 1, 0x01);
		// wriu -w	0x100d06  0x0130 //tREF
		bRet &= fpWriteReg(0x100D00 + 0x03 * 2 + 0, 0x30);
		bRet &= fpWriteReg(0x100D00 + 0x03 * 2 + 1, 0x01);
		// wriu -w	0x100d08  0x0833
		bRet &= fpWriteReg(0x100D00 + 0x04 * 2 + 0, 0x33);
		bRet &= fpWriteReg(0x100D00 + 0x04 * 2 + 1, 0x08);
		// wriu -w	0x100d0a  0x0b42
		bRet &= fpWriteReg(0x100D00 + 0x05 * 2 + 0, 0x42);
		bRet &= fpWriteReg(0x100D00 + 0x05 * 2 + 1, 0x0B);
		// wriu -w	0x100d0c  0x5230
		bRet &= fpWriteReg(0x100D00 + 0x06 * 2 + 0, 0x30);
		bRet &= fpWriteReg(0x100D00 + 0x06 * 2 + 1, 0x52);
		// wriu -w	0x100d0e  0x100b
		bRet &= fpWriteReg(0x100D00 + 0x07 * 2 + 0, 0x0B);
		bRet &= fpWriteReg(0x100D00 + 0x07 * 2 + 1, 0x10);
		// wriu -w	0x100d10  0x0031
		bRet &= fpWriteReg(0x100D00 + 0x08 * 2 + 0, 0x31);
		bRet &= fpWriteReg(0x100D00 + 0x08 * 2 + 1, 0x00);
		// wriu -w	0x100d2a  0x400f //cko_state
		bRet &= fpWriteReg(0x100D00 + 0x15 * 2 + 0, 0x0F);
		bRet &= fpWriteReg(0x100D00 + 0x15 * 2 + 1, 0x40);
		// wriu -w	0x100e02  0x0101 //dqs_state
		bRet &= fpWriteReg(0x100E00 + 0x01 * 2 + 0, 0x01);
		bRet &= fpWriteReg(0x100E00 + 0x01 * 2 + 1, 0x01);
		// wriu -w	0x100e38  0x0000 //
		bRet &= fpWriteReg(0x100E00 + 0x1C * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100E00 + 0x1C * 2 + 1, 0x00);
		// wriu -w	0x100e3a  0x0060 //update 8/6
		bRet &= fpWriteReg(0x100E00 + 0x1D * 2 + 0, 0x60);
		bRet &= fpWriteReg(0x100E00 + 0x1D * 2 + 1, 0x00);
		// wriu -w	0x100e3c  0x8000 //dqsm_skew
		bRet &= fpWriteReg(0x100E00 + 0x1E * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100E00 + 0x1E * 2 + 1, 0x80);
		// wriu -w	0x100e80  0x0010
		bRet &= fpWriteReg(0x100E00 + 0x40 * 2 + 0, 0x10);
		bRet &= fpWriteReg(0x100E00 + 0x40 * 2 + 1, 0x00);
		// wriu -w	0x100e0e  0x0083
		bRet &= fpWriteReg(0x100E00 + 0x07 * 2 + 0, 0x83);
		bRet &= fpWriteReg(0x100E00 + 0x07 * 2 + 1, 0x00);
		// wriu -w	0x100e3a  0x0080
		bRet &= fpWriteReg(0x100E00 + 0x1D * 2 + 0, 0x80);
		bRet &= fpWriteReg(0x100E00 + 0x1D * 2 + 1, 0x00);
	}
	return bRet;
}

//--------------------------------------------------------------------
// DRAM vendor Type
//--------------------------------------------------------------------
#define BABN_64PIN_WB 0xF6
#define BABN_64PIN_ESMT 0xF7
#define BAAN_64PIN_WB 0xE6
#define BAAN_64PIN_ESMT 0xE7
#define BABN_48PIN_WB 0xFE
#define BABN_48PIN_ESMT 0xFF
static MS_BOOL _MIU_SDRAM_INIT(MS_BOOL (*fpReadReg)(MS_U32 u32Addr, MS_U8 *pu8Data),
		MS_BOOL (*fpWriteReg)(MS_U32 u32Addr, MS_U8 pu8Data))
{
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data = 0;

	bRet &= fpReadReg(0x100D00 + 0x00 * 2 + 0, &u8Data);

	if (u8Data != 0x1F) {
		// MIU not init yet

		//================================================
		// Start MIU init !!!
		//================================================
		// wriu -w	0x100d20  0x0000
		bRet &= fpWriteReg(0x100D00 + 0x10 * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100D00 + 0x10 * 2 + 1, 0x00);
		// wriu -w	0x100d1e  0x0c00
		bRet &= fpWriteReg(0x100D00 + 0x0F * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100D00 + 0x0F * 2 + 1, 0x0C);
		// wriu -w	0x100d1e  0x0c00
		bRet &= fpWriteReg(0x100D00 + 0x0F * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100D00 + 0x0F * 2 + 1, 0x0C);
		// wriu -w	0x100d1e  0x0c00
		bRet &= fpWriteReg(0x100D00 + 0x0F * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100D00 + 0x0F * 2 + 1, 0x0C);
		// wriu -w	0x100d1e  0x0c01
		bRet &= fpWriteReg(0x100D00 + 0x0F * 2 + 0, 0x01);
		bRet &= fpWriteReg(0x100D00 + 0x0F * 2 + 1, 0x0C);
		// wriu -w	0x100d1e  0x0c00
		bRet &= fpWriteReg(0x100D00 + 0x0F * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100D00 + 0x0F * 2 + 1, 0x0C);
		// wriu -w	0x100d02  0x0000
		bRet &= fpWriteReg(0x100D00 + 0x01 * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100D00 + 0x01 * 2 + 1, 0x00);
		// wriu -w	0x100d46  0xfffe
		bRet &= fpWriteReg(0x100D00 + 0x23 * 2 + 0, 0xFE);
		bRet &= fpWriteReg(0x100D00 + 0x23 * 2 + 1, 0xFF);
		// wriu -w	0x100d66  0xffff
		bRet &= fpWriteReg(0x100D00 + 0x33 * 2 + 0, 0xFF);
		bRet &= fpWriteReg(0x100D00 + 0x33 * 2 + 1, 0xFF);
		// wriu -w	0x100d86  0xffff
		bRet &= fpWriteReg(0x100D00 + 0x43 * 2 + 0, 0xFF);
		bRet &= fpWriteReg(0x100D00 + 0x43 * 2 + 1, 0xFF);
		// wriu -w	0x100da6  0xffff
		bRet &= fpWriteReg(0x100D00 + 0x53 * 2 + 0, 0xFF);
		bRet &= fpWriteReg(0x100D00 + 0x53 * 2 + 1, 0xFF);

		bRet &= _DDR_PLL_INIT(fpReadReg, fpWriteReg);

		//---------------------------------
		// Pack setting
		//---------------------------------
		// wriu -w	0x100d2c  0xa621
		bRet &= fpWriteReg(0x100D00 + 0x16 * 2 + 0, 0x21);
		bRet &= fpWriteReg(0x100D00 + 0x16 * 2 + 1, 0xA6);
		// wriu -w	0x100e7a  0xffff
		bRet &= fpWriteReg(0x100E00 + 0x3D * 2 + 0, 0xFF);
		bRet &= fpWriteReg(0x100E00 + 0x3D * 2 + 1, 0xFF);
		// wriu -w	0x100e80  0x0010
		bRet &= fpWriteReg(0x100E00 + 0x40 * 2 + 0, 0x10);
		bRet &= fpWriteReg(0x100E00 + 0x40 * 2 + 1, 0x00);
		// wriu -w	0x100e08  0x003f
		bRet &= fpWriteReg(0x100E00 + 0x04 * 2 + 0, 0x3F);
		bRet &= fpWriteReg(0x100E00 + 0x04 * 2 + 1, 0x00);
		// wriu -w	0x100e0e  0x0083
		bRet &= fpWriteReg(0x100E00 + 0x07 * 2 + 0, 0x83);
		bRet &= fpWriteReg(0x100E00 + 0x07 * 2 + 1, 0x00);
		// wriu -w	0x100e0e  0x00c3
		bRet &= fpWriteReg(0x100E00 + 0x07 * 2 + 0, 0xC3);
		bRet &= fpWriteReg(0x100E00 + 0x07 * 2 + 1, 0x00);
		// wriu -w	0x100e0e  0x0083
		bRet &= fpWriteReg(0x100E00 + 0x07 * 2 + 0, 0x83);
		bRet &= fpWriteReg(0x100E00 + 0x07 * 2 + 1, 0x00);
		// wriu -w	0x100d1e  0x0c01
		bRet &= fpWriteReg(0x100D00 + 0x0F * 2 + 0, 0x01);
		bRet &= fpWriteReg(0x100D00 + 0x0F * 2 + 1, 0x0C);
		// wriu -w	0x100d1e  0x0c00
		bRet &= fpWriteReg(0x100D00 + 0x0F * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100D00 + 0x0F * 2 + 1, 0x0C);

		//---------------------------
		// disable GPIO
		//---------------------------
		// wriu -w	0x100e00  0x2010
		bRet &= fpWriteReg(0x100E00 + 0x00 * 2 + 0, 0x10);
		bRet &= fpWriteReg(0x100E00 + 0x00 * 2 + 1, 0x20);
		// wriu -w	0x100e00  0x0000
		bRet &= fpWriteReg(0x100E00 + 0x00 * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100E00 + 0x00 * 2 + 1, 0x00);
		// wriu -w	0x100e7c  0x0000
		bRet &= fpWriteReg(0x100E00 + 0x3E * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100E00 + 0x3E * 2 + 1, 0x00);
		// wriu -w	0x100e00  0x0001 //pakge sel
		bRet &= fpWriteReg(0x100E00 + 0x00 * 2 + 0, 0x01);
		bRet &= fpWriteReg(0x100E00 + 0x00 * 2 + 1, 0x00);
		// wriu -w	0x100e0e  0x0083
		bRet &= fpWriteReg(0x100E00 + 0x07 * 2 + 0, 0x83);
		bRet &= fpWriteReg(0x100E00 + 0x07 * 2 + 1, 0x00);
		// wriu -w	0x100e0e  0x00c3
		bRet &= fpWriteReg(0x100E00 + 0x07 * 2 + 0, 0xC3);
		bRet &= fpWriteReg(0x100E00 + 0x07 * 2 + 1, 0x00);
		// wriu -w	0x100e0e  0x0083
		bRet &= fpWriteReg(0x100E00 + 0x07 * 2 + 0, 0x83);
		bRet &= fpWriteReg(0x100E00 + 0x07 * 2 + 1, 0x00);

		// SDR Setting
		bRet &= fpReadReg(0x100900 + 0x02 * 2 + 0, &u8Data);
		switch (u8Data) {
		case BABN_64PIN_WB:
		case BABN_64PIN_ESMT:
		case BAAN_64PIN_WB:
		case BAAN_64PIN_ESMT:
		case BABN_48PIN_ESMT: {
			bRet &= fpWriteReg(0x100E00 + 0x1B * 2 + 0, 0x08);
			bRet &= fpWriteReg(0x100E00 + 0x1B * 2 + 1, 0x40);
			bRet &= fpWriteReg(0x100E00 + 0x1D * 2 + 0, 0x50);
			bRet &= fpWriteReg(0x100E00 + 0x1D * 2 + 1, 0x00);
			bRet &= fpWriteReg(0x100E00 + 0x3A * 2 + 0, 0xAA);
			bRet &= fpWriteReg(0x100E00 + 0x3A * 2 + 1, 0x00);
			bRet &= fpWriteReg(0x100E00 + 0x2E * 2 + 0, 0xAA);
			bRet &= fpWriteReg(0x100E00 + 0x2E * 2 + 1, 0x00);
			bRet &= fpWriteReg(0x100E00 + 0x3D * 2 + 0, 0xAA);
			bRet &= fpWriteReg(0x100E00 + 0x3D * 2 + 1, 0x00);
		} break;

		case BABN_48PIN_WB: {
			bRet &= fpWriteReg(0x100E00 + 0x1B * 2 + 0, 0x08);
			bRet &= fpWriteReg(0x100E00 + 0x1B * 2 + 1, 0x40);
			bRet &= fpWriteReg(0x100E00 + 0x1D * 2 + 0, 0x50);
			bRet &= fpWriteReg(0x100E00 + 0x1D * 2 + 1, 0x00);
			bRet &= fpWriteReg(0x100E00 + 0x3A * 2 + 0, 0xFF);
			bRet &= fpWriteReg(0x100E00 + 0x3A * 2 + 1, 0x00);
			bRet &= fpWriteReg(0x100E00 + 0x2E * 2 + 0, 0xAA);
			bRet &= fpWriteReg(0x100E00 + 0x2E * 2 + 1, 0x00);
			bRet &= fpWriteReg(0x100E00 + 0x3D * 2 + 0, 0xAA);
			bRet &= fpWriteReg(0x100E00 + 0x3D * 2 + 1, 0x00);
		} break;

		default:
			break;
		}

		// wriu -w	0x100d00  0x0000
		bRet &= fpWriteReg(0x100D00 + 0x00 * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100D00 + 0x00 * 2 + 1, 0x00);
		// wriu -w	0x100d00  0x0008
		bRet &= fpWriteReg(0x100D00 + 0x00 * 2 + 0, 0x08);
		bRet &= fpWriteReg(0x100D00 + 0x00 * 2 + 1, 0x00);
		// wriu -w	0x100d00  0x000c
		bRet &= fpWriteReg(0x100D00 + 0x00 * 2 + 0, 0x0C);
		bRet &= fpWriteReg(0x100D00 + 0x00 * 2 + 1, 0x00);

		//==================================================================
		//--------Wait 10us, Reset Dram(200us in real case)
		//==================================================================
		// wait 1 //delay 1ms
		sys.delayms(1);
		// wriu -w	0x100d00  0x000e
		bRet &= fpWriteReg(0x100D00 + 0x00 * 2 + 0, 0x0E);
		bRet &= fpWriteReg(0x100D00 + 0x00 * 2 + 1, 0x00);

		//======================================================================
		//--------Wait 500ns, dram initernal state initialization(real in 500us)
		//======================================================================
		// wait 1 //delay 1ms
		sys.delayms(1);
		//--------Initial DRAM start here!!!
		// wriu -w	0x100d00  0x001f
		bRet &= fpWriteReg(0x100D00 + 0x00 * 2 + 0, 0x1F);
		bRet &= fpWriteReg(0x100D00 + 0x00 * 2 + 1, 0x00);
		// wait 10 //check reg_101200 #15 for wait initial done
		sys.delayms(10);
		// wriu -w	0x100d1e  0x1a08
		bRet &= fpWriteReg(0x100D00 + 0x0F * 2 + 0, 0x08);
		bRet &= fpWriteReg(0x100D00 + 0x0F * 2 + 1, 0x1A);
		// wriu -w	0x100d40  0x8015
		bRet &= fpWriteReg(0x100D00 + 0x20 * 2 + 0, 0x15);
		bRet &= fpWriteReg(0x100D00 + 0x20 * 2 + 1, 0x80);
		// wriu -w	0x100d60  0x8015
		bRet &= fpWriteReg(0x100D00 + 0x30 * 2 + 0, 0x15);
		bRet &= fpWriteReg(0x100D00 + 0x30 * 2 + 1, 0x80);
		// wriu -w	0x100d80  0x8015
		bRet &= fpWriteReg(0x100D00 + 0x40 * 2 + 0, 0x15);
		bRet &= fpWriteReg(0x100D00 + 0x40 * 2 + 1, 0x80);
		// wriu -w	0x100da0  0x8015
		bRet &= fpWriteReg(0x100D00 + 0x50 * 2 + 0, 0x15);
		bRet &= fpWriteReg(0x100D00 + 0x50 * 2 + 1, 0x80);

		//-------------------------
		// unmask all
		//-------------------------
		// wriu -w	0x100d46  0x0000 //unmask
		bRet &= fpWriteReg(0x100D00 + 0x23 * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100D00 + 0x23 * 2 + 1, 0x00);
		// wriu -w	0x100d66  0x0000 //unmask
		bRet &= fpWriteReg(0x100D00 + 0x33 * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100D00 + 0x33 * 2 + 1, 0x00);
		// wriu -w	0x100d86  0x0000 //unmask
		bRet &= fpWriteReg(0x100D00 + 0x43 * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100D00 + 0x43 * 2 + 1, 0x00);
		// wriu -w	0x100da6  0x0000 //unmask
		bRet &= fpWriteReg(0x100D00 + 0x53 * 2 + 0, 0x00);
		bRet &= fpWriteReg(0x100D00 + 0x53 * 2 + 1, 0x00);
	}
	return bRet;
}

static MS_BOOL _HAL_EXTERN_ISDBT_Download(void)
{
	MS_BOOL bRet = TRUE;
	MS_U16 index = 0;
	MS_U16 SRAM_Address = 0;
#if DMD_ISDBT_UTOPIA_EN || DMD_ISDBT_UTOPIA2_EN || DMD_ISDBT_3PARTY_MSPI_EN
	MS_U32 SRAM_SSPI_Address = 0;
#endif
	MS_U8 u8TmpData = 0;
	MS_U16 u16AddressOffset = 0;
	const MS_U8 *ISDBT_table;
	MS_U16 u16Lib_size;

	pr_info("[%s][%d] *pExtChipChId = %d, __entry__\n",
			__func__, __LINE__, *pExtChipChId);

#if (BOOT_FROM_SRAM == FALSE)
	// check if FW was downloaded or not
	// icache not bypass
	bRet &= _I2C_READ_BYTE(0x102B00 + 0x50 * 2, &u8TmpData);
	if (u8TmpData == 0x00) // downloaded
		pRes->sdmd_isdbt_pridata.bdownloaded = TRUE;
	else
		pRes->sdmd_isdbt_pridata.bdownloaded = FALSE;
#endif

	if (pRes->sdmd_isdbt_pridata.bdownloaded) {
		// Enable MCU Reset
		bRet &= _I2C_WRITE_BYTE(REG_MCU_RST + (*(pExtChipChId)), 0x01);

		// Boot from SRAM
		bRet &= _I2C_WRITE_BYTE(MCU_REG_BASE + (*(pExtChipChId)) * 0x2800 + 0x18, 0x01);

		sys.delayms(5);

		// Disable MCU Reset
		bRet &= _I2C_WRITE_BYTE(REG_MCU_RST + (*(pExtChipChId)), 0x00);

		sys.delayms(20);

		return bRet;
	}

	if (pRes->sdmd_isdbt_pridata.elast_type == DMD_ISDBT_DEMOD_8M) {
		ISDBT_table = &EXTERN_ISDBT_8M_table[0];
		u16Lib_size = sizeof(EXTERN_ISDBT_8M_table);
	} else {
		ISDBT_table = &EXTERN_ISDBT_table[0];
		u16Lib_size = sizeof(EXTERN_ISDBT_table);
	}
	pr_info("[%s][%d] *pExtChipChId = %d, firmware code size = 0x[%x]\n",
		__func__, __LINE__, pExtChipChId, u16Lib_size);

	// Enable MCU Reset
	bRet &= _I2C_WRITE_BYTE(REG_MCU_RST + (*(pExtChipChId)), 0x01);

#if !SOC_LIKE_EXT_DMD
	bRet &= _I2C_Channel_Change(0);
#endif

	// Disable Watch-Dog
	bRet &= _I2C_WRITE_BYTE(WDT_REG_BASE + 0x08, 0x00);
	bRet &= _I2C_WRITE_BYTE(WDT_REG_BASE + 0x09, 0x00);
	bRet &= _I2C_WRITE_BYTE(WDT_REG_BASE + 0x0A, 0x00);
	bRet &= _I2C_WRITE_BYTE(WDT_REG_BASE + 0x0B, 0x00);

	bRet &= _I2C_Channel_Change(3);

	// Enable SRAM XDATA mapping
	// Start address
	bRet &= _I2C_WRITE_BYTE(MCU_REG_BASE + (*(pExtChipChId)) * 0x2800 + 0xE1, 0x20);
	// End address
	bRet &= _I2C_WRITE_BYTE(MCU_REG_BASE + (*(pExtChipChId)) * 0x2800 + 0xE0, 0x3F);
#if !USE_PSRAM_32KB
	bRet &= _I2C_WRITE_BYTE(MCU_REG_BASE + (*(pExtChipChId)) * 0x2800 + 0xE6, 0x08);
#else
	bRet &= _I2C_WRITE_BYTE(MCU_REG_BASE + (*(pExtChipChId)) * 0x2800 + 0xE6, 0x18);
	bRet &= _I2C_WRITE_BYTE(MCU_REG_BASE + (*(pExtChipChId)) * 0x2800 + 0xE4, 0x20);
#endif

	// Choose download FW to DMD 0 or DMD 1
	if (*pExtChipChId == 0) {
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x24, 0x00);
		// sel dmd_riu_0
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x26, 0x00);
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x28, 0x00);
	} else {
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x24, 0x01);
		// sel dmd_riu_1
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x26, 0x01);
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x28, 0x00);
	}

	pr_info("[%s][%d] *pExtChipChId = %d, Downloading...\n",
			__func__, __LINE__, *pExtChipChId);

	if (pRes->sdmd_isdbt_initdata.is_use_sspi_load_code) {
#if DMD_ISDBT_UTOPIA_EN || DMD_ISDBT_UTOPIA2_EN || DMD_ISDBT_3PARTY_MSPI_EN

		pr_info("[%s][%d] *pExtChipChId = %d, By SSPI download firmware\n",
				__func__, __LINE__, *pExtChipChId);

		// Turn on all pad in
		bRet &= _I2C_WRITE_BYTE(REG_ALL_PAD_IN, 0x00);

		// ------- MSPI protocol setting
		// [8] cpha
		// [9] cpol
		bRet &= _I2C_READ_BYTE(TOP_REG_BASE + 0x3A * 2 + 1, &u8TmpData);
		u8TmpData &= 0xFC;
		bRet &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x3A * 2 + 1, u8TmpData);

		if (pRes->sdmd_isdbt_initdata.is_sspi_use_ts_pin == TRUE) {
			pr_info("[%s][%d] *pExtChipChId = %d, MSPI USE TS PIN : ENABLE\n",
					__func__, __LINE__, *pExtChipChId);
			bRet &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x3B * 2 + 0, 0x02);
		} else {
			pr_info("[%s][%d] *pExtChipChId = %d, MSPI USE SPI PIN : ENABLE\n",
					__func__, __LINE__, *pExtChipChId);
			bRet &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x3B * 2 + 0, 0x01);
		}

		pr_info("[%s][%d] *pExtChipChId = %d, %s by MSPI\n",
				__func__, __LINE__, *pExtChipChId, __func__);

		_SSPI_Init(0);

		// Debug SSPI r/w
		bRet &= _SSPI_RIU_Read8(TOP_REG_BASE, &u8TmpData);
		pr_info("[%s][%d] *pExtChipChId = %d, _SSPI_RIU_Read chip ID = 0x[%x]\n",
				__func__, __LINE__, *pExtChipChId, u8TmpData);

		if (u8TmpData != CHIP_ID)
			return FALSE;

		// Enable sspi to sram
		//[4:4]reg_sspi2sram_en;
		//[5:5]reg_sspi2sram_1_en;
		bRet &= _SSPI_RIU_Read8(TOP_REG_BASE + 0x3A * 2 + 0, &u8TmpData);
		if (*pExtChipChId == 0)
			u8TmpData |= 0x10;
		else
			u8TmpData |= 0x20;

		bRet &= _SSPI_RIU_Write8(TOP_REG_BASE + 0x3A * 2 + 0, u8TmpData);

		bRet &= _MPLL_INIT(&_I2C_READ_BYTE, &_SSPI_RIU_Write8);
		bRet &= _MIU_SDRAM_INIT(&_I2C_READ_BYTE, &_SSPI_RIU_Write8);

		SRAM_SSPI_Address = 0x80000000;
		bRet &= _SSPI_MIU_Writes(SRAM_SSPI_Address, (MS_U8 *)ISDBT_table, u16Lib_size);

		// Disable sspi to sram
		//[4:4]reg_sspi2sram_en;
		//[5:5]reg_sspi2sram_1_en;
		bRet &= _SSPI_RIU_Read8(TOP_REG_BASE + 0x3A * 2 + 0, &u8TmpData);
		if (*pExtChipChId == 0)
			u8TmpData &= ~0x10;
		else
			u8TmpData &= ~0x20;

		bRet &= _SSPI_RIU_Write8(TOP_REG_BASE + 0x3A * 2 + 0, u8TmpData);

		if (pRes->sdmd_isdbt_initdata.is_sspi_use_ts_pin == TRUE) {
			pr_info("[%s][%d] *pExtChipChId = %d, MSPI USE TS PIN : DISABLE\n",
				__func__, __LINE__, *pExtChipChId);
			bRet &= _I2C_READ_BYTE(TOP_REG_BASE + 0x3B * 2 + 0, &u8TmpData);
			u8TmpData &= ~0x02;
			bRet &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x3B * 2 + 0, u8TmpData);
		}
#endif
	} else {
		// By I2C

		pr_info("[%s][%d] *pExtChipChId = %d, By I2C download firmware\n",
				__func__, __LINE__, *pExtChipChId);
		bRet &= _I2C_Channel_Change(0);

		for (index = 0; index < u16Lib_size;) {
			SRAM_Address = SRAM_BASE + index;
			if ((index + LOAD_CODE_I2C_BLOCK_NUM) <= u16Lib_size) {
				bRet &= _I2C_WRITE_BYTES(
						SRAM_Address,
						(MS_U8 *)(ISDBT_table + index),
						LOAD_CODE_I2C_BLOCK_NUM);
				index += LOAD_CODE_I2C_BLOCK_NUM;
			} else {
				bRet &= _I2C_WRITE_BYTES(
						SRAM_Address,
						(MS_U8 *)(ISDBT_table + index),
						u16Lib_size - index);
				index = u16Lib_size;
			}
		}
	}

	bRet &= _I2C_Channel_Change(0);

	// Get address offset
	u16AddressOffset = (ISDBT_table[0x400] << 8) | ISDBT_table[0x401];

	pr_info("[%s][%d] *pExtChipChId = %d, u16AddressOffset = 0x[%x]\n",
		__func__, __LINE__, *pExtChipChId,
		u16AddressOffset);
	pr_info("[%s][%d] *pExtChipChId = %d, if_khz = 0x[%x]\n",
		__func__, __LINE__, *pExtChipChId,
		(pRes->sdmd_isdbt_initdata.if_khz));
	pr_info("[%s][%d] *pExtChipChId = %d, iq_swap = 0x[%x]\n",
		__func__, __LINE__, *pExtChipChId,
		pRes->sdmd_isdbt_initdata.iq_swap);
	pr_info("[%s][%d] *pExtChipChId = %d, agc_reference_value = 0x[%x]\n",
		__func__, __LINE__, *pExtChipChId,
		(pRes->sdmd_isdbt_initdata.agc_reference_value));
	pr_info("[%s][%d] *pExtChipChId = %d, tuner_gain_invert = 0x[%x]\n",
		__func__, __LINE__, *pExtChipChId,
		(pRes->sdmd_isdbt_initdata.tuner_gain_invert));

	// Set IF value
	SRAM_Address = SRAM_BASE + u16AddressOffset;
	u8TmpData = (pRes->sdmd_isdbt_initdata.if_khz) & 0xFF;
	bRet &= _I2C_WRITE_BYTE(SRAM_Address, u8TmpData);
	SRAM_Address = SRAM_BASE + u16AddressOffset + 1;
	u8TmpData = (pRes->sdmd_isdbt_initdata.if_khz) >> 8;
	bRet &= _I2C_WRITE_BYTE(SRAM_Address, u8TmpData);

	// Set IQSwap mode
	SRAM_Address = SRAM_BASE + u16AddressOffset + 2;
	u8TmpData = pRes->sdmd_isdbt_initdata.iq_swap;
	bRet &= _I2C_WRITE_BYTE(SRAM_Address, u8TmpData);

	// Set AGC ref
	SRAM_Address = SRAM_BASE + u16AddressOffset + 3;
	u8TmpData = (pRes->sdmd_isdbt_initdata.agc_reference_value) & 0xFF;
	bRet &= _I2C_WRITE_BYTE(SRAM_Address, u8TmpData);
	SRAM_Address = SRAM_BASE + u16AddressOffset + 4;
	u8TmpData = (pRes->sdmd_isdbt_initdata.agc_reference_value) >> 8;
	bRet &= _I2C_WRITE_BYTE(SRAM_Address, u8TmpData);

	// Set Tuner Gain Invert
	SRAM_Address = SRAM_BASE + u16AddressOffset + 9;
	u8TmpData = pRes->sdmd_isdbt_initdata.tuner_gain_invert;
	bRet &= _I2C_WRITE_BYTE(SRAM_Address, u8TmpData);

	bRet &= _I2C_Channel_Change(3);

	// Set program SRAM start address
	bRet &= _I2C_WRITE_BYTE(MCU_REG_BASE + (*(pExtChipChId)) * 0x2800 + 0x04, 0x00);
	bRet &= _I2C_WRITE_BYTE(MCU_REG_BASE + (*(pExtChipChId)) * 0x2800 + 0x05, 0x00);
	bRet &= _I2C_WRITE_BYTE(MCU_REG_BASE + (*(pExtChipChId)) * 0x2800 + 0x00, 0x00);

	// Set program SRAM end address
	bRet &= _I2C_WRITE_BYTE(MCU_REG_BASE + (*(pExtChipChId)) * 0x2800 + 0x06, 0x7F);
	bRet &= _I2C_WRITE_BYTE(MCU_REG_BASE + (*(pExtChipChId)) * 0x2800 + 0x07, 0xFF);
	bRet &= _I2C_WRITE_BYTE(MCU_REG_BASE + (*(pExtChipChId)) * 0x2800 + 0x02, 0x00);

	// Disable SRAM XDATA mapping
	bRet &= _I2C_WRITE_BYTE(MCU_REG_BASE + (*(pExtChipChId)) * 0x2800 + 0xE6, 0x00);

	// Boot from SRAM
	bRet &= _I2C_WRITE_BYTE(MCU_REG_BASE + (*(pExtChipChId)) * 0x2800 + 0x18, 0x01);

	// Disable MCU Reset
	bRet &= _I2C_WRITE_BYTE(REG_MCU_RST + (*(pExtChipChId)), 0x00);

	pRes->sdmd_isdbt_pridata.bdownloaded = TRUE;
	pr_info("[%s][%d] *pExtChipChId = %d, pRes->sdmd_isdbt_pridata.bdownloaded = TRUE\n",
		__func__, __LINE__, *pExtChipChId);
	sys.delayms(20);

	pr_info("[%s][%d] *pExtChipChId = %d, _HAL_EXTERN_ISDBT_Download_End\n",
		__func__, __LINE__, *pExtChipChId);

	return bRet;
}

static void _HAL_EXTERN_ISDBT_FWVERSION(void)
{
	MS_U8 data1 = 0;
	MS_U8 data2 = 0;
	MS_U8 data3 = 0;
	MS_BOOL bRet = TRUE;

	pr_info("[%s][%d] *pExtChipChId = %d, __entry__\n", __func__, __LINE__, *pExtChipChId);

	// Choose download FW to DMD 0 or DMD 1
	if (*pExtChipChId == 0) {
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x24, 0x00);
		// sel dmd_riu_0
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x26, 0x00);
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x28, 0x00);
	} else {
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x24, 0x01);
		// sel dmd_riu_1
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x26, 0x01);
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x28, 0x00);
	}

#if SOC_LIKE_EXT_DMD
	_I2C_READ_BYTE(0x20C4, &data1);
	_I2C_READ_BYTE(0x20C5, &data2);
	_I2C_READ_BYTE(0x20C6, &data3);
#else
	_I2C_READ_BYTE(0x0995, &data1); // REG_BASE[DMDTOP_WR_DBG_04]
	_I2C_READ_BYTE(0x0996, &data2); // REG_BASE[DMDTOP_WR_DBG_05]
	_I2C_READ_BYTE(0x0997, &data3); // REG_BASE[DMDTOP_WR_DBG_06]
#endif

	pr_info("[%s][%d] *pExtChipChId = %d, %x.%x.%x\n",
		__func__, __LINE__, *pExtChipChId,
		data1, data2, data3);
}

static MS_BOOL _HAL_EXTERN_ISDBT_Exit(void)
{
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data = 0;

	pr_info("[%s][%d] *pExtChipChId = %d, __entry__\n", __func__, __LINE__, *pExtChipChId);

	// Choose download FW to DMD 0 or DMD 1
	if (*pExtChipChId == 0) {
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x24, 0x00);
		// sel dmd_riu_0
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x26, 0x00);
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x28, 0x00);
	} else {
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x24, 0x01);
		// sel dmd_riu_1
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x26, 0x01);
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x28, 0x00);
	}

	// Prevent ISDBT Access DRAM before MCU reset
	// PRINT("Stop ISDBT Access DRAM before MCU reset\n");
	if (_I2C_WRITE_BYTE(0x20C0, 0x00) == FALSE)
		return FALSE;

	u8Data = 0;
	while (u8Data != 0x02) {
		if (_I2C_READ_BYTE(0x20C1, &u8Data) == FALSE)
			return FALSE;
	}
	// PRINT("Stop ISDBT Access DRAM Done\n");

	// Reset MCU
	// Enable MCU Reset
	bRet &= _I2C_WRITE_BYTE(REG_MCU_RST + (*(pExtChipChId)), 0x01);
	sys.delayms(1);
	// Disable MCU Reset
	bRet &= _I2C_WRITE_BYTE(REG_MCU_RST + (*(pExtChipChId)), 0x00);
	sys.delayms(1);
	// Enable MCU Reset
	bRet &= _I2C_WRITE_BYTE(REG_MCU_RST + (*(pExtChipChId)), 0x01);

	// Disable TS pad
	u8Data = 0x00;
	bRet &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x5A, u8Data);

	// [0][4] ifagc/rfagc disable
	bRet &= _I2C_READ_BYTE(DMDANA_REG_BASE + (*(pExtChipChId)) * 0x2400 + 0x30, &u8Data);
	u8Data &= ~0x11;
	bRet &= _I2C_WRITE_BYTE(DMDANA_REG_BASE + (*(pExtChipChId)) * 0x2400 + 0x30, u8Data);

	return bRet;
}

static MS_BOOL _HAL_EXTERN_ISDBT_SoftReset(void)
{
	MS_U8 u8Data = 1;
	MS_U8 u8Data_Temp1 = 1;
	MS_U8 u8Data_Temp2 = 1;
	MS_U8 u8Data_mcu_boot = 0;
	MS_U32 u32programCounterValue = 1;
	MS_U8 useMCURST = 0;
	MS_U8 u8DatadbgPrint = 0;
	MS_U8 u8Cnt = 0;

	pr_info("[%s][%d]DMD_tune start\n", __func__, __LINE__);
// Reset FSM
#if SOC_LIKE_EXT_DMD
	if (_I2C_WRITE_BYTE(0x20C0, 0x00) == FALSE)
		return FALSE;

	while (u8Data != 0x00) {
		_I2C_READ_BYTE(0x20C0, &u8Data);
		pr_info("[%s][%d]DMD_tune 0x20C0:0x%x\n",
			__func__, __LINE__, u8Data);
		_I2C_WRITE_BYTE(0x20C0, 0x00);
	}

	while (u8Data != 0x02) {
		if (_I2C_READ_BYTE(0x20C1, &u8Data) == FALSE) {
			// u8Data:0x20c1 state machine
			return FALSE;
		}

		// u8Data_Temp1:0x20c0 active flag read
		_I2C_READ_BYTE(0x20C0, &u8Data_Temp1);

		// u8Data_Temp2:program counter
		_I2C_READ_BYTE(MCU_REG_BASE + 0xFC, &u8Data_Temp2);
		u32programCounterValue = u8Data_Temp2;

		_I2C_READ_BYTE(MCU_REG_BASE + 0xFD, &u8Data_Temp2);
		u32programCounterValue |= u8Data_Temp2 << 8;

		_I2C_READ_BYTE(MCU_REG_BASE + 0xFE, &u8Data_Temp2);
		u32programCounterValue |= u8Data_Temp2 << 16;

		_I2C_READ_BYTE(0x20E0, &u8DatadbgPrint);

		pr_info("[%s][%d]DMD_tune 0x20C1:0x%x 0x20C0:0x%x counter:0x%x 0x20E0:0x%x\n",
			__func__, __LINE__, u8Data,	u8Data_Temp1,
			u32programCounterValue, u8DatadbgPrint);

		u8Cnt++;

		if ((u8Data != 0x02) && (u8Data_Temp1 == 0x00) && (u8Cnt >= 5)) {
			useMCURST = 1;
			break;
		}
	}

	if (useMCURST) {
		_I2C_READ_BYTE(MCU_REG_BASE + (*(pExtChipChId)) * 0x2800 + 0x18, &u8Data_mcu_boot);
		pr_info("[%s][%d] dmd-%d, u8Data_mcu_boot = %d.\r\n",
			__func__, __LINE__, *(pExtChipChId), u8Data_mcu_boot);

		// Enable MCU Reset
		_I2C_WRITE_BYTE(REG_MCU_RST + (*(pExtChipChId)), 0x01);

		// Boot from SRAM
		_I2C_WRITE_BYTE(MCU_REG_BASE + (*(pExtChipChId)) * 0x2800 + 0x18, 0x01);

		// Disable MCU Reset
		_I2C_WRITE_BYTE(REG_MCU_RST + (*(pExtChipChId)), 0x00);

		sys.delayms(20);

		if (_I2C_WRITE_BYTE(0x20C0, 0x00) == FALSE)
			return FALSE;

		u8Data = 1;
		while (u8Data != 0x02) {
			if (_I2C_READ_BYTE(0x20C1, &u8Data) == FALSE)
				return FALSE;
			pr_info("[%s][%d]0x20C1:0x%x\n", __func__, __LINE__, u8Data);
		}
	}
#else
	if (_I2C_WRITE_BYTE(0x0990, 0x00) == FALSE)
		return FALSE;

	while (u8Data != 0x02) {
		if (_I2C_READ_BYTE(0x0992, &u8Data) == FALSE)
			return FALSE;
	}
#endif
	pr_info("[%s][%d]DMD_tune end\n", __func__, __LINE__);

	return TRUE;
}

static MS_BOOL _HAL_EXTERN_ISDBT_SetACICoef(void)
{
	return TRUE;
}

static MS_BOOL _HAL_EXTERN_ISDBT_SetIsdbtMode(void)
{
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data = 0;

	pr_info("[%s][%d] *pExtChipChId = %d, __entry__\n",
			__func__, __LINE__, *pExtChipChId);

	// Choose download FW to DMD 0 or DMD 1
	if (*pExtChipChId == 0) {
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x24, 0x00);
		// sel dmd_riu_0
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x26, 0x00);
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x28, 0x00);
	} else {
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x24, 0x01);
		// sel dmd_riu_1
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x26, 0x01);
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x28, 0x00);
	}

// #if SOC_LIKE_EXT_DMD
// if (_I2C_WRITE_BYTE(0x20C2, 0x04)==FALSE) return FALSE;
// return _I2C_WRITE_BYTE(0x20C0, 0x04);
// #else
// if (_I2C_WRITE_BYTE(0x0993, 0x04)==FALSE) return FALSE;
// return _I2C_WRITE_BYTE(0x0990, 0x04);
// #endif

#if SOC_LIKE_EXT_DMD
	if (_I2C_WRITE_BYTE(0x20C2, 0x04) == FALSE)
		return FALSE;

	bRet &= _I2C_WRITE_BYTE(0x20C0, 0x04);

	sys.delayms(20);

	// dbg
	// [0][4] ifagc/rfagc enable
	bRet &= _I2C_READ_BYTE(DMDANA_REG_BASE + (*(pExtChipChId)) * 0x2400 + 0x30, &u8Data);
	u8Data |= 0x01;
	bRet &= _I2C_WRITE_BYTE(DMDANA_REG_BASE + (*(pExtChipChId)) * 0x2400 + 0x30, u8Data);

	return bRet;
#else
	if (_I2C_WRITE_BYTE(0x0993, 0x04) == FALSE)
		return FALSE;
	return _I2C_WRITE_BYTE(0x0990, 0x04);
#endif
}

static MS_BOOL _HAL_EXTERN_ISDBT_SetEwbsMode(void)
{
	MS_BOOL bRet = TRUE;
	MS_U8 u8TmpData;
	MS_U16 u16EWBSConfigDataAddr;

	// Get the base address of FW HAL_PRI_XDATA_BASE
	u16EWBSConfigDataAddr = 0;
	bRet &= _READ_MBX(FW_PRI_XDATA_BASE, &u8TmpData); // 0x4008
	u16EWBSConfigDataAddr = u8TmpData << 8;
	bRet &= _READ_MBX(FW_PRI_XDATA_BASE + 1, &u8TmpData); // 0x4009
	u16EWBSConfigDataAddr |= u8TmpData;

	// SET Area code to u16EWBSConfigDataAddr

	// Area code set 0 (16 bits): area_code_addr_set0 (HB, LB)
	u8TmpData = (pRes->sdmd_isdbt_initdata.area_code_addr_set0) & 0xFF; // LB
	bRet &= _WRITE_MBX(u16EWBSConfigDataAddr + 0, u8TmpData);
	u8TmpData = (pRes->sdmd_isdbt_initdata.area_code_addr_set0) >> 8; // HB
	bRet &= _WRITE_MBX(u16EWBSConfigDataAddr + 1, u8TmpData);

	// Area code set 1 (16 bits): area_code_addr_set1 (HB, LB)
	u8TmpData = (pRes->sdmd_isdbt_initdata.area_code_addr_set1) & 0xFF; // LB
	bRet &= _WRITE_MBX(u16EWBSConfigDataAddr + 2, u8TmpData);
	u8TmpData = (pRes->sdmd_isdbt_initdata.area_code_addr_set1) >> 8; // HB
	bRet &= _WRITE_MBX(u16EWBSConfigDataAddr + 3, u8TmpData);

	// Area code set 2 (16 bits): area_code_addr_set2 (HB, LB)
	u8TmpData = (pRes->sdmd_isdbt_initdata.area_code_addr_set2) & 0xFF; // LB
	bRet &= _WRITE_MBX(u16EWBSConfigDataAddr + 4, u8TmpData);
	u8TmpData = (pRes->sdmd_isdbt_initdata.area_code_addr_set2) >> 8; // HB
	bRet &= _WRITE_MBX(u16EWBSConfigDataAddr + 5, u8TmpData);

	// Area code set 3 (16 bits): area_code_addr_set3 (HB, LB)
	u8TmpData = (pRes->sdmd_isdbt_initdata.area_code_addr_set3) & 0xFF; // LB
	bRet &= _WRITE_MBX(u16EWBSConfigDataAddr + 6, u8TmpData);
	u8TmpData = (pRes->sdmd_isdbt_initdata.area_code_addr_set3) >> 8; // HB
	bRet &= _WRITE_MBX(u16EWBSConfigDataAddr + 7, u8TmpData);

#if SOC_LIKE_EXT_DMD
	if (_I2C_WRITE_BYTE(0x20C2, 0x14) == FALSE)
		return FALSE;
	return _I2C_WRITE_BYTE(0x20C0, 0x04);
#else
	if (_I2C_WRITE_BYTE(0x0993, 0x14) == FALSE)
		return FALSE;
	return _I2C_WRITE_BYTE(0x0990, 0x04);
#endif
}

static MS_BOOL _HAL_EXTERN_ISDBT_SetModeClean(void)
{
#if SOC_LIKE_EXT_DMD
	if (_I2C_WRITE_BYTE(0x20C2, 0x07) == FALSE)
		return FALSE;
	return _I2C_WRITE_BYTE(0x20C0, 0x00);
#else
	if (_I2C_WRITE_BYTE(0x0993, 0x07) == FALSE)
		return FALSE;
	return _I2C_WRITE_BYTE(0x0990, 0x00);
#endif
}

static MS_BOOL _HAL_EXTERN_ISDBT_Check_EWBS_Lock(void)
{
	MS_BOOL bCheckPass = FALSE;
	MS_U8 u8Data = 0;

	_I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x08, &u8Data);
	if ((u8Data & 0x01) != 0x00) // Check EWBS TMCC FLAG
		bCheckPass = TRUE;

	return bCheckPass;
}

static MS_BOOL _HAL_EXTERN_ISDBT_Check_FEC_Lock(void)
{
	MS_BOOL bCheckPass = FALSE;
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data = 0;
	MS_U16 u16PacketErr = 0;
	MS_U8 u8ReadData = 0;
	MS_U8 u8Data_state = 0;

	pr_info("[%s][%d] *pExtChipChId = %d, __entry__\n",
			__func__, __LINE__, *pExtChipChId);

	// Choose download FW to DMD 0 or DMD 1
	if (*pExtChipChId == 0) {
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x24, 0x00);
		// sel dmd_riu_0
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x26, 0x00);
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x28, 0x00);
		_I2C_READ_BYTE(0x20C1, &u8Data_state);
		pr_info("[%s][%d] *pExtChipChId = %d, [isdbt-dmd-0]0x20C1=0x%x.\n",
				__func__, __LINE__, *pExtChipChId, u8Data_state);
	} else {
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x24, 0x01);
		// sel dmd_riu_1
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x26, 0x01);
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x28, 0x00);
		_I2C_READ_BYTE(0x20C1, &u8Data_state);
		pr_info("[%s][%d] *pExtChipChId = %d, [isdbt-dmd-1]0x20C1=0x%x.\n",
				__func__, __LINE__, *pExtChipChId, u8Data_state);
	}

	_I2C_READ_BYTE(REG_ISDBT_LOCK_STATUS2, &u8Data);
	pr_info("[%s][%d] *pExtChipChId = %d, REG_ISDBT_LOCK_STATUS2 = 0x%x\n",
			__func__, __LINE__, *pExtChipChId, u8Data);
	if ((u8Data & 0x04) != 0x00) // Check FEC Lock Flag
		bCheckPass = TRUE;

	return bCheckPass;
}

static MS_BOOL _HAL_EXTERN_ISDBT_Check_FSA_TRACK_Lock(void)
{
	MS_BOOL bCheckPass = FALSE;
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data = 0;

	pr_info("[%s][%d] *pExtChipChId = %d, __entry__\n", __func__, __LINE__, *pExtChipChId);

	// Choose download FW to DMD 0 or DMD 1
	if (*pExtChipChId == 0) {
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x24, 0x00);
		// sel dmd_riu_0
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x26, 0x00);
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x28, 0x00);
	} else {
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x24, 0x01);
		// sel dmd_riu_1
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x26, 0x01);
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x28, 0x00);
	}

	_I2C_READ_BYTE(REG_ISDBT_LOCK_STATUS2, &u8Data);

	if ((u8Data & 0x10) != 0x00) // Check FSA Track Lock Flag
		bCheckPass = TRUE;

	return bCheckPass;
}

static MS_BOOL _HAL_EXTERN_ISDBT_Check_PSYNC_Lock(void)
{
	MS_BOOL bCheckPass = FALSE;
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data = 0;

	pr_info("[%s][%d] *pExtChipChId = %d, __entry__\n",
		__func__, __LINE__, *pExtChipChId);

	// Choose download FW to DMD 0 or DMD 1
	if (*pExtChipChId == 0) {
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x24, 0x00);
		// sel dmd_riu_0
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x26, 0x00);
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x28, 0x00);
	} else {
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x24, 0x01);
		// sel dmd_riu_1
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x26, 0x01);
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x28, 0x00);
	}

	_I2C_READ_BYTE(REG_ISDBT_LOCK_STATUS, &u8Data);

	if ((u8Data & 0x04) != 0x00) // Check Psync Lock Flag
		bCheckPass = TRUE;

	return bCheckPass;
}

static MS_BOOL _HAL_EXTERN_ISDBT_Check_ICFO_CH_EXIST_Lock(void)
{
	MS_BOOL bCheckPass = FALSE;
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data = 0;

	pr_info("[%s][%d] *pExtChipChId = %d, __entry__\n",
		__func__, __LINE__, *pExtChipChId);

	// Choose download FW to DMD 0 or DMD 1
	if (*pExtChipChId == 0) {
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x24, 0x00);
		// sel dmd_riu_0
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x26, 0x00);
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x28, 0x00);
	} else {
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x24, 0x01);
		// sel dmd_riu_1
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x26, 0x01);
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x28, 0x00);
	}

	_I2C_READ_BYTE(REG_ISDBT_LOCK_STATUS2, &u8Data);
	pr_info("[%s][%d] *pExtChipChId = %d, REG_ISDBT_LOCK_STATUS2 = 0x%x\n",
		__func__, __LINE__, *pExtChipChId, u8Data);

	if ((u8Data & 0x03) == 0x02) {
		// Check ICFO Lock Flag
		bCheckPass = TRUE;
	}

	pr_info("[%s][%d]*pExtChipChId = %d, bCheckPass = %d\n",
		__func__, __LINE__, *pExtChipChId, bCheckPass);
	return bCheckPass;
}

static MS_BOOL _HAL_EXTERN_ISDBT_Check_MODE_CP_Lock(void)
{
	MS_BOOL bCheckPass = FALSE;
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data = 0;

	pr_info("[%s][%d] *pExtChipChId = %d, __entry__\n",
		__func__, __LINE__, *pExtChipChId);

	// Choose download FW to DMD 0 or DMD 1
	if (*pExtChipChId == 0) {
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x24, 0x00);
		// sel dmd_riu_0
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x26, 0x00);
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x28, 0x00);
	} else {
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x24, 0x01);
		// sel dmd_riu_1
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x26, 0x01);
		bRet &= _I2C_WRITE_BYTE(0x103C00 + 0x28, 0x00);
	}

#if SOC_LIKE_EXT_DMD
	_I2C_READ_BYTE(0x20C1, &u8Data);
	pr_info("[%s][%d] *pExtChipChId = %d, 0x20C1 = %d\n",
		__func__, __LINE__, *pExtChipChId, u8Data);
#else
	_I2C_READ_BYTE(0x0992, &u8Data);
#endif

	if (u8Data >= 0x30) {
		// Check MODE CP Lock Flag
		bCheckPass = TRUE;
	}

	pr_info("[%s][%d] *pExtChipChId = %d, bCheckPass = %d\n",
		__func__, __LINE__, *pExtChipChId, bCheckPass);

	return bCheckPass;
}

static MS_BOOL _HAL_EXTERN_ISDBT_GetSignalCodeRate(
		enum en_isdbt_layer eLayerIndex, enum en_isdbt_code_rate *peIsdbtCodeRate)
{
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data = 0;
	MS_U8 u8CodeRate = 0;

	switch (eLayerIndex) {
	case E_ISDBT_Layer_A:
		// [10:8] reg_tmcc_cur_convolution_code_rate_a
		bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x04 * 2 + 1, &u8Data);
		u8CodeRate = u8Data & 0x07;
		break;
	case E_ISDBT_Layer_B:
		// [10:8] reg_tmcc_cur_convolution_code_rate_b
		bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x05 * 2 + 1, &u8Data);
		u8CodeRate = u8Data & 0x07;
		break;
	case E_ISDBT_Layer_C:
		// [10:8] reg_tmcc_cur_convolution_code_rate_c
		bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x06 * 2 + 1, &u8Data);
		u8CodeRate = u8Data & 0x07;
		break;
	default:
		u8CodeRate = 15;
		break;
	}

	switch (u8CodeRate) {
	case 0:
		*peIsdbtCodeRate = E_ISDBT_CODERATE_1_2;
		break;
	case 1:
		*peIsdbtCodeRate = E_ISDBT_CODERATE_2_3;
		break;
	case 2:
		*peIsdbtCodeRate = E_ISDBT_CODERATE_3_4;
		break;
	case 3:
		*peIsdbtCodeRate = E_ISDBT_CODERATE_5_6;
		break;
	case 4:
		*peIsdbtCodeRate = E_ISDBT_CODERATE_7_8;
		break;
	default:
		*peIsdbtCodeRate = E_ISDBT_CODERATE_INVALID;
		break;
	}

	return bRet;
}

static MS_BOOL _HAL_EXTERN_ISDBT_GetSignalGuardInterval(
		enum en_isdbt_guard_interval *peIsdbtGI)
{
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data = 0;
	MS_U8 u8CP = 0;

// [7:6] reg_mcd_out_cp
// output cp -> 00: 1/4
//                    01: 1/8
//                    10: 1/16
//                    11: 1/32
#if SOC_LIKE_EXT_DMD
	bRet &= _I2C_READ_BYTE(ISDBT_TDP_REG_BASE + 0x5A * 2, &u8Data);
	u8CP = (u8Data >> 4) & 0x03;
#else
	bRet &= _I2C_READ_BYTE(ISDBT_TDP_REG_BASE + 0x34 * 2, &u8Data);
	u8CP = (u8Data >> 6) & 0x03;
#endif

	switch (u8CP) {
	case 0:
		*peIsdbtGI = E_ISDBT_GUARD_INTERVAL_1_4;
		break;
	case 1:
		*peIsdbtGI = E_ISDBT_GUARD_INTERVAL_1_8;
		break;
	case 2:
		*peIsdbtGI = E_ISDBT_GUARD_INTERVAL_1_16;
		break;
	case 3:
		*peIsdbtGI = E_ISDBT_GUARD_INTERVAL_1_32;
		break;
	default:
		*peIsdbtGI = E_ISDBT_GUARD_INTERVAL_INVALID;
		break;
	}

	return bRet;
}

static MS_BOOL _HAL_EXTERN_ISDBT_GetSignalTimeInterleaving(
		enum en_isdbt_layer eLayerIndex, enum en_isdbt_time_interleaving *peIsdbtTDI)
{
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data = 0;
	MS_U8 u8Mode = 0;
	MS_U8 u8Tdi = 0;

// [5:4] reg_mcd_out_mode
// output mode  -> 00: 2k
//                         01: 4k
//                         10: 8k
#if SOC_LIKE_EXT_DMD
	bRet &= _I2C_READ_BYTE(ISDBT_TDP_REG_BASE + 0x5A * 2, &u8Data);
	u8Mode = u8Data & 0x03;
#else
	bRet &= _I2C_READ_BYTE(ISDBT_TDP_REG_BASE + 0x34 * 2, &u8Data);
	u8Mode = (u8Data >> 4) & 0x03;
#endif

	switch (eLayerIndex) {
	case E_ISDBT_Layer_A:
		// [14:12] reg_tmcc_cur_interleaving_length_a
		bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x04 * 2 + 1, &u8Data);
		u8Tdi = (u8Data >> 4) & 0x07;
		break;
	case E_ISDBT_Layer_B:
		// [14:12] reg_tmcc_cur_interleaving_length_b
		bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x05 * 2 + 1, &u8Data);
		u8Tdi = (u8Data >> 4) & 0x07;
		break;
	case E_ISDBT_Layer_C:
		// [14:12] reg_tmcc_cur_interleaving_length_c
		bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x06 * 2 + 1, &u8Data);
		u8Tdi = (u8Data >> 4) & 0x07;
		break;
	default:
		u8Tdi = 15;
		break;
	}

	// u8Tdi+u8Mode*4
	// => 0~3: 2K
	// => 4~7: 4K
	// => 8~11:8K
	switch (u8Tdi + u8Mode * 4) {
	case 0:
		*peIsdbtTDI = E_ISDBT_2K_TDI_0;
		break;
	case 1:
		*peIsdbtTDI = E_ISDBT_2K_TDI_4;
		break;
	case 2:
		*peIsdbtTDI = E_ISDBT_2K_TDI_8;
		break;
	case 3:
		*peIsdbtTDI = E_ISDBT_2K_TDI_16;
		break;
	case 4:
		*peIsdbtTDI = E_ISDBT_4K_TDI_0;
		break;
	case 5:
		*peIsdbtTDI = E_ISDBT_4K_TDI_2;
		break;
	case 6:
		*peIsdbtTDI = E_ISDBT_4K_TDI_4;
		break;
	case 7:
		*peIsdbtTDI = E_ISDBT_4K_TDI_8;
		break;
	case 8:
		*peIsdbtTDI = E_ISDBT_8K_TDI_0;
		break;
	case 9:
		*peIsdbtTDI = E_ISDBT_8K_TDI_1;
		break;
	case 10:
		*peIsdbtTDI = E_ISDBT_8K_TDI_2;
		break;
	case 11:
		*peIsdbtTDI = E_ISDBT_8K_TDI_4;
		break;
	default:
		*peIsdbtTDI = E_ISDBT_TDI_INVALID;
		break;
	}

	return bRet;
}

static MS_BOOL _HAL_EXTERN_ISDBT_GetSignalFFTValue(enum en_isdbt_fft_val *peIsdbtFFT)
{
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data = 0;
	MS_U8 u8Mode = 0;

// [5:4]  reg_mcd_out_mode
// output mode  -> 00: 2k
//                         01: 4k
//                         10: 8k
#if SOC_LIKE_EXT_DMD
	bRet &= _I2C_READ_BYTE(ISDBT_TDP_REG_BASE + 0x5A * 2, &u8Data);
	u8Mode = u8Data & 0x03;
#else
	bRet &= _I2C_READ_BYTE(ISDBT_TDP_REG_BASE + 0x34 * 2, &u8Data);
	u8Mode = (u8Data >> 4) & 0x03;
#endif

	switch (u8Mode) {
	case 0:
		*peIsdbtFFT = E_ISDBT_FFT_2K;
		break;
	case 1:
		*peIsdbtFFT = E_ISDBT_FFT_4K;
		break;
	case 2:
		*peIsdbtFFT = E_ISDBT_FFT_8K;
		break;
	default:
		*peIsdbtFFT = E_ISDBT_FFT_INVALID;
		break;
	}

	return bRet;
}

static MS_BOOL _HAL_EXTERN_ISDBT_GetSystemIndentificationOfTMCC(
		enum en_isdbt_tmcc_sys_id *peIsdbtSysTMCC)
{
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data = 0;
	MS_U8 u8TmccSysId = 0;
	// [9:8]  reg_tmcc_system_id
	// system id  -> 00: ISDB_T
	//               01: ISDBT_SB
	bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x03 * 2 + 1, &u8Data);
	u8TmccSysId = u8Data & 0x03;

	switch (u8TmccSysId) {
	case 0:
		*peIsdbtSysTMCC = E_ISDBT_TMCC_SYS_ISDB_T;
		break;
	case 1:
		*peIsdbtSysTMCC = E_ISDBT_TMCC_SYS_ISDBT_SB;
		break;
	default:
		*peIsdbtSysTMCC = E_ISDBT_TMCC_SYS_INVALID;
		break;
	}

	return bRet;
}

static MS_BOOL _HAL_EXTERN_ISDBT_GetSignalModulation(
		enum en_isdbt_layer eLayerIndex, enum en_isdbt_constel_type *peIsdbtConstellation)
{
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data = 0;
	MS_U8 u8QAM = 0;

	switch (eLayerIndex) {
	case E_ISDBT_Layer_A:
		// [6:4] reg_tmcc_cur_carrier_modulation_a
		bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x04 * 2, &u8Data);
		u8QAM = (u8Data >> 4) & 0x07;
		break;
	case E_ISDBT_Layer_B:
		// [6:4] reg_tmcc_cur_carrier_modulation_b
		bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x05 * 2, &u8Data);
		u8QAM = (u8Data >> 4) & 0x07;
		break;
	case E_ISDBT_Layer_C:
		// [6:4] reg_tmcc_cur_carrier_modulation_c
		bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x06 * 2, &u8Data);
		u8QAM = (u8Data >> 4) & 0x07;
		break;
	default:
		u8QAM = 15;
		break;
	}

	switch (u8QAM) {
	case 0:
		*peIsdbtConstellation = E_ISDBT_DQPSK;
		break;
	case 1:
		*peIsdbtConstellation = E_ISDBT_QPSK;
		break;
	case 2:
		*peIsdbtConstellation = E_ISDBT_16QAM;
		break;
	case 3:
		*peIsdbtConstellation = E_ISDBT_64QAM;
		break;
	default:
		*peIsdbtConstellation = E_ISDBT_QAM_INVALID;
		break;
	}

	return bRet;
}

static MS_U8 _HAL_EXTERN_ISDBT_ReadIFAGC(void)
{
	MS_U8 data = 0;

#if !SOC_LIKE_EXT_DMD
	// debug select
	_I2C_WRITE_BYTE(ISDBT_FE_REG_BASE + 0x13 * 2, 0x03);

	// set freeze & dump [Write]
	_I2C_WRITE_BYTE(ISDBT_FE_REG_BASE + 0x02 * 2 + 1, 0x80);

	// Read High Byte of IF AGC
	_I2C_READ_BYTE(ISDBT_FE_REG_BASE + 0x14 * 2 + 1, &data);

	// Unfreeze & dump [Write]
	_I2C_WRITE_BYTE(ISDBT_FE_REG_BASE + 0x02 * 2 + 1, 0x00);
#else
	//_I2C_READ_BYTE(ISDBT_FE_REG_BASE+0xFD, &data);

	// debug select
	_I2C_WRITE_BYTE(ISDBT_FE_REG_BASE + 0x11 * 2, 0x03);

	// set freeze & dump [Write]
	_I2C_WRITE_BYTE(ISDBT_FE_REG_BASE + 0x02 * 2 + 1, 0x80);

	// Read High Byte of IF AGC
	_I2C_READ_BYTE(ISDBT_FE_REG_BASE + 0x12 * 2 + 1, &data);

	// Unfreeze & dump [Write]
	_I2C_WRITE_BYTE(ISDBT_FE_REG_BASE + 0x02 * 2 + 1, 0x00);
#endif

	return data;
}

static MS_U8 _HAL_EXTERN_ISDBT_ReadIndicatorOfTransmissionParameterSwitch(void)
{
	MS_U8 data = 0;
	MS_U8 u8Countdown = 0;
	// [15:12] reg_tmcc_transmission_para_switch
	// transmission_para_switch  -> 1111: normal calue

	_I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x03 * 2 + 1, &data);
	u8Countdown = (data >> 4) & 0x0F;

	return u8Countdown;
}

static MS_U8 _HAL_EXTERN_ISDBT_GetNumberOfSegmentsOfLayerA(void)
{
	MS_U8 data = 0;
	MS_U8 u8Numofsegments_layerA = 0;
	// [3:0] reg_tmcc_cur_number_of_segmants_a

	_I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x05 * 2, &data);
	data = (data & 0x0F);

	if ((data != 0x0F) && (data != 0x00))
		u8Numofsegments_layerA = data;
	else
		u8Numofsegments_layerA = 0;

	return u8Numofsegments_layerA;
}

static MS_U8 _HAL_EXTERN_ISDBT_GetNumberOfSegmentsOfLayerB(void)
{
	MS_U8 data = 0;
	MS_U8 u8Numofsegments_layerB = 0;
	// [3:0] reg_tmcc_cur_number_of_segmants_b

	_I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x06 * 2, &data);
	data = (data & 0x0F);

	if ((data != 0x0F) && (data != 0x00))
		u8Numofsegments_layerB = data;
	else
		u8Numofsegments_layerB = 0;

	return u8Numofsegments_layerB;
}

static MS_U8 _HAL_EXTERN_ISDBT_GetNumberOfSegmentsOfLayerC(void)
{
	MS_U8 data = 0;
	MS_U8 u8Numofsegments_layerC = 0;
	// [3:0] reg_tmcc_cur_number_of_segmants_c

	_I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x07 * 2, &data);
	data = (data & 0x0F);

	if ((data != 0x0F) && (data != 0x00))
		u8Numofsegments_layerC = data;
	else
		u8Numofsegments_layerC = 0;

	return u8Numofsegments_layerC;
}

static MS_U8 _HAL_EXTERN_ISDBT_GetPhaseShiftCorrectionValue(void)
{
	MS_U8 data = 0;
	MS_U8 u8Phaseshiftcorrection_value = 0;
	// [6:4] reg_tmcc_phase_shift_correction
	// tmcc_phase_shift_correction  -> 111: 1 for all bits

	_I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x0a * 2, &data);
	u8Phaseshiftcorrection_value = (data >> 4) & 0x07;

	return u8Phaseshiftcorrection_value;
}

static MS_BOOL _HAL_EXTERN_ISDBT_GetPartialReceptionFlag(
		MS_BOOL *pbPartialReceptionFlag)
{
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data = 0;

	bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x04 * 2, &u8Data);
	*pbPartialReceptionFlag = (u8Data >> 2) & 0x01;

	return bRet;
}

#ifdef UTPA2
static MS_BOOL _HAL_EXTERN_ISDBT_GetFreqOffset(
		MS_U8 *pFFT_Mode, MS_S32 *pTdCfoRegValue,
		MS_S32 *pFdCfoRegValue,
		MS_S16 *pIcfoRegValue)
#else
static MS_BOOL _HAL_EXTERN_ISDBT_GetFreqOffset(float *pFreqOff)
#endif
{
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data;
	MS_S32 s32TdCfoRegValue = 0;
	MS_S32 s32FdCfoRegValue = 0;
	MS_S16 s16IcfoRegValue = 0;
#ifndef UTPA2
	float fTdCfoFreq = 0.0;
	float fICfoFreq = 0.0;
	float fFdCfoFreq = 0.0;
#endif

	// Get TD CFO
	bRet &= _I2C_READ_BYTE(ISDBT_TDP_REG_BASE + 0x04, &u8Data); // 0x02 * 2
	bRet &= _I2C_WRITE_BYTE(ISDBT_TDP_REG_BASE + 0x04, (u8Data | 0x01));

	// read td_freq_error
	// Read <29,38>
	bRet &= _I2C_READ_BYTE(ISDBT_TDP_REG_BASE + 0x8A, &u8Data); // 0x45 * 2
	s32TdCfoRegValue = u8Data;
	bRet &= _I2C_READ_BYTE(ISDBT_TDP_REG_BASE + 0x8B, &u8Data); // 0x45 * 2 + 1
	s32TdCfoRegValue |= u8Data << 8;
	bRet &= _I2C_READ_BYTE(ISDBT_TDP_REG_BASE + 0x8C, &u8Data); // 0x46 * 2
	s32TdCfoRegValue = u8Data << 16;
	bRet &= _I2C_READ_BYTE(ISDBT_TDP_REG_BASE + 0x8D, &u8Data); // 0x46 * 2 + 1
	s32TdCfoRegValue |= u8Data << 24;

	if (u8Data >= 0x10)
		s32TdCfoRegValue = 0xE0000000 | s32TdCfoRegValue;

	s32TdCfoRegValue >>= 4;

	// TD_cfo_Hz = RegCfoTd * fb
	bRet &= _I2C_READ_BYTE(ISDBT_TDP_REG_BASE + 0x04, &u8Data); // 0x02 * 2
	bRet &= _I2C_WRITE_BYTE(ISDBT_TDP_REG_BASE + 0x04, (u8Data & ~0x01));

#ifndef UTPA2
	fTdCfoFreq = ((float)s32TdCfoRegValue) / 17179869184.0; //<25,34>
	fTdCfoFreq = fTdCfoFreq * 8126980.0;
#endif

	// Get FD CFO
	bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0xFE, &u8Data); // 0x7f * 2
	bRet &= _I2C_WRITE_BYTE(ISDBT_FDP_REG_BASE + 0xFE, (u8Data | 0x01));
	// load
	bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0xFF, &u8Data); // 0x7f * 2 + 1
	bRet &= _I2C_WRITE_BYTE(ISDBT_FDP_REG_BASE + 0xFF, (u8Data | 0x01));

	// read CFO_KI
	bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x5E, &u8Data); // 0x2F * 2
	s32FdCfoRegValue = u8Data;
	bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x5F, &u8Data); // 0x2F * 2 + 1
	s32FdCfoRegValue |= u8Data << 8;
	bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x60, &u8Data); // 0x30 * 2
	s32FdCfoRegValue |= u8Data << 16;
	bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x61, &u8Data); // 0x30 * 2
	s32FdCfoRegValue |= u8Data << 24;

	if (u8Data >= 0x01)
		s32FdCfoRegValue = 0xFE000000 | s32FdCfoRegValue;

	bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0xFE, &u8Data); // 0x7f * 2
	bRet &= _I2C_WRITE_BYTE(ISDBT_FDP_REG_BASE + 0xFE, (u8Data & ~0x01));
	// load
	bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0xFF, &u8Data); // 0x7f * 2 + 1
	bRet &= _I2C_WRITE_BYTE(ISDBT_FDP_REG_BASE + 0xFF, (u8Data | 0x01));

#ifndef UTPA2
	fFdCfoFreq = ((float)s32FdCfoRegValue) / 17179869184.0;
	fFdCfoFreq = fFdCfoFreq * 8126980.0;
#endif

	// Get ICFO
	bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x5C, &u8Data); // 0x2E * 2
	s16IcfoRegValue = u8Data;
	bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0x5D, &u8Data); // 0x2E * 2 + 1
	s16IcfoRegValue |= u8Data << 8;
	s16IcfoRegValue = (s16IcfoRegValue >> 4) & 0x07FF;

	if (s16IcfoRegValue >= 0x400)
		s16IcfoRegValue = s16IcfoRegValue | 0xFFFFF800;

#if SOC_LIKE_EXT_DMD
	bRet &= _I2C_READ_BYTE(ISDBT_TDP_REG_BASE + 0x5A * 2, &u8Data);
	u8Data = u8Data << 4;
#else
	bRet &= _I2C_READ_BYTE(ISDBT_TDP_REG_BASE + 0x68, &u8Data); // 0x34 * 2
#endif

#ifdef UTPA2
	*pFFT_Mode = u8Data;
	*pTdCfoRegValue = s32TdCfoRegValue;
	*pFdCfoRegValue = s32FdCfoRegValue;
	*pIcfoRegValue = s16IcfoRegValue;
#else
	if ((u8Data & 0x30) == 0x0000) // 2k
		fICfoFreq = (float)s16IcfoRegValue * 250000.0 / 63.0;
	else if ((u8Data & 0x0030) == 0x0010) // 4k
		fICfoFreq = (float)s16IcfoRegValue * 125000.0 / 63.0;
	else // if(u16data & 0x0030 == 0x0020) // 8k
		fICfoFreq = (float)s16IcfoRegValue * 125000.0 / 126.0;

	*pFreqOff = fTdCfoFreq + fFdCfoFreq + fICfoFreq;

	pr_info("[%s][%d] *pExtChipChId = %d, Total CFO value = %f\n", __func__, __LINE__,
			*pExtChipChId, *pFreqOff);
#endif

	return bRet;
}

#ifdef UTPA2
static MS_BOOL _HAL_EXTERN_ISDBT_GetPreViterbiBer(
		enum en_isdbt_layer eLayerIndex, MS_U32 *pBerValue, MS_U16 *pBerPeriod)
#else
static MS_BOOL _HAL_EXTERN_ISDBT_GetPreViterbiBer(enum en_isdbt_layer eLayerIndex, float *pfber)
#endif
{
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data = 0;
	MS_U16 u16BerValue = 0;
	MS_U32 u32BerPeriod = 0;

	// reg_rd_freezeber
	bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x60, &u8Data);
	bRet &= _I2C_WRITE_BYTE(ISDBT_OUTER_REG_BASE + 0x60, u8Data | 0x10);

	if (eLayerIndex == E_ISDBT_Layer_A) {
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x90, &u8Data); // 0x48 * 2
		u16BerValue = u8Data;
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x91, &u8Data); // 0x48 * 2+1
		u16BerValue |= (u8Data << 8);
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x76, &u8Data); // 0x3b * 2
		u32BerPeriod = (u8Data & 0x3F);
		u32BerPeriod <<= 16;
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x70, &u8Data); // 0x38 * 2
		u32BerPeriod |= u8Data;
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x70, &u8Data); // 0x38 * 2 +1
		u32BerPeriod |= (u8Data << 8);
	} else if (eLayerIndex == E_ISDBT_Layer_B) {
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x92, &u8Data); // 0x49 * 2
		u16BerValue = u8Data;
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x93, &u8Data); // 0x49 * 2+1
		u16BerValue |= (u8Data << 8);
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x77, &u8Data); // 0x3b * 2 + 1
		u32BerPeriod = (u8Data & 0x3F);
		u32BerPeriod <<= 16;
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x72, &u8Data); // 0x39 * 2
		u32BerPeriod |= u8Data;
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x73, &u8Data); // 0x39 * 2 +1
		u32BerPeriod |= (u8Data << 8);
	} else if (eLayerIndex == E_ISDBT_Layer_C) {
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x94, &u8Data); // 0x4A * 2
		u16BerValue = u8Data;
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x95, &u8Data); // 0x4A * 2+1
		u16BerValue |= (u8Data << 8);
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x78, &u8Data); // 0x3C
		u32BerPeriod = (u8Data & 0x003F);
		u32BerPeriod <<= 16;
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x74, &u8Data); // 0x3A * 2
		u32BerPeriod |= u8Data;
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x75, &u8Data); // 0x3A * 2 +1
		u32BerPeriod |= (u8Data << 8);
	} else {
		pr_info("[%s][%d] *pExtChipChId = %d, Please select correct Layer\n",
			__func__, __LINE__, *pExtChipChId);
		bRet = FALSE;
	}

	// reg_rd_freezeber
	bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x60, &u8Data);
	bRet &= _I2C_WRITE_BYTE(ISDBT_OUTER_REG_BASE + 0x60, (u8Data & ~0x10));

	u32BerPeriod <<= 8; // *256

	if (u32BerPeriod == 0)
		u32BerPeriod = 1;

#ifdef UTPA2
	*pBerPeriod = u32BerPeriod;
	*pBerValue = u16BerValue;
#else
	*pfber = (float)u16BerValue / u32BerPeriod;

	pr_info("[%s][%d] *pExtChipChId = %d, Layer: 0x%x, Pre-Ber = %e\n", __func__, __LINE__,
			*pExtChipChId, eLayerIndex, *pfber);
#endif

	return bRet;
}

#ifdef UTPA2
static MS_BOOL _HAL_EXTERN_ISDBT_GetPostViterbiBer(
		enum en_isdbt_layer eLayerIndex, MS_U32 *pBerValue, MS_U16 *pBerPeriod)
#else
static MS_BOOL _HAL_EXTERN_ISDBT_GetPostViterbiBer(enum en_isdbt_layer eLayerIndex, float *pfber)
#endif
{
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data = 0;
	MS_U8 u8FrzData = 0;
	MS_U32 u32BerValue = 0;
	MS_U16 u16BerPeriod = 0;

	// dbg
	// PRINT("\r\n ===== _HAL_EXTERN_ISDBT_GetPostViterbiBer_Start ===== \r\n");

	bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x01 * 2 + 1, &u8FrzData);
	u8Data = u8FrzData | 0x01;
	bRet &= _I2C_WRITE_BYTE(ISDBT_OUTER_REG_BASE + 0x01 * 2 + 1, u8Data);

	if (eLayerIndex == E_ISDBT_Layer_A) {
		// dbg
		// PRINT("\r\n ===== _HAL_EXTERN_ISDBT_GetPostViterbiBer_Start_LayerA ===== \r\n");
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x22, &u8Data);
		if ((u8Data & 0x03) == 0) {
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0xA4, &u8Data); // 0x52 * 2
			u32BerValue = u8Data;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0xA5, &u8Data); // 0x53 * 2+1
			u32BerValue |= u8Data << 8;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0xA6, &u8Data); // 0x54 * 2
			u32BerValue |= u8Data << 16;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0xA7, &u8Data); // 0x55 * 2+1
			u32BerValue |= u8Data << 24;
		} else {
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x14, &u8Data); // 0x0A * 2
			u32BerValue = u8Data;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x15, &u8Data); // 0x0A * 2+1
			u32BerValue |= u8Data << 8;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x16, &u8Data); // 0x0B * 2
			u32BerValue |= u8Data << 16;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x17, &u8Data); // 0x0B * 2+1
			u32BerValue |= u8Data << 24;
		}
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x0A, &u8Data); // 0x05 * 2
		u16BerPeriod = u8Data;
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x0B, &u8Data); // 0x05 * 2+1
		u16BerPeriod |= u8Data << 8;

		// dbg
		// PRINT("\r\n ===== _HAL_EXTERN_ISDBT_GetPostViterbiBer_End_LayerA ===== \r\n");
	} else if (eLayerIndex == E_ISDBT_Layer_B) {
		// dbg
		// PRINT("\r\n ===== _HAL_EXTERN_ISDBT_GetPostViterbiBer_Start_LayerB ===== \r\n");
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x22, &u8Data);
		if ((u8Data & 0x03) == 0) {
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0xA4, &u8Data); // 0x52 * 2
			u32BerValue = u8Data;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0xA5, &u8Data); // 0x53 * 2+1
			u32BerValue |= u8Data << 8;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0xA6, &u8Data); // 0x54 * 2
			u32BerValue |= u8Data << 16;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0xA7, &u8Data); // 0x55 * 2+1
			u32BerValue |= u8Data << 24;
		} else {
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x46, &u8Data); // 0x23 * 2
			u32BerValue = u8Data;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x47, &u8Data); // 0x23 * 2+1
			u32BerValue |= u8Data << 8;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x48, &u8Data); // 0x24 * 2
			u32BerValue |= u8Data << 16;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x49, &u8Data); // 0x24 * 2+1
			u32BerValue |= u8Data << 24;
		}
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x3A, &u8Data); // 0x1d * 2
		u16BerPeriod = u8Data;
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x3B, &u8Data); // 0x1d * 2+1
		u16BerPeriod |= u8Data << 8;

		// dbg
		// PRINT("\r\n ===== _HAL_EXTERN_ISDBT_GetPostViterbiBer_End_LayerB ===== \r\n");
	} else if (eLayerIndex == E_ISDBT_Layer_C) {
		// dbg
		// PRINT("\r\n ===== _HAL_EXTERN_ISDBT_GetPostViterbiBer_Start_LayerC ===== \r\n");
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x22, &u8Data);
		if ((u8Data & 0x03) == 0) {
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0xA4, &u8Data); // 0x52 * 2
			u32BerValue = u8Data;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0xA5, &u8Data); // 0x53 * 2+1
			u32BerValue |= u8Data << 8;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0xA6, &u8Data); // 0x54 * 2
			u32BerValue |= u8Data << 16;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0xA7, &u8Data); // 0x55 * 2+1
			u32BerValue |= u8Data << 24;
		} else {
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x88, &u8Data); // 0x44 * 2
			u32BerValue = u8Data;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x89, &u8Data); // 0x44 * 2+1
			u32BerValue |= u8Data << 8;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x8A, &u8Data); // 0x45 * 2
			u32BerValue |= u8Data << 16;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x8B, &u8Data); // 0x45 * 2+1
			u32BerValue |= u8Data << 24;
		}
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x3E, &u8Data); // 0x1f * 2
		u16BerPeriod = u8Data;
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x3F, &u8Data); // 0x1d * 2+1
		u16BerPeriod |= u8Data << 8;

		// dbg
		// PRINT("\r\n ===== _HAL_EXTERN_ISDBT_GetPostViterbiBer_End_LayerC ===== \r\n");
	} else {
		pr_info("[%s][%d] *pExtChipChId = %d, Please select correct Layer\n",
			__func__, __LINE__, *pExtChipChId);
		bRet = FALSE;
	}

	// reg_rd_freezeber
	bRet &= _I2C_WRITE_BYTE(ISDBT_OUTER_REG_BASE + 0x01 * 2 + 1, u8FrzData);

	if (u16BerPeriod == 0)
		u16BerPeriod = 1;

#ifdef UTPA2
	*pBerPeriod = u16BerPeriod;
	*pBerValue = u32BerValue;
#else
	*pfber = (float)u32BerValue / u16BerPeriod / (128.0 * 188.0 * 8.0);

	pr_info("[%s][%d] *pExtChipChId = %d, Layer: 0x%x, Post-Ber = %e\n", __func__, __LINE__,
			*pExtChipChId, eLayerIndex, *pfber);
#endif
	// dbg
	// PRINT("\r\n ===== _HAL_EXTERN_ISDBT_GetPostViterbiBer_End ===== \r\n");

	return bRet;
}

static MS_U16 _HAL_EXTERN_ISDBT_GetSignalQualityOfLayerA(void)
{
#ifdef UTPA2
	MS_U32 BerValue = 0;
	MS_U16 BerPeriod = 0;
#else
	float fber;
#endif
	MS_BOOL bRet = TRUE;
	enum en_isdbt_layer eLayerIndex;
	MS_U16 u16SQI;

	// Tmp solution
	eLayerIndex = E_ISDBT_Layer_A;

	if (_HAL_EXTERN_ISDBT_Check_FEC_Lock() == FALSE) {
		// PRINT("Dan Demod unlock!!!\n");
		u16SQI = 0;
	} else {
// Part 1: get ber value from demod.
#ifdef UTPA2
		bRet &= _HAL_EXTERN_ISDBT_GetPostViterbiBer(eLayerIndex, &BerValue, &BerPeriod);

		u16SQI = _CALCULATE_SQI(BerValue, BerPeriod * 128 * 188 * 8);
#else
		bRet &= _HAL_EXTERN_ISDBT_GetPostViterbiBer(eLayerIndex, &fber);

		u16SQI = _CALCULATE_SQI(fber);
#endif
	}

	// PRINT("dan SQI = %d\n", SQI);
	return u16SQI;
}

static MS_U16 _HAL_EXTERN_ISDBT_GetSignalQualityOfLayerB(void)
{
#ifdef UTPA2
	MS_U32 BerValue = 0;
	MS_U16 BerPeriod = 0;
#else
	float fber;
#endif
	MS_BOOL bRet = TRUE;
	enum en_isdbt_layer eLayerIndex;
	MS_U16 u16SQI;

	// Tmp solution
	eLayerIndex = E_ISDBT_Layer_B;

	if (_HAL_EXTERN_ISDBT_Check_FEC_Lock() == FALSE) {
		// PRINT("Dan Demod unlock!!!\n");
		u16SQI = 0;
	} else {
// Part 1: get ber value from demod.
#ifdef UTPA2
		bRet &= _HAL_EXTERN_ISDBT_GetPostViterbiBer(eLayerIndex, &BerValue, &BerPeriod);

		u16SQI = _CALCULATE_SQI(BerValue, BerPeriod * 128 * 188 * 8);
#else
		bRet &= _HAL_EXTERN_ISDBT_GetPostViterbiBer(eLayerIndex, &fber);

		u16SQI = _CALCULATE_SQI(fber);
#endif
	}

	// PRINT("dan SQI = %d\n", SQI);
	return u16SQI;
}

static MS_U16 _HAL_EXTERN_ISDBT_GetSignalQualityOfLayerC(void)
{
#ifdef UTPA2
	MS_U32 BerValue = 0;
	MS_U16 BerPeriod = 0;
#else
	float fber;
#endif
	MS_BOOL bRet = TRUE;
	enum en_isdbt_layer eLayerIndex;
	MS_U16 u16SQI;

	// Tmp solution
	eLayerIndex = E_ISDBT_Layer_C;

	if (_HAL_EXTERN_ISDBT_Check_FEC_Lock() == FALSE) {
		// PRINT("Dan Demod unlock!!!\n");
		u16SQI = 0;
	} else {
// Part 1: get ber value from demod.
#ifdef UTPA2
		bRet &= _HAL_EXTERN_ISDBT_GetPostViterbiBer(eLayerIndex, &BerValue, &BerPeriod);

		u16SQI = _CALCULATE_SQI(BerValue, BerPeriod * 128 * 188 * 8);
#else
		bRet &= _HAL_EXTERN_ISDBT_GetPostViterbiBer(eLayerIndex, &fber);

		u16SQI = _CALCULATE_SQI(fber);
#endif
	}

	// PRINT("dan SQI = %d\n", SQI);
	return u16SQI;
}

static MS_U16 _HAL_EXTERN_ISDBT_GetSignalQualityOfLayerCombine(void)
{
	MS_S8 s8LayerAValue = 0, s8LayerBValue = 0, s8LayerCValue = 0;
	MS_U16 u16SQI;
	enum en_isdbt_layer eLayerIndex;
	enum en_isdbt_constel_type eIsdbtConstellationA, eIsdbtConstellationB, eIsdbtConstellationC;

	// Get modulation of each layer
	eLayerIndex = E_ISDBT_Layer_A;
	_HAL_EXTERN_ISDBT_GetSignalModulation(eLayerIndex, &eIsdbtConstellationA);
	eLayerIndex = E_ISDBT_Layer_B;
	_HAL_EXTERN_ISDBT_GetSignalModulation(eLayerIndex, &eIsdbtConstellationB);
	eLayerIndex = E_ISDBT_Layer_C;
	_HAL_EXTERN_ISDBT_GetSignalModulation(eLayerIndex, &eIsdbtConstellationC);

	if (eIsdbtConstellationA != E_ISDBT_QAM_INVALID)
		s8LayerAValue = (MS_S8)eIsdbtConstellationA;
	else
		s8LayerAValue = -1;

	if (eIsdbtConstellationB != E_ISDBT_QAM_INVALID)
		s8LayerBValue = (MS_S8)eIsdbtConstellationB;
	else
		s8LayerBValue = -1;

	if (eIsdbtConstellationC != E_ISDBT_QAM_INVALID)
		s8LayerCValue = (MS_S8)eIsdbtConstellationC;
	else
		s8LayerCValue = -1;

	// PRINT("Layer info A:%d, B:%d, C:%d\n", s8LayerAValue, s8LayerBValue, s8LayerCValue);
	if (s8LayerAValue >= s8LayerBValue) {
		if (s8LayerCValue >= s8LayerAValue) {
			// Get Layer C u16SQI
			u16SQI = _HAL_EXTERN_ISDBT_GetSignalQualityOfLayerC();
			// PRINT("dan u16SQI Layer C1: %d\n", u16SQI);
		} else {
			// A>C

			// Get Layer A u16SQI
			u16SQI = _HAL_EXTERN_ISDBT_GetSignalQualityOfLayerA();
			// PRINT("dan u16SQI Layer A: %d\n", u16SQI);
		}
	} else {
		// B >= A

		if (s8LayerCValue >= s8LayerBValue) {
			// Get Layer C u16SQI
			u16SQI = _HAL_EXTERN_ISDBT_GetSignalQualityOfLayerC();
			// PRINT("dan u16SQI Layer C2: %d\n", u16SQI);
		} else {
			// B>C
			// Get Layer B u16SQI
			u16SQI = _HAL_EXTERN_ISDBT_GetSignalQualityOfLayerB();
			// PRINT("dan u16SQI Layer B: %d\n", u16SQI);
		}
	}

	return u16SQI;
}

#ifdef UTPA2
static MS_BOOL _HAL_EXTERN_ISDBT_GetSNR(MS_U32 *pRegSNR, MS_U16 *pRegSnrObsNum)
#else
static MS_BOOL _HAL_EXTERN_ISDBT_GetSNR(float *pf_snr)
#endif
{
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data = 0;
	MS_U32 u32RegSNR = 0;
	MS_U16 u16RegSnrObsNum = 0;
#ifndef UTPA2
	float fSNRAvg = 0.0;
#endif

	// set freeze
	bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0xFE, &u8Data); // 0x7f * 2
	bRet &= _I2C_WRITE_BYTE(ISDBT_FDP_REG_BASE + 0xFE, (u8Data | 0x01));
	// load
	bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0xFF, &u8Data); // 0x7f * 2 + 1
	bRet &= _I2C_WRITE_BYTE(ISDBT_FDP_REG_BASE + 0xFF, (u8Data | 0x01));

	// ==============Average SNR===============//
	// [26:0] reg_snr_accu
	bRet &= _I2C_READ_BYTE(ISDBT_FDPEXT_REG_BASE + 0x2d * 2 + 1, &u8Data);
	u32RegSNR = u8Data & 0x07;
	bRet &= _I2C_READ_BYTE(ISDBT_FDPEXT_REG_BASE + 0x2d * 2, &u8Data);
	u32RegSNR = (u32RegSNR << 8) | u8Data;
	bRet &= _I2C_READ_BYTE(ISDBT_FDPEXT_REG_BASE + 0x2c * 2 + 1, &u8Data);
	u32RegSNR = (u32RegSNR << 8) | u8Data;
	bRet &= _I2C_READ_BYTE(ISDBT_FDPEXT_REG_BASE + 0x2c * 2, &u8Data);
	u32RegSNR = (u32RegSNR << 8) | u8Data;

	// [12:0] reg_snr_observe_sum_num
	bRet &= _I2C_READ_BYTE(ISDBT_FDPEXT_REG_BASE + 0x2a * 2 + 1, &u8Data);
	u16RegSnrObsNum = u8Data & 0x1f;
	bRet &= _I2C_READ_BYTE(ISDBT_FDPEXT_REG_BASE + 0x2a * 2, &u8Data);
	u16RegSnrObsNum = (u16RegSnrObsNum << 8) | u8Data;

	// release freeze
	bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0xFE, &u8Data); // 0x7f * 2
	bRet &= _I2C_WRITE_BYTE(ISDBT_FDP_REG_BASE + 0xFE, (u8Data & ~0x01));
	// load
	bRet &= _I2C_READ_BYTE(ISDBT_FDP_REG_BASE + 0xFF, &u8Data); // 0x7f * 2 + 1
	bRet &= _I2C_WRITE_BYTE(ISDBT_FDP_REG_BASE + 0xFF, (u8Data | 0x01));

	if (u16RegSnrObsNum == 0)
		u16RegSnrObsNum = 1;

#ifdef UTPA2
	*pRegSNR = 10 * Log10Approx(u32RegSNR / u16RegSnrObsNum / 2);
	pr_info("[%s][%d] *pExtChipChId = %d, SNR*100 value = %u\n",
		__func__, __LINE__, *pExtChipChId, *pRegSNR);
#else
	fSNRAvg = (float)u32RegSNR / u16RegSnrObsNum;

	if (fSNRAvg == 0) // protect value 0
		fSNRAvg = 0.01;

#ifdef MSOS_TYPE_LINUX
	*pf_snr = 10 * (float)log10f((double)fSNRAvg / 2);
#else
	*pf_snr = 10 * (float)Log10Approx((double)fSNRAvg / 2);
#endif

	pr_info("[%s][%d] *pExtChipChId = %d,SNR value = %f\n", __func__, __LINE__, *pExtChipChId,
			*pf_snr);
#endif

	return bRet;
}

static MS_BOOL _HAL_EXTERN_ISDBT_Read_PKT_ERR(
		enum en_isdbt_layer eLayerIndex, MS_U16 *pu16PacketErr)
{
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data = 0;
	MS_U8 u8FrzData = 0;
	MS_U16 u16PacketErrA = 0xFFFF, u16PacketErrB = 0xFFFF, u16PacketErrC = 0xFFFF;
#if DMD_ISDBT_TBVA_EN
	MS_U8 bTbvaBypass = 0;
	MS_U8 u8TbvaLayer = 0;
#endif

	// Read packet errors of three layers
	// OUTER_FUNCTION_ENABLE
	// [8] reg_biterr_num_pcktprd_freeze
	// Freeze Packet error
	bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x01 * 2 + 1, &u8FrzData);
	u8Data = u8FrzData | 0x01;
	bRet &= _I2C_WRITE_BYTE(ISDBT_OUTER_REG_BASE + 0x01 * 2 + 1, u8Data);

#if DMD_ISDBT_TBVA_EN
	bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x10 * 2, &u8Data);
	bTbvaBypass = u8Data & 0x01;
	bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x11 * 2, &u8Data);
	u8TbvaLayer = u8Data & 0x03;
	switch (eLayerIndex) {
	case E_ISDBT_Layer_A:
		// [15:0] OUTER_UNCRT_PKT_NUM_PCKTPRD_A
		if (!bTbvaBypass && u8TbvaLayer == 0) {
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x17 * 2 + 1, &u8Data);
			u16PacketErrA = u8Data << 8;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x17 * 2, &u8Data);
			u16PacketErrA = u16PacketErrA | u8Data;
			*pu16PacketErr = u16PacketErrA;
		} else {
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x08 * 2 + 1, &u8Data);
			u16PacketErrA = u8Data << 8;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x08 * 2, &u8Data);
			u16PacketErrA = u16PacketErrA | u8Data;
			*pu16PacketErr = u16PacketErrA;
		}
		break;
	case E_ISDBT_Layer_B:
		// [15:0] OUTER_UNCRT_PKT_NUM_PCKTPRD_B
		if (!bTbvaBypass && u8TbvaLayer == 1) {
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x17 * 2 + 1, &u8Data);
			u16PacketErrB = u8Data << 8;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x17 * 2, &u8Data);
			u16PacketErrB = u16PacketErrB | u8Data;
			*pu16PacketErr = u16PacketErrB;
		} else {
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x21 * 2 + 1, &u8Data);
			u16PacketErrB = u8Data << 8;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x21 * 2, &u8Data);
			u16PacketErrB = u16PacketErrB | u8Data;
			*pu16PacketErr = u16PacketErrB;
		}
		break;
	case E_ISDBT_Layer_C:
		// [15:0] OUTER_UNCRT_PKT_NUM_PCKTPRD_C
		if (!bTbvaBypass && u8TbvaLayer == 2) {
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x17 * 2 + 1, &u8Data);
			u16PacketErrC = u8Data << 8;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x17 * 2, &u8Data);
			u16PacketErrC = u16PacketErrC | u8Data;
			*pu16PacketErr = u16PacketErrC;
		} else {
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x42 * 2 + 1, &u8Data);
			u16PacketErrC = u8Data << 8;
			bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x42 * 2, &u8Data);
			u16PacketErrC = u16PacketErrC | u8Data;
			*pu16PacketErr = u16PacketErrC;
		}
		break;
	default:
		*pu16PacketErr = 0xFFFF;
		break;
	}
#else
	switch (eLayerIndex) {
	case E_ISDBT_Layer_A:
		// [15:0] OUTER_UNCRT_PKT_NUM_PCKTPRD_A
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x08 * 2 + 1, &u8Data);
		u16PacketErrA = u8Data << 8;
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x08 * 2, &u8Data);
		u16PacketErrA = u16PacketErrA | u8Data;
		*pu16PacketErr = u16PacketErrA;
		pr_info("[%s][%d] *pExtChipChId = %d, E_ISDBT_Layer_A, *pu16PacketErr = %d\n",
			__func__, __LINE__, *pExtChipChId, (int)*pu16PacketErr);
		break;
	case E_ISDBT_Layer_B:
		// [15:0] OUTER_UNCRT_PKT_NUM_PCKTPRD_B
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x21 * 2 + 1, &u8Data);
		u16PacketErrB = u8Data << 8;
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x21 * 2, &u8Data);
		u16PacketErrB = u16PacketErrB | u8Data;
		*pu16PacketErr = u16PacketErrB;
		pr_info("[%s][%d] *pExtChipChId = %d, E_ISDBT_Layer_B, *pu16PacketErr = %d\n",
			__func__, __LINE__, *pExtChipChId, (int)*pu16PacketErr);
		break;
	case E_ISDBT_Layer_C:
		// [15:0] OUTER_UNCRT_PKT_NUM_PCKTPRD_C
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x42 * 2 + 1, &u8Data);
		u16PacketErrC = u8Data << 8;
		bRet &= _I2C_READ_BYTE(ISDBT_OUTER_REG_BASE + 0x42 * 2, &u8Data);
		u16PacketErrC = u16PacketErrC | u8Data;
		*pu16PacketErr = u16PacketErrC;
		pr_info("[%s][%d] *pExtChipChId = %d, E_ISDBT_Layer_C, *pu16PacketErr = %d\n",
			__func__, __LINE__, *pExtChipChId, (int)*pu16PacketErr);
		break;
	default:
		*pu16PacketErr = 0xFFFF;
		break;
	}
#endif

	// Unfreeze Packet error
	bRet &= _I2C_WRITE_BYTE(ISDBT_OUTER_REG_BASE + 0x01 * 2 + 1, u8FrzData);

	return bRet;
}

static MS_BOOL _HAL_EXTERN_ISDBT_SetSerialControl(void)
{
	MS_BOOL bResult = TRUE;
	MS_U8 u8TsConfigData = 0;
	MS_U8 u8TmpData = 0;
	MS_U8 u8ReadData = 0;
	MS_U16 u16TSConfigDataAddr = 0;
	MS_U32 u32Address = 0;

	pr_info("[%s][%d] *pExtChipChId = %d, __entry__\n", __func__, __LINE__, *pExtChipChId);

	// Set DMD_ISDBT_TS_DRIVE_STRENGTH_3:
	bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x2A * 2 + 0, 0xFF);
	bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x2A * 2 + 1, 0x07);
	bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x2C * 2 + 0, 0xFF);
	bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x2C * 2 + 1, 0x07);

	pRes->sdmd_isdbt_initdata.ts_config_byte_2bit_serial = 1;
	pRes->sdmd_isdbt_initdata.ts_config_byte_div_num = 2;
	pRes->sdmd_isdbt_initdata.ts_config_byte_clock_inv = 1;
	pRes->sdmd_isdbt_initdata.ts_config_byte_data_swap = 0;
	pRes->sdmd_isdbt_initdata.ts_config_byte_serial_mode = 1;

	u8TsConfigData = (pRes->sdmd_isdbt_initdata.ts_config_byte_2bit_serial << 7) |
					 (pRes->sdmd_isdbt_initdata.ts_config_byte_div_num << 3) |
					 (pRes->sdmd_isdbt_initdata.ts_config_byte_clock_inv << 2) |
					 (pRes->sdmd_isdbt_initdata.ts_config_byte_data_swap << 1) |
					 (pRes->sdmd_isdbt_initdata.ts_config_byte_serial_mode);

	if (*pExtChipChId == 0) {
		bResult &= _I2C_READ_BYTE(TOP_REG_BASE + 0x14 * 2 + 0, &u8ReadData);
		u8ReadData = (u8ReadData & 0xFE);
		bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x14 * 2 + 0, u8ReadData);
	} else {
		bResult &= _I2C_READ_BYTE(TOP_REG_BASE + 0x14 * 2 + 1, &u8ReadData);
		u8ReadData = (u8ReadData & 0xFE);
		bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x14 * 2 + 1, u8ReadData);
	}
	if (pRes->sdmd_isdbt_initdata.ts_config_byte_clock_inv) {
		// Invert

		if (*pExtChipChId == 0) {
			// DEMOD 0
			// [5] reg_dvbtm_ts_clk_pol_0
			u32Address = TOP_REG_BASE + 0x14 * 2 + 0;
		} else {
			// DEMOD 1
			// [13] reg_dvbtm_ts_clk_pol_1
			u32Address = TOP_REG_BASE + 0x14 * 2 + 1;
		}
		bResult &= _I2C_READ_BYTE(u32Address, &u8ReadData);
		u8ReadData |= 0x20;
		bResult &= _I2C_WRITE_BYTE(u32Address, u8ReadData);
	} else {
		if (*pExtChipChId == 0) {
			// DEMOD 0
			// [5] reg_dvbtm_ts_clk_pol_0
			u32Address = TOP_REG_BASE + 0x14 * 2 + 0;
		} else {
			// DEMOD 1
			// [13] reg_dvbtm_ts_clk_pol_1
			u32Address = TOP_REG_BASE + 0x14 * 2 + 1;
		}
		bResult &= _I2C_READ_BYTE(u32Address, &u8ReadData);
		u8ReadData &= ~0x20;
		bResult &= _I2C_WRITE_BYTE(u32Address, u8ReadData);
	}

	// 2-bits serial mode start
	u8TmpData = (u8TsConfigData & 0x80) >> 7;
	if ((u8TmpData & 0x01) == 0x01) {
		// Is 2-bit serial mode

		// Turn on TS_MUX output
		if (*pExtChipChId == 0) {
			// DEMOD_0
			pr_info("[%s][%d] *pExtChipChId = %d, ISDBT use 2 bit serial mode\n",
				__func__, __LINE__, *pExtChipChId);
			// clk_ts: 144
			bResult &= _I2C_READ_BYTE(TOP_REG_BASE + 0x14 * 2 + 0, &u8ReadData);
			u8ReadData = (u8ReadData & 0xF3) | (0x02 << 2);
			bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x14 * 2 + 0, u8ReadData);

			// disable reg_en_ts_pad[4], [5]
			bResult &= _I2C_READ_BYTE(TOP_REG_BASE + 0x2D * 2 + 0, &u8ReadData);
			u8ReadData &= (~0x30);
			bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x2D * 2 + 0, u8ReadData);
			// enable reg_en_ts_pad[14], [15]
			bResult &= _I2C_READ_BYTE(TOP_REG_BASE + 0x2D * 2 + 1, &u8ReadData);
			u8ReadData |= 0xC0;
			bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x2D * 2 + 1, u8ReadData);
			// Switch TS_MUX mode (output 0 mode)
			// [1:0]: output 0 mode
			// [3:2]: output 1 mode
			bResult &= _I2C_READ_BYTE(0x102A00 + 0x02 * 2 + 0, &u8ReadData);
			u8ReadData = (u8ReadData & 0xFC) | 0x02;
			bResult &= _I2C_WRITE_BYTE(0x102A00 + 0x02 * 2 + 0, u8ReadData);

			// div_num
			bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x11 * 2 + 0, 0x05);
		} else {
			// DEMOD_1

			pr_info("[%s][%d] *pExtChipChId = %d, ISDBT use 2 bit serial mode\n",
				__func__, __LINE__, *pExtChipChId);
			// clk_ts: 144
			bResult &= _I2C_READ_BYTE(TOP_REG_BASE + 0x14 * 2 + 1, &u8ReadData);
			u8ReadData = (u8ReadData & 0xF3) | (0x02 << 2);
			bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x14 * 2 + 1, u8ReadData);

			// // reg_out_1_swrst [8]
			// bResult &= _I2C_READ_BYTE(0x102A00 + 0x00*2 + 1, &u8ReadData);
			// u8ReadData |= 0x01;
			// bResult &= _I2C_WRITE_BYTE(0x102A00 + 0x00*2 + 1, u8ReadData);

			// disable reg_en_ts_pad[6], [7]
			bResult &= _I2C_READ_BYTE(TOP_REG_BASE + 0x2D * 2 + 0, &u8ReadData);
			u8ReadData &= (~0xC0);
			bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x2D * 2 + 0, u8ReadData);
			// enable reg_en_ts_pad_new[10], [11] //pad chang, org set[8], [9]
			bResult &= _I2C_READ_BYTE(TOP_REG_BASE + 0x2E * 2 + 1, &u8ReadData);
			u8ReadData |= 0x0C; //0x03; //pad change
			bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x2E * 2 + 1, u8ReadData);
			// Switch TS_MUX mode (output 1 mode)
			// [1:0]: output 0 mode
			// [3:2]: output 1 mode
			bResult &= _I2C_READ_BYTE(0x102A00 + 0x02 * 2 + 0, &u8ReadData);
			u8ReadData = (u8ReadData & 0xF3) | 0x08;
			bResult &= _I2C_WRITE_BYTE(0x102A00 + 0x02 * 2 + 0, u8ReadData);

			// div_num
			bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x11 * 2 + 0, 0x05);
		}

	} else {
		// 2-bits serial mode end

		// Set Serial mode
		u8TmpData = u8TsConfigData & 0x01;
		if (u8TmpData == 0x01) {
			// Is 1-bit serial mode

			if (*pExtChipChId == 0) {
				// DEMOD_0

				// clk_ts: 144
				bResult &= _I2C_READ_BYTE(TOP_REG_BASE + 0x14 * 2 + 0, &u8ReadData);
				u8ReadData = (u8ReadData & 0xF3) | (0x02 << 2);
				bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x14 * 2 + 0, u8ReadData);

				// // reg_out_0_swrst [7]
				// bResult &= _I2C_READ_BYTE(0x102A00 + 0x00*2 + 0, &u8ReadData);
				// u8ReadData |= 0x80;
				// bResult &= _I2C_WRITE_BYTE(0x102A00 + 0x00*2 + 0, u8ReadData);

				// disable reg_en_ts_pad[4], [5]
				bResult &= _I2C_READ_BYTE(TOP_REG_BASE + 0x2D * 2 + 0, &u8ReadData);
				u8ReadData &= (~0x30);
				bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x2D * 2 + 0, u8ReadData);

				// Turn on PadMux for DEMOD_0 1-bit serial mode
				// reg_en_ts_pad[14]
				bResult &= _I2C_READ_BYTE(TOP_REG_BASE + 0x2D * 2 + 1, &u8ReadData);
				u8ReadData |= 0x40;
				bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x2D * 2 + 1, u8ReadData);

				// Switch TS_MUX mode (output 0 mode)
				// [1:0]: output 0 mode
				// [3:2]: output 1 mode
				bResult &= _I2C_READ_BYTE(0x102A00 + 0x02 * 2 + 0, &u8ReadData);
				u8ReadData = (u8ReadData & 0xFC) | 0x01;
				bResult &= _I2C_WRITE_BYTE(0x102A00 + 0x02 * 2 + 0, u8ReadData);

				// div_num
				bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x11 * 2 + 0, 0x02);
			} else {
				// DEMOD_1

				// clk_ts: 144
				bResult &= _I2C_READ_BYTE(TOP_REG_BASE + 0x14 * 2 + 1, &u8ReadData);
				u8ReadData = (u8ReadData & 0xF3) | (0x02 << 2);
				bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x14 * 2 + 1, u8ReadData);

				// disable reg_en_ts_pad[6], [7]
				bResult &= _I2C_READ_BYTE(TOP_REG_BASE + 0x2D * 2 + 0, &u8ReadData);
				u8ReadData &= (~0xC0);
				bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x2D * 2 + 0, u8ReadData);

				// Turn on PadMux for DEMOD_1 1-bit serial mode
				// reg_en_ts_pad[19:0] =
				// {reg_en_ts_pad_new[3:0],reg_en_ts_pad[15:0]}
				// reg_en_ts_pad[14]=1, other bits are '0'.
				bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x2D * 2, 0x00);
				bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x2D * 2 + 1, 0x40);
				// reg_en_ts_pad[16]
				bResult &= _I2C_READ_BYTE(TOP_REG_BASE + 0x2E * 2 + 1, &u8ReadData);
				u8ReadData |= 0x01;
				bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x2E * 2 + 1, u8ReadData);

				// Switch TS_MUX mode (output 1 mode)
				// [1:0]: output 0 mode
				// [3:2]: output 1 mode
				bResult &= _I2C_READ_BYTE(0x102A00 + 0x02 * 2 + 0, &u8ReadData);
				u8ReadData = (u8ReadData & 0xF3) | 0x04;
				bResult &= _I2C_WRITE_BYTE(0x102A00 + 0x02 * 2 + 0, u8ReadData);

				// div_num
				bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x11 * 2 + 0, 0x02);
			}

		} else {
			// Set Parallel mode

			if (*pExtChipChId == 0) {
				// DEMOD_0

				// clk_ts: 144
				bResult &= _I2C_READ_BYTE(TOP_REG_BASE + 0x14 * 2 + 0, &u8ReadData);
				u8ReadData = (u8ReadData & 0xF3) | (0x02 << 2);
				bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x14 * 2 + 0, u8ReadData);

				// disable reg_en_ts_pad[4], [5]
				bResult &= _I2C_READ_BYTE(TOP_REG_BASE + 0x2D * 2 + 0, &u8ReadData);
				u8ReadData &= (~0x30);
				bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x2D * 2 + 0, u8ReadData);

				// Turn on PadMux for DEMOD_0 parallel mode
				// reg_en_ts_pad[4], [5]
				bResult &= _I2C_READ_BYTE(TOP_REG_BASE + 0x2D * 2 + 0, &u8ReadData);
				u8ReadData |= 0x30;
				bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x2D * 2 + 0, u8ReadData);

				// Switch TS_MUX mode (output 0 mode)
				// [1:0]: output 0 mode
				// [3:2]: output 1 mode
				bResult &= _I2C_READ_BYTE(0x102A00 + 0x02 * 2 + 0, &u8ReadData);
				u8ReadData = (u8ReadData & 0xFC);
				bResult &= _I2C_WRITE_BYTE(0x102A00 + 0x02 * 2 + 0, u8ReadData);

				// div_num
				bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x11 * 2 + 0, 0x17);
			} else {
				// DEMOD_1

				// clk_ts: 144
				bResult &= _I2C_READ_BYTE(TOP_REG_BASE + 0x14 * 2 + 1, &u8ReadData);
				u8ReadData = (u8ReadData & 0xF3) | (0x02 << 2);
				bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x14 * 2 + 1, u8ReadData);

				// disable reg_en_ts_pad[6], [7]
				bResult &= _I2C_READ_BYTE(TOP_REG_BASE + 0x2D * 2 + 0, &u8ReadData);
				u8ReadData &= (~0xC0);
				bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x2D * 2 + 0, u8ReadData);

				// Turn on PadMux for DEMOD_1 parallel mode
				// reg_en_ts_pad[8], [9]
				bResult &= _I2C_READ_BYTE(TOP_REG_BASE + 0x2D * 2 + 1, &u8ReadData);
				u8ReadData |= 0x03;
				bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x2D * 2 + 1, u8ReadData);

				// Switch TS_MUX mode (output 1 mode)
				// [1:0]: output 0 mode
				// [3:2]: output 1 mode
				bResult &= _I2C_READ_BYTE(0x102A00 + 0x02 * 2 + 0, &u8ReadData);
				u8ReadData = (u8ReadData & 0xF3);
				bResult &= _I2C_WRITE_BYTE(0x102A00 + 0x02 * 2 + 0, u8ReadData);

				// div_num
				bResult &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x11 * 2 + 0, 0x17);
			}
		}
	}

	// Set TS config data to Xdata
	u16TSConfigDataAddr = 0;
	bResult &= _READ_MBX(0x0080, &u8ReadData);
	u16TSConfigDataAddr = u8ReadData << 8;
	bResult &= _READ_MBX(0x0081, &u8ReadData);
	u16TSConfigDataAddr |= u8ReadData;

	bResult &= _WRITE_MBX(u16TSConfigDataAddr, u8TsConfigData);

	return bResult;
}

static MS_BOOL _HAL_EXTERN_ISDBT_IIC_Bypass_Mode(MS_BOOL bEnable)
{
	MS_U8 u8Retry = 10;
	MS_U8 u8Data = 0;
	MS_BOOL bRet = FALSE;

	if (bEnable) {
#if SOC_LIKE_EXT_DMD
		_I2C_READ_BYTE(0x20C2, &u8Data);
#else
		_I2C_READ_BYTE(0x0993, &u8Data);
#endif
		// For EWBS mode
		if ((u8Data & 0x14) == 0x14) {
#if SOC_LIKE_EXT_DMD
			if (_I2C_WRITE_BYTE(0x20C2, 0x07) == FALSE)
				return FALSE;
			if (_I2C_WRITE_BYTE(0x20C0, 0x00) == FALSE)
				return FALSE;
#else
			if (_I2C_WRITE_BYTE(0x0993, 0x07) == FALSE)
				return FALSE;
			if (_I2C_WRITE_BYTE(0x0990, 0x00) == FALSE)
				return FALSE;
#endif
			// Waiting to enter FW idle state
			while (u8Data != 0x02) {
				if (_I2C_READ_BYTE(0x20C1, &u8Data) == FALSE)
					return FALSE;
			}
		}
	}

	_I2C_WRITE_BYTE(0x100900 + 0x28 * 2 + 1, 0x00);

	while ((u8Retry--) && (bRet == FALSE)) {
		if (bEnable) {
			// IIC by-pass mode on
			bRet &= _I2C_WRITE_BYTE(REG_IIC_BYPASS, 0x10);
		} else {
			// IIC by-pass mode off
			bRet &= _I2C_WRITE_BYTE(REG_IIC_BYPASS, 0x00);
		}
	}

	return bRet;
}

static MS_BOOL _HAL_EXTERN_ISDBT_SW_SSPI_GPIO(MS_BOOL bEnable)
{
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data;

	if (bEnable == TRUE) {
		// switch to GPIO
		bRet &= _I2C_READ_BYTE(TOP_REG_BASE + 0x76, &u8Data);
		u8Data &= ~0x01;
		// [0] reg_en_sspi_pad = 0
		bRet &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x76, u8Data);
	} else {
		bRet &= _I2C_READ_BYTE(TOP_REG_BASE + 0x76, &u8Data);
		u8Data |= 0x01;
		// [0] reg_en_sspi_pad = 1
		bRet &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x76, u8Data);
	}

	return bRet;
}

static MS_BOOL _HAL_EXTERN_ISDBT_GPIO_GET_LEVEL(MS_U8 u8Pin, MS_BOOL *bLevel)
{
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data;

	bRet &= _I2C_READ_BYTE(TOP_REG_BASE + 0xCA, &u8Data);
	if (u8Pin == 0) {
		if ((u8Data & 0x01) == 0x01)
			*bLevel = TRUE;
		else
			*bLevel = FALSE;
	} else if (u8Pin == 1) {
		if ((u8Data & 0x02) == 0x02)
			*bLevel = TRUE;
		else
			*bLevel = FALSE;
	} else if (u8Pin == 2) {
		if ((u8Data & 0x04) == 0x04)
			*bLevel = TRUE;
		else
			*bLevel = FALSE;
	} else if (u8Pin == 5) {
		if ((u8Data & 0x20) == 0x20)
			*bLevel = TRUE;
		else
			*bLevel = FALSE;
	} else {
		pr_info("[%s][%d] *pExtChipChId = %d, Can not use this pin as GPIO[%d]\n",
			__func__, __LINE__, *pExtChipChId, u8Pin);

		bRet = FALSE;

		return bRet;
	}

	return bRet;
}

static MS_BOOL _HAL_EXTERN_ISDBT_GPIO_SET_LEVEL(MS_U8 u8Pin, MS_BOOL bLevel)
{
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data;

	bRet &= _I2C_READ_BYTE(TOP_REG_BASE + 0xC6, &u8Data);
	if (u8Pin == 0) {
		if (bLevel == FALSE)
			u8Data &= ~0x01;
		else
			u8Data |= 0x01;
	} else if (u8Pin == 1) {
		if (bLevel == FALSE)
			u8Data &= ~0x02;
		else
			u8Data |= 0x02;
	} else if (u8Pin == 2) {
		if (bLevel == FALSE)
			u8Data &= ~0x04;
		else
			u8Data |= 0x04;
	} else if (u8Pin == 5) {
		if (bLevel == FALSE)
			u8Data &= ~0x20;
		else
			u8Data |= 0x20;
	} else {
		pr_info("[%s][%d] *pExtChipChId = %d, Can not use this pin as GPIO[%d]\n",
			__func__, __LINE__, *pExtChipChId, u8Pin);
		bRet = FALSE;

		return bRet;
	}

	bRet &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0xC6, u8Data);

	return bRet;
}

static MS_BOOL _HAL_EXTERN_ISDBT_GPIO_OUT_ENABLE(MS_U8 u8Pin, MS_BOOL bEnableOut)
{
	MS_BOOL bRet = TRUE;
	MS_U8 u8Data;

	bRet &= _I2C_READ_BYTE(TOP_REG_BASE + 0xC8, &u8Data);
	if (u8Pin == 0) {
		if (bEnableOut == TRUE)
			u8Data &= ~0x01;
		else
			u8Data |= 0x01;
	} else if (u8Pin == 1) {
		if (bEnableOut == TRUE)
			u8Data &= ~0x02;
		else
			u8Data |= 0x02;
	} else if (u8Pin == 2) {
		if (bEnableOut == TRUE)
			u8Data &= ~0x04;
		else
			u8Data |= 0x04;
	} else if (u8Pin == 5) {
		if (bEnableOut == TRUE)
			u8Data &= ~0x20;
		else
			u8Data |= 0x20;
	} else {
		pr_info("[%s][%d] *pExtChipChId = %d, Can not use this pin as GPIO[%d]\n",
			__func__, __LINE__, *pExtChipChId, u8Pin);
		bRet = FALSE;

		return bRet;
	}

	bRet &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0xC8, u8Data);

	return bRet;
}

static MS_BOOL _HAL_EXTERN_ISDBT_GetReg(MS_U16 u16Addr, MS_U8 *pu8Data)
{
	return _I2C_READ_BYTE(u16Addr, pu8Data);
}

static MS_BOOL _HAL_EXTERN_ISDBT_SetReg(MS_U16 u16Addr, MS_U8 u8Data)
{
	return _I2C_WRITE_BYTE(u16Addr, u8Data);
}

static MS_BOOL _HAL_EXTERN_ISDBT_DoIQSwap(MS_BOOL bIsQPad)
{
	pRes->sdmd_isdbt_pridata.bis_qpad = bIsQPad;

	// Set I&Q pad
	if (pRes->sdmd_isdbt_pridata.bis_qpad) {
		_I2C_WRITE_BYTE(DMDANA_REG_BASE + (*(pExtChipChId)) * 0x2400 + 0x03, 0x14);
		_I2C_WRITE_BYTE(DMDANA_REG_BASE + (*(pExtChipChId)) * 0x2400 + 0x33, 0x2E);

		pr_info("[%s][%d] *pExtChipChId = %d, select Q pad source\n", __func__, __LINE__,
				*pExtChipChId);
	} else {
		_I2C_WRITE_BYTE(DMDANA_REG_BASE + (*(pExtChipChId)) * 0x2400 + 0x03, 0x04);
		_I2C_WRITE_BYTE(DMDANA_REG_BASE + (*(pExtChipChId)) * 0x2400 + 0x33, 0x1E);

		pr_info("[%s][%d] *pExtChipChId = %d, select I pad source\n", __func__, __LINE__,
				*pExtChipChId);
	}

	return TRUE;
}

static MS_BOOL _HAL_EXTERN_ISDBT_SetTSDriveStrength(
		enum dmd_isdbt_ts_drive_strength eTsDriveStrength)
{
	MS_BOOL bRet = TRUE;
	MS_U16 u16Data1 = 0;
	MS_U16 u16Data2 = 0;

	switch (eTsDriveStrength) {
	case DMD_ISDBT_TS_DRIVE_STRENGTH_0:
		u16Data1 = 0x0000;
		u16Data2 = 0x0000;
		break;
	case DMD_ISDBT_TS_DRIVE_STRENGTH_1:
		u16Data1 = 0x0000;
		u16Data2 = 0x07FF;
		break;
	case DMD_ISDBT_TS_DRIVE_STRENGTH_2:
		u16Data1 = 0x07FF;
		u16Data2 = 0x0000;
		break;
	case DMD_ISDBT_TS_DRIVE_STRENGTH_3:
		u16Data1 = 0x07FF;
		u16Data2 = 0x07FF;
		break;
	default:
		u16Data1 = 0x07FF;
		u16Data2 = 0x07FF;
		break;
	}

	bRet &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x2A * 2 + 0, u16Data1 & 0xFF);
	bRet &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x2A * 2 + 1, (u16Data1 >> 8) & 0xFF);
	bRet &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x2C * 2 + 0, u16Data2 & 0xFF);
	bRet &= _I2C_WRITE_BYTE(TOP_REG_BASE + 0x2C * 2 + 1, (u16Data2 >> 8) & 0xFF);

	return bRet;
}

//-------------------------------------------------------------------------------------------------
//  Global Functions
//-------------------------------------------------------------------------------------------------
u8 hal_extern_isdbt_ioctl_cmd(
		struct dmd_isdbt_ioctl_data *pData, enum dmd_isdbt_hal_command eCmd, void *pArgs)
{
	u8 bResult = TRUE;

	id = pData->id;
	pRes = pData->pres;

	pExtChipChNum = pData->pExtChipChNum;
	pExtChipChId = pData->pExtChipChId;
	pExtChipI2cCh = pData->pExtChipI2cCh;

	sys = pData->sys;

#if IS_MULTI_DMD
	_SEL_DMD();
#endif

	switch (eCmd) {
	case DMD_ISDBT_HAL_CMD_Exit:
		bResult = _HAL_EXTERN_ISDBT_Exit();
		break;
	case DMD_ISDBT_HAL_CMD_InitClk:
		_HAL_EXTERN_ISDBT_InitClk();
		break;
	case DMD_ISDBT_HAL_CMD_Download:
		bResult = _HAL_EXTERN_ISDBT_Download();
		break;
	case DMD_ISDBT_HAL_CMD_FWVERSION:
		_HAL_EXTERN_ISDBT_FWVERSION();
		break;
	case DMD_ISDBT_HAL_CMD_SoftReset:
		bResult = _HAL_EXTERN_ISDBT_SoftReset();
		break;
	case DMD_ISDBT_HAL_CMD_SetACICoef:
		bResult = _HAL_EXTERN_ISDBT_SetACICoef();
		break;
	case DMD_ISDBT_HAL_CMD_SetISDBTMode:
		bResult = _HAL_EXTERN_ISDBT_SetIsdbtMode();
		break;
	case DMD_ISDBT_HAL_CMD_SetEWBSMode:
		bResult = _HAL_EXTERN_ISDBT_SetEwbsMode();
		break;
	case DMD_ISDBT_HAL_CMD_SetModeClean:
		bResult = _HAL_EXTERN_ISDBT_SetModeClean();
		break;
	case DMD_ISDBT_HAL_CMD_Active:
		break;
	case DMD_ISDBT_HAL_CMD_Check_EWBS_Lock:
		bResult = _HAL_EXTERN_ISDBT_Check_EWBS_Lock();
		break;
	case DMD_ISDBT_HAL_CMD_Check_FEC_Lock:
		bResult = _HAL_EXTERN_ISDBT_Check_FEC_Lock();
		break;
	case DMD_ISDBT_HAL_CMD_Check_FSA_TRACK_Lock:
		bResult = _HAL_EXTERN_ISDBT_Check_FSA_TRACK_Lock();
		break;
	case DMD_ISDBT_HAL_CMD_Check_PSYNC_Lock:
		bResult = _HAL_EXTERN_ISDBT_Check_PSYNC_Lock();
		break;
	case DMD_ISDBT_HAL_CMD_Check_ICFO_CH_EXIST_Lock:
		bResult = _HAL_EXTERN_ISDBT_Check_ICFO_CH_EXIST_Lock();
		break;
	case DMD_ISDBT_HAL_CMD_Check_MODE_CP_Lock:
		bResult = _HAL_EXTERN_ISDBT_Check_MODE_CP_Lock();
		break;
	case DMD_ISDBT_HAL_CMD_GetSignalCodeRate:
		bResult = _HAL_EXTERN_ISDBT_GetSignalCodeRate(
			(*((struct dmd_isdbt_get_code_rate *)pArgs)).eisdbtlayer,
			&((*((struct dmd_isdbt_get_code_rate *)pArgs)).ecoderate));
		break;
	case DMD_ISDBT_HAL_CMD_GetSignalGuardInterval:
		bResult =
			_HAL_EXTERN_ISDBT_GetSignalGuardInterval(
			(enum en_isdbt_guard_interval *)pArgs);
		break;
	case DMD_ISDBT_HAL_CMD_GetSignalTimeInterleaving:
		bResult = _HAL_EXTERN_ISDBT_GetSignalTimeInterleaving(
			(*((struct dmd_isdbt_get_time_interleaving *)pArgs)).eisdbtlayer,
			&((*((struct dmd_isdbt_get_time_interleaving *)pArgs)).etimeinterleaving));
		break;
	case DMD_ISDBT_HAL_CMD_GetSignalFFTValue:
		bResult =
			_HAL_EXTERN_ISDBT_GetSignalFFTValue((enum en_isdbt_fft_val *)pArgs);
		break;
	case DMD_ISDBT_HAL_CMD_GetSystemIndentificationOfTMCC:
		bResult =
			_HAL_EXTERN_ISDBT_GetSystemIndentificationOfTMCC(
			(enum en_isdbt_tmcc_sys_id *)pArgs);
		break;
	case DMD_ISDBT_HAL_CMD_GetSignalModulation:
		bResult =
			_HAL_EXTERN_ISDBT_GetSignalModulation(
			(*((struct dmd_isdbt_get_modulation *)pArgs)).eisdbtlayer,
			&((*((struct dmd_isdbt_get_modulation *)pArgs)).econstellation));
		break;
	case DMD_ISDBT_HAL_CMD_ReadIFAGC:
		*((MS_U16 *)pArgs) = _HAL_EXTERN_ISDBT_ReadIFAGC();
		break;
	case DMD_ISDBT_HAL_CMD_ReadIndicatorOfTransmissionParameterSwitch:
		*((MS_U16 *)pArgs) =
			_HAL_EXTERN_ISDBT_ReadIndicatorOfTransmissionParameterSwitch();
		break;
	case DMD_ISDBT_HAL_CMD_GetNumberOfSegmentsOfLayerA:
		*((MS_U16 *)pArgs) = _HAL_EXTERN_ISDBT_GetNumberOfSegmentsOfLayerA();
		break;
	case DMD_ISDBT_HAL_CMD_GetNumberOfSegmentsOfLayerB:
		*((MS_U16 *)pArgs) = _HAL_EXTERN_ISDBT_GetNumberOfSegmentsOfLayerB();
		break;
	case DMD_ISDBT_HAL_CMD_GetNumberOfSegmentsOfLayerC:
		*((MS_U16 *)pArgs) = _HAL_EXTERN_ISDBT_GetNumberOfSegmentsOfLayerC();
		break;
	case DMD_ISDBT_HAL_CMD_GetPhaseShiftCorrectionValue:
		*((MS_U16 *)pArgs) = _HAL_EXTERN_ISDBT_GetPhaseShiftCorrectionValue();
		break;
	case DMD_ISDBT_HAL_CMD_GetPartialReceptionFlag:
		bResult = _HAL_EXTERN_ISDBT_GetPartialReceptionFlag((MS_BOOL *)pArgs);
		break;
	case DMD_ISDBT_HAL_CMD_GetFreqOffset:
#ifdef UTPA2
		bResult = _HAL_EXTERN_ISDBT_GetFreqOffset(
			&((*((struct dmd_isdbt_cfo_data *)pArgs)).fft_mode),
			&((*((struct dmd_isdbt_cfo_data *)pArgs)).tdcfo_regvalue),
			&((*((struct dmd_isdbt_cfo_data *)pArgs)).fdcfo_regvalue),
			&((*((struct dmd_isdbt_cfo_data *)pArgs)).icfo_regvalue));
#else
		bResult = _HAL_EXTERN_ISDBT_GetFreqOffset((float *)pArgs);
#endif
		break;
	case DMD_ISDBT_HAL_CMD_GetSignalQuality:
	case DMD_ISDBT_HAL_CMD_GetSignalQualityOfLayerA:
		*((MS_U16 *)pArgs) = _HAL_EXTERN_ISDBT_GetSignalQualityOfLayerA();
		break;
	case DMD_ISDBT_HAL_CMD_GetSignalQualityOfLayerB:
		*((MS_U16 *)pArgs) = _HAL_EXTERN_ISDBT_GetSignalQualityOfLayerB();
		break;
	case DMD_ISDBT_HAL_CMD_GetSignalQualityOfLayerC:
		*((MS_U16 *)pArgs) = _HAL_EXTERN_ISDBT_GetSignalQualityOfLayerC();
		break;
	case DMD_ISDBT_HAL_CMD_GetSignalQualityCombine:
		*((MS_U16 *)pArgs) = _HAL_EXTERN_ISDBT_GetSignalQualityOfLayerCombine();
		break;
	case DMD_ISDBT_HAL_CMD_GetSNR:
#ifdef UTPA2
		bResult =
			_HAL_EXTERN_ISDBT_GetSNR(
			&((*((struct dmd_isdbt_snr_data *)pArgs)).reg_snr),
			&((*((struct dmd_isdbt_snr_data *)pArgs)).reg_snr_obs_num));
#else
		bResult = _HAL_EXTERN_ISDBT_GetSNR((float *)pArgs);
#endif
		break;
	case DMD_ISDBT_HAL_CMD_GetPreViterbiBer:
#ifdef UTPA2
		bResult =
			_HAL_EXTERN_ISDBT_GetPreViterbiBer(
			(*((struct dmd_isdbt_get_ber_value *)pArgs)).eisdbtlayer,
			&((*((struct dmd_isdbt_get_ber_value *)pArgs)).bervalue),
			&((*((struct dmd_isdbt_get_ber_value *)pArgs)).berperiod));
#else
		bResult =
			_HAL_EXTERN_ISDBT_GetPreViterbiBer(
			(*((struct dmd_isdbt_get_ber_value *)pArgs)).eisdbtlayer,
			&((*((struct dmd_isdbt_get_ber_value *)pArgs)).fbervalue));
#endif
		break;
	case DMD_ISDBT_HAL_CMD_GetPostViterbiBer:
#ifdef UTPA2
		bResult =
			_HAL_EXTERN_ISDBT_GetPostViterbiBer(
			(*((struct dmd_isdbt_get_ber_value *)pArgs)).eisdbtlayer,
			&((*((struct dmd_isdbt_get_ber_value *)pArgs)).bervalue),
			&((*((struct dmd_isdbt_get_ber_value *)pArgs)).berperiod));
#else
		bResult =
			_HAL_EXTERN_ISDBT_GetPostViterbiBer(
			(*((struct dmd_isdbt_get_ber_value *)pArgs)).eisdbtlayer,
			&((*((struct dmd_isdbt_get_ber_value *)pArgs)).fbervalue));
#endif
		break;
	case DMD_ISDBT_HAL_CMD_Read_PKT_ERR:
		bResult =
			_HAL_EXTERN_ISDBT_Read_PKT_ERR(
			(*((struct dmd_isdbt_get_pkt_err *)pArgs)).eisdbtlayer,
			&((*((struct dmd_isdbt_get_pkt_err *)pArgs)).packeterr));
		break;
	case DMD_ISDBT_HAL_CMD_TS_INTERFACE_CONFIG:
		bResult = _HAL_EXTERN_ISDBT_SetSerialControl();
		break;
	case DMD_ISDBT_HAL_CMD_IIC_Bypass_Mode:
		bResult =
			_HAL_EXTERN_ISDBT_IIC_Bypass_Mode(*((MS_BOOL *)pArgs));
		break;
	case DMD_ISDBT_HAL_CMD_SSPI_TO_GPIO:
		bResult =
			_HAL_EXTERN_ISDBT_SW_SSPI_GPIO(*((MS_BOOL *)pArgs));
		break;
	case DMD_ISDBT_HAL_CMD_GPIO_GET_LEVEL:
		bResult =
			_HAL_EXTERN_ISDBT_GPIO_GET_LEVEL(
			(*((struct dmd_isdbt_gpio_pin_data *)pArgs)).pin,
			&((*((struct dmd_isdbt_gpio_pin_data *)pArgs)).level));
		break;
	case DMD_ISDBT_HAL_CMD_GPIO_SET_LEVEL:
		bResult =
			_HAL_EXTERN_ISDBT_GPIO_SET_LEVEL(
			(*((struct dmd_isdbt_gpio_pin_data *)pArgs)).pin,
			(*((struct dmd_isdbt_gpio_pin_data *)pArgs)).level);
		break;
	case DMD_ISDBT_HAL_CMD_GPIO_OUT_ENABLE:
		bResult =
			_HAL_EXTERN_ISDBT_GPIO_OUT_ENABLE(
			(*((struct dmd_isdbt_gpio_pin_data *)pArgs)).pin,
			(*((struct dmd_isdbt_gpio_pin_data *)pArgs)).is_out);
		break;
	case DMD_ISDBT_HAL_CMD_GET_REG:
		bResult = _HAL_EXTERN_ISDBT_GetReg(
			(*((struct dmd_isdbt_reg_data *)pArgs)).isdbt_u32addr,
			&((*((struct dmd_isdbt_reg_data *)pArgs)).isdbt_data));
		break;
	case DMD_ISDBT_HAL_CMD_SET_REG:
		bResult =
			_HAL_EXTERN_ISDBT_SetReg(
			(*((struct dmd_isdbt_reg_data *)pArgs)).isdbt_u32addr,
			(*((struct dmd_isdbt_reg_data *)pArgs)).isdbt_data);
		break;
	case DMD_ISDBT_HAL_CMD_SSPI_INIT:
		bResult = _SSPI_Init(*((MS_U8 *)pArgs));
		break;
	case DMD_ISDBT_HAL_CMD_SSPI_GET_REG:
		bResult =
			_SSPI_RIU_Read8(
			(*((struct dmd_isdbt_reg_data *)pArgs)).isdbt_u32addr,
			&((*((struct dmd_isdbt_reg_data *)pArgs)).isdbt_data));
		break;
	case DMD_ISDBT_HAL_CMD_SSPI_SET_REG:
		bResult =
			_SSPI_RIU_Write8(
			(*((struct dmd_isdbt_reg_data *)pArgs)).isdbt_u32addr,
			(*((struct dmd_isdbt_reg_data *)pArgs)).isdbt_data);
		break;
	case DMD_ISDBT_HAL_CMD_DoIQSwap:
		bResult = _HAL_EXTERN_ISDBT_DoIQSwap(*((MS_BOOL *)pArgs));
		break;
	case DMD_ISDBT_HAL_CMD_SetTSDriveStrength:
		bResult =
			_HAL_EXTERN_ISDBT_SetTSDriveStrength(
			*((enum dmd_isdbt_ts_drive_strength *)pArgs));
		break;
	default:
		break;
	}

	return bResult;
}

#if defined(MSOS_TYPE_LINUX_KERNEL) && defined(CONFIG_CC_IS_CLANG)
#if defined(CONFIG_MSTAR_CHIP)
EXPORT_SYMBOL(hal_extern_isdbt_ioctl_cmd);
#endif
#endif
