/*
 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
 *
 * Efusewriter API for Fastcall drivers
 */
#include "drStd.h"
#include "DrApi/DrApiCommon.h"

#include "drMobicore.h"
#include "efusewriter.h"
#include "fcEfuse.h"

struct data d_list;

#if defined(CONFIG_EXYNOS3475)
unsigned int efuse_bitsize[17] = {0, 128, 128, 0, 0, 0, 0, 128, 128, 32, 128, 96, 128, 128, 128, 0, 128};
#else
unsigned int efuse_bitsize[17] = {0, 128, 128, 128, 96, 80, 128, 128, 32, 128, 96, 0, 0, 0, 0, 128, 128};
#endif

void Efusewriter_Enable(void)
{
	unsigned int uTemp;

	uTemp = read_sfr_value(EFUSE_SFR_VA + EFUSE_WRITER_CTL);
	uTemp |= (1 << EFUSE_WRITER_ENABLE);
	write_sfr_value(EFUSE_SFR_VA + EFUSE_WRITER_CTL, uTemp);
}

void Efusewriter_SelectEfuseChip(unsigned int nIndex)
{
	unsigned int uBits;

	if (nIndex)
		uBits = (1 << (nIndex - 1));
	else
		uBits = 0;

	write_sfr_value(EFUSE_SFR_VA + EFUSE_CHIP_SELECT, uBits);
}

int Efusewriter_CheckEfromLockOn(void)
{
	bool ret = FALSE;

	if (read_sfr_value(EFUSE_SFR_VA + EFUSE_WRITER_STATUS) & EFUSE_LOCK_ON)
		ret = TRUE;
	else
		ret = FALSE;

	return ret;
}

int Efusewriter_CheckEfromInitEnd(void)
{
	bool ret = FALSE;

	if (read_sfr_value(EFUSE_SFR_VA + EFUSE_WRITER_STATUS) & EFUSE_INITIAL_END)
		ret = TRUE;
	else
		ret = FALSE;

	return ret;
}

void Efusewriter_Size(unsigned char nSize)
{
	unsigned int uTemp;

	uTemp = nSize & 0xff;
	write_sfr_value(EFUSE_SFR_VA + EFUSE_SIZE, uTemp);
}

void Efusewriter_Waittime(unsigned int nWaittime)
{
	unsigned int uTemp;

	uTemp = nWaittime & 0x1ff;
	write_sfr_value(EFUSE_SFR_VA + EFUSE_Wait_Time, uTemp);
}

void Efusewriter_Programwaittime(unsigned int nProgWaittime)
{
	unsigned int uTemp;

	uTemp = nProgWaittime & 0x1fff;
	write_sfr_value(EFUSE_SFR_VA + EFUSE_Program_Time, uTemp);
}

void Efusewriter_InitStart(void)
{
	unsigned int uTemp;

	uTemp = read_sfr_value(EFUSE_SFR_VA + EFUSE_WRITER_CTL);
	uTemp |= (1 << EFUSE_INITIAL_START);
	write_sfr_value(EFUSE_SFR_VA + EFUSE_WRITER_CTL, uTemp);
}

void Efusewriter_WriteData(unsigned int index, unsigned int data)
{
	write_sfr_value(EFUSE_SFR_VA + EFUSE_DATA0 + index * 4, data);
}

void Efusewriter_WriteLockbit(unsigned int lockbit)
{
	write_sfr_value(EFUSE_SFR_VA + EFUSE_lock_bit_status, lockbit);
}

void Efusewriter_StartBlow(void)
{
	unsigned int uTemp;

	uTemp = read_sfr_value(EFUSE_SFR_VA + EFUSE_WRITER_CTL);
	uTemp |= (1 << EFUSE_PROGRAM_START);
	write_sfr_value(EFUSE_SFR_VA + EFUSE_WRITER_CTL, uTemp);
}

int Efusewriter_CheckBlow(void)
{
	bool ret = FALSE;

	if ((read_sfr_value(EFUSE_SFR_VA + EFUSE_WRITER_STATUS) & EFUSE_BLOW_END))
		ret = TRUE;
	else
		ret = FALSE;

	return ret;
}

void Efusewriter_Sensing(void)
{
	unsigned int uTemp;

	uTemp = read_sfr_value(EFUSE_SFR_VA + EFUSE_WRITER_CTL);
	uTemp &= ~(1 << EFUSE_WRITER_ENABLE);
	write_sfr_value(EFUSE_SFR_VA + EFUSE_WRITER_CTL, uTemp);
}

void Efusewriter_Compare(void)
{
	unsigned int uTemp;

	uTemp = read_sfr_value(EFUSE_SFR_VA + EFUSE_WRITER_CTL);
	uTemp |= (1 << EFUSE_COMPARE_START);
	write_sfr_value(EFUSE_SFR_VA + EFUSE_WRITER_CTL, uTemp);
}

int Efusewriter_CheckCompare(void)
{
	bool ret = FALSE;

	if (read_sfr_value(EFUSE_SFR_VA + EFUSE_WRITER_STATUS) & EFUSE_COMPARE_END)
		ret = TRUE;
	else
		ret = FALSE;

	return ret;
}

int Efusewriter_CheckCompareStatus_Errorcontrol(void)
{
	bool ret = FALSE;

	if (read_sfr_value(EFUSE_SFR_VA + EFUSE_WRITER_STATUS) & EFUSE_COMPARE_END_WITHOUT_ERROR)
		ret = TRUE;
	else if (read_sfr_value(EFUSE_SFR_VA + EFUSE_WRITER_STATUS) & EFUSE_COMPARE_END_WITH_ERROR)
		ret = TRUE;
	else
		ret = FALSE;

	return ret;
}

int Efusewriter_CheckCompareStatus(uint32_t nChipselect)
{
	bool ret = FALSE;

	if (read_sfr_value(EFUSE_SFR_VA + EFUSE_WRITER_STATUS) & EFUSE_COMPARE_END_WITHOUT_ERROR)
		ret = TRUE;

	return ret;
}

int efuse_initialize(int efuse_id)
{
	int idx;

	Efusewriter_Enable();
	Efusewriter_SelectEfuseChip(efuse_id);

	if (Efusewriter_CheckEfromLockOn() == TRUE)
		return LOCK_ON;

	Efusewriter_Size(efuse_bitsize[efuse_id]);

	Efusewriter_WriteData(0, d_list.data0);
	Efusewriter_WriteData(1, d_list.data1);
	Efusewriter_WriteData(2, d_list.data2);
	Efusewriter_WriteData(3, d_list.data3);

	Efusewriter_Waittime(24); /* OSC_CLK 24MHz, tFSRCS = 1000ns -> 24 */
	Efusewriter_Programwaittime(240);

	Efusewriter_InitStart();

	for (idx = 0; idx < 1000000; idx++) {
		if (Efusewriter_CheckEfromInitEnd() == TRUE)
			return SUCCESS;
	}

	return INIT_FAIL;
}

int efuse_blow(void)
{
	int idx;

	Efusewriter_StartBlow();

	for (idx = 0; idx < 1000000; idx++) {
		if (Efusewriter_CheckBlow() == TRUE)
			return SUCCESS;
	}

	return BLOW_FAIL;
}

int efuse_finalize(int efuse_id)
{
	int idx;
	uint32_t value = 0;
	uint32_t ret = COMPARE_STATUS_FAIL;

	Efusewriter_Sensing();
	Efusewriter_Compare();

	for (idx = 0; idx < 1000000; idx++) {
		if (Efusewriter_CheckCompare() == TRUE)
			break;
	}

	if (idx == 1000000)
		return COMPARE_FAIL;

	switch (efuse_id) {
	case BAN_APFA:
		value = efuse_read(BAN_APFA);
		d_list.data0 = (d_list.data0 >> BAN_APFA_BIT_OFFSET) & ONE_BIT;
		if (d_list.data0 == value)
			ret = SUCCESS;
		break;
#if defined(CONFIG_EXYNOS5430) || defined(CONFIG_EXYNOS3475)
	case JTAG_LOCK:
		value = efuse_read(JTAG_LOCK);
		d_list.data0 = (d_list.data0 >> JTAG_LOCK_BIT_OFFSET) & ONE_BIT;
		if (d_list.data0 == value)
			ret = SUCCESS;
		break;
#endif

#if defined(CONFIG_EXYNOS4415)
	case JTAG_LOCK:
		value = efuse_read(JTAG_LOCK);
		d_list.data2 = (d_list.data2 & ONE_BIT);
		if (d_list.data2 == value)
			ret = SUCCESS;
		break;
#endif
	case BAN_OEM_KEY:
		value = efuse_read(BAN_OEM_KEY);
		d_list.data0 = (d_list.data0 >> BAN_OEM_BIT_OFFSET) & ONE_BIT;
		if (d_list.data0 == value)
			ret = SUCCESS;
		break;
	case USE_OEM_KEY:
		value = efuse_read(USE_OEM_KEY);
		d_list.data0 = (d_list.data0 >> USE_OEM_BIT_OFFSET) & ONE_BIT;
		if (d_list.data0 == value)
			ret = SUCCESS;
		break;
	case SKIP_AES:
		value = efuse_read(SKIP_AES);
		d_list.data0 = (d_list.data0 >> SKIP_AES_BIT_OFFSET) & ONE_BIT;
		if (d_list.data0 == value)
			ret = SUCCESS;
		break;
	case PREORDER:
		value = efuse_read(PREORDER);
		d_list.data0 = (d_list.data0 >> PREORDER_BIT_OFFSET) & ONE_BIT;
		if ((d_list.data0 & value) == d_list.data0)
			ret = SUCCESS;
		break;
	case OEM_KEY0:
		value = read_sfr_value(ROOT_KEY_VA + SECURE_BOOT_KEY0_BASE_OFFSET);
		if (d_list.data0 != value)
			break;

		value = read_sfr_value(ROOT_KEY_VA + SECURE_BOOT_KEY0_BASE_OFFSET + 0x4);
		if (d_list.data1 != value)
			break;

		value = read_sfr_value(ROOT_KEY_VA + SECURE_BOOT_KEY0_BASE_OFFSET + 0x8);
		if (d_list.data2 != value)
			break;

		value = read_sfr_value(ROOT_KEY_VA + SECURE_BOOT_KEY0_BASE_OFFSET + 0xC);
		if (d_list.data3 != value)
			break;

		ret = SUCCESS;
		break;
	case OEM_KEY1:
		value = read_sfr_value(ROOT_KEY_VA + SECURE_BOOT_KEY1_BASE_OFFSET);
		if (d_list.data0 != value)
			break;

		value = read_sfr_value(ROOT_KEY_VA + SECURE_BOOT_KEY1_BASE_OFFSET + 0x4);
		if (d_list.data1 != value)
			break;

		value = read_sfr_value(ROOT_KEY_VA + SECURE_BOOT_KEY1_BASE_OFFSET + 0x8);
		if (d_list.data2 != value)
			break;

		value = read_sfr_value(ROOT_KEY_VA + SECURE_BOOT_KEY1_BASE_OFFSET + 0xC);
		if (d_list.data3 != value)
			break;

		ret = SUCCESS;
		break;
	case MODEL_ID:
		value = read_sfr_value(MAIN_EFUSE_VA + 0x4);
		if ((d_list.data1 & value) == d_list.data1)
			ret = SUCCESS;
		break;
	case SANTIRBK:
		value = read_sfr_value(ROOT_KEY_VA + ANTIRBK_SEC_BASE_OFFSET);
		if ((d_list.data0 & value) == d_list.data0)
			ret = SUCCESS;
		break;
	case NANTIRBK0:
		value = read_sfr_value(NANTIRBK_VA + NANTIRBK0_BASE_OFFSET);
		if ((d_list.data0 & value) != d_list.data0)
			break;

		value = read_sfr_value(NANTIRBK_VA + NANTIRBK0_BASE_OFFSET + 0x4);
		if ((d_list.data1 & value) != d_list.data1)
			break;

		value = read_sfr_value(NANTIRBK_VA + NANTIRBK0_BASE_OFFSET + 0x8);
		if ((d_list.data2 & value) != d_list.data2)
			break;

		value = read_sfr_value(NANTIRBK_VA + NANTIRBK0_BASE_OFFSET + 0xC);
		if ((d_list.data3 & value) != d_list.data3)
			break;

		ret = SUCCESS;
		break;
	case NANTIRBK1:
		value = read_sfr_value(NANTIRBK_VA + NANTIRBK1_BASE_OFFSET);
		if ((d_list.data0 & value) != d_list.data0)
			break;

		value = read_sfr_value(NANTIRBK_VA + NANTIRBK1_BASE_OFFSET + 0x4);
		if ((d_list.data1 & value) != d_list.data1)
			break;

		value = read_sfr_value(NANTIRBK_VA + NANTIRBK1_BASE_OFFSET + 0x8);
		if ((d_list.data2 & value) != d_list.data2)
			break;

		ret = SUCCESS;
		break;
	case COMMERCIAL:
		value = efuse_read(COMMERCIAL);
		d_list.data2 = (d_list.data2 >> COMMERCIAL_BIT_OFFSET) & ONE_BIT;
		if (d_list.data2 == value)
			ret = SUCCESS;
		break;
	case TEST:
		value = efuse_read(TEST);
		d_list.data2 = (d_list.data2 >> TEST_BIT_OFFSET) & ONE_BIT;
		if (d_list.data2 == value)
			ret = SUCCESS;
		break;
	case WARRANTY:
		value = efuse_read(WARRANTY);
		d_list.data2 = (d_list.data2 >> WARRANTY_BIT_OFFSET) & ONE_BIT;
		if (d_list.data2 == value)
			ret = SUCCESS;
		break;
	case W_ETC:
		ret = SUCCESS;
		break;
	default:
		ret = COMPARE_STATUS_FAIL;
	}

	return ret;
}

#if defined(CONFIG_EXYNOS4415)
uint32_t check_secure_jtag_key()
{
	uint32_t value = 0;

	value = read_sfr_value(ROOT_KEY_VA + JTAG_KEY_0_OFFSET) | read_sfr_value(ROOT_KEY_VA + JTAG_KEY_1_OFFSET) |
		read_sfr_value(ROOT_KEY_VA + JTAG_KEY_2_OFFSET) | read_sfr_value(ROOT_KEY_VA + JTAG_KEY_3_OFFSET) |
		read_sfr_value(ROOT_KEY_VA + JTAG_KEY_4_OFFSET);

	if (value == NO_DATA)
		return JTAG_KEY_NO_FUSING;
	else
		return JTAG_KEY_FUSING;

}
#endif

uint32_t efuse_read(int efuse_id)
{
	uint32_t value;
    uint32_t *jtag_lock_addr;

	switch (efuse_id) {
	case BAN_APFA:
		value = ((read_sfr_value(MAIN_EFUSE_VA) >> BAN_APFA_BIT_OFFSET) & ONE_BIT);
		break;
#if defined(CONFIG_EXYNOS5430) || defined(CONFIG_EXYNOS3475)
	case JTAG_LOCK:
		value = ((read_sfr_value(MAIN_EFUSE_VA) >> JTAG_LOCK_BIT_OFFSET) & ONE_BIT);
		break;
#endif
#if defined(CONFIG_EXYNOS5430)
	case JTAG_LOCK_VF:
        jtag_lock_addr = (uint32_t *)(SECURE_JTAG_VA + (SECURE_JTAG_BASE & (SIZE_4KB - 1)));
		value = ((read_sfr_value(jtag_lock_addr) >> 3) & 0x1F);
		break;
#endif

#if defined(CONFIG_EXYNOS4415)
	case JTAG_LOCK:
		value = (read_sfr_value(ROOT_KEY_VA + JTAG_LOCK_BIT_OFFSET) & ONE_BIT);
		break;

	case CHECK_JTAG_KEY:
		value = check_secure_jtag_key();
		break;
#endif
	case BAN_OEM_KEY:
		value = ((read_sfr_value(MAIN_EFUSE_VA) >> BAN_OEM_BIT_OFFSET) & ONE_BIT);
		break;
	case USE_OEM_KEY:
		value = ((read_sfr_value(MAIN_EFUSE_VA) >> USE_OEM_BIT_OFFSET) & ONE_BIT);
		break;
	case SKIP_AES:
		value = ((read_sfr_value(MAIN_EFUSE_VA) >> SKIP_AES_BIT_OFFSET) & ONE_BIT);
		break;
	case PREORDER:
		value = ((read_sfr_value(MAIN_EFUSE_VA) >> PREORDER_BIT_OFFSET) & ONE_BYTE);
		break;
	case MODEL_ID:
		value = (read_sfr_value(MAIN_EFUSE_VA + 0x4));
		break;
	case COMMERCIAL:
		value = ((read_sfr_value(MAIN_EFUSE_VA + 0x8) >> COMMERCIAL_BIT_OFFSET) & ONE_BIT);
		break;
	case TEST:
		value = ((read_sfr_value(MAIN_EFUSE_VA + 0x8) >> TEST_BIT_OFFSET) & ONE_BIT);
		break;
	case WARRANTY:
		value = ((read_sfr_value(MAIN_EFUSE_VA + 0x8) >> WARRANTY_BIT_OFFSET) & ONE_BIT);
		break;
	default:
		value = ID_FAULT;
	}

	return value;
}

void d_list_clean(void)
{
	d_list.data0 = 0;
	d_list.data1 = 0;
	d_list.data2 = 0;
	d_list.data3 = 0;
}

int efuse_writer(
	fastcall_registers_t regs
) {
	uint32_t efuseWriterID = regs[2];

	switch (efuseWriterID) {
	case BAN_APFA:
		d_list.data0 = read_sfr_value(MAIN_EFUSE_VA) | (ONE_BIT << BAN_APFA_BIT_OFFSET);
		d_list.data1 = read_sfr_value(MAIN_EFUSE_VA + 0x4);
		d_list.data2 = read_sfr_value(MAIN_EFUSE_VA + 0x8);
		d_list.data3 = read_sfr_value(MAIN_EFUSE_VA + 0xC);
		regs[1] = efuse_initialize(MAIN_EFUSE);
		break;
#if defined(CONFIG_EXYNOS5430) || defined(CONFIG_EXYNOS3475)
	case JTAG_LOCK:
		d_list.data0 = read_sfr_value(MAIN_EFUSE_VA) | (ONE_BIT << JTAG_LOCK_BIT_OFFSET);
		d_list.data1 = read_sfr_value(MAIN_EFUSE_VA + 0x4);
		d_list.data2 = read_sfr_value(MAIN_EFUSE_VA + 0x8);
		d_list.data3 = read_sfr_value(MAIN_EFUSE_VA + 0xC);
		regs[1] = efuse_initialize(MAIN_EFUSE);
		break;
#endif

#if defined(CONFIG_EXYNOS4415)
	case JTAG_LOCK:
		d_list.data0 = NO_DATA;
		d_list.data1 = NO_DATA;
		d_list.data2 = read_sfr_value(ROOT_KEY_VA + JTAG_LOCK_BIT_OFFSET) | ONE_BIT;
		d_list.data3 = NO_DATA;
		regs[1] = efuse_initialize(JTAG_KEY1);
		break;
#endif
	case BAN_OEM_KEY:
		d_list.data0 = read_sfr_value(MAIN_EFUSE_VA) | (ONE_BIT << BAN_OEM_BIT_OFFSET);
		d_list.data1 = read_sfr_value(MAIN_EFUSE_VA + 0x4);
		d_list.data2 = read_sfr_value(MAIN_EFUSE_VA + 0x8);
		d_list.data3 = read_sfr_value(MAIN_EFUSE_VA + 0xC);
		regs[1] = efuse_initialize(MAIN_EFUSE);
		break;
	case USE_OEM_KEY:
		d_list.data0 = read_sfr_value(MAIN_EFUSE_VA) | (ONE_BIT << USE_OEM_BIT_OFFSET);
		d_list.data1 = read_sfr_value(MAIN_EFUSE_VA + 0x4);
		d_list.data2 = read_sfr_value(MAIN_EFUSE_VA + 0x8);
		d_list.data3 = read_sfr_value(MAIN_EFUSE_VA + 0xC);;
		regs[1] = efuse_initialize(MAIN_EFUSE);
		break;
	case SKIP_AES:
		d_list.data0 = read_sfr_value(MAIN_EFUSE_VA) | (ONE_BIT << SKIP_AES_BIT_OFFSET);
		d_list.data1 = read_sfr_value(MAIN_EFUSE_VA + 0x4);
		d_list.data2 = read_sfr_value(MAIN_EFUSE_VA + 0x8);
		d_list.data3 = read_sfr_value(MAIN_EFUSE_VA + 0xC);
		regs[1] = efuse_initialize(MAIN_EFUSE);
		break;
	case PREORDER:
		d_list.data0 = read_sfr_value(MAIN_EFUSE_VA) | ((regs[3] & ONE_BYTE) << PREORDER_BIT_OFFSET);
		d_list.data1 = read_sfr_value(MAIN_EFUSE_VA + 0x4);
		d_list.data2 = read_sfr_value(MAIN_EFUSE_VA + 0x8);
		d_list.data3 = read_sfr_value(MAIN_EFUSE_VA + 0xC);
		regs[1] = efuse_initialize(MAIN_EFUSE);
		break;
	case DATA_INPUT_OEM_KEY0:
		d_list.data0 = read_sfr_value(ROOT_KEY_VA + SECURE_BOOT_KEY0_BASE_OFFSET) |  regs[1];
		d_list.data1 = read_sfr_value(ROOT_KEY_VA + SECURE_BOOT_KEY0_BASE_OFFSET + 0x4) | regs[3];
		regs[1] = SUCCESS;
		break;
	case OEM_KEY0:
		d_list.data2 = read_sfr_value(ROOT_KEY_VA + SECURE_BOOT_KEY0_BASE_OFFSET + 0x8) | regs[1];
		d_list.data3 = read_sfr_value(ROOT_KEY_VA + SECURE_BOOT_KEY0_BASE_OFFSET + 0xC) | regs[3];
		regs[1] = efuse_initialize(SECURE_BOOT_KEY0);
		break;
	case DATA_INPUT_OEM_KEY1:
		d_list.data0 = read_sfr_value(ROOT_KEY_VA + SECURE_BOOT_KEY1_BASE_OFFSET) | regs[1];
		d_list.data1 = read_sfr_value(ROOT_KEY_VA + SECURE_BOOT_KEY1_BASE_OFFSET + 0x4) | regs[3];
		regs[1] = SUCCESS;
		break;
	case OEM_KEY1:
		d_list.data2 = read_sfr_value(ROOT_KEY_VA + SECURE_BOOT_KEY1_BASE_OFFSET + 0x8) | regs[1];
		d_list.data3 = read_sfr_value(ROOT_KEY_VA + SECURE_BOOT_KEY1_BASE_OFFSET + 0xC) | regs[3];
		regs[1] = efuse_initialize(SECURE_BOOT_KEY1);
		break;
	case MODEL_ID:
		d_list.data0 = read_sfr_value(MAIN_EFUSE_VA);
		d_list.data1 = read_sfr_value(MAIN_EFUSE_VA + 0x4) | regs[1];
		d_list.data2 = read_sfr_value(MAIN_EFUSE_VA + 0x8);
		d_list.data3 = read_sfr_value(MAIN_EFUSE_VA + 0xC);
		regs[1] = efuse_initialize(MAIN_EFUSE);
		break;
	case SANTIRBK:
		d_list.data0 = read_sfr_value(ROOT_KEY_VA + ANTIRBK_SEC_BASE_OFFSET) | regs[1];
		d_list.data1 = NO_DATA;
		d_list.data2 = NO_DATA;
		d_list.data3 = NO_DATA;
		regs[1] = efuse_initialize(ANTIRBK_SEC);
		break;
	case DATA_INPUT_NANTIRBK0:
		d_list.data0 = read_sfr_value(NANTIRBK_VA + NANTIRBK0_BASE_OFFSET) | regs[1];
		d_list.data1 = read_sfr_value(NANTIRBK_VA + NANTIRBK0_BASE_OFFSET + 0x4) | regs[3];
		regs[1] = SUCCESS;
		break;
	case NANTIRBK0:
		d_list.data2 = read_sfr_value(NANTIRBK_VA + NANTIRBK0_BASE_OFFSET + 0x8) |  regs[1];
		d_list.data3 = read_sfr_value(NANTIRBK_VA + NANTIRBK0_BASE_OFFSET + 0xC) | regs[3];
		regs[1] = efuse_initialize(ANTIRBK0);
		break;
	case DATA_INPUT_NANTIRBK1:
		d_list.data0 = read_sfr_value(NANTIRBK_VA + NANTIRBK1_BASE_OFFSET) | regs[1];
		d_list.data1 = read_sfr_value(NANTIRBK_VA + NANTIRBK1_BASE_OFFSET + 0x4) | regs[3];
		regs[1] = SUCCESS;
		break;
	case NANTIRBK1:
		d_list.data2 = read_sfr_value(NANTIRBK_VA + NANTIRBK1_BASE_OFFSET + 0x8) | regs[1];
		d_list.data3 = NO_DATA;
		regs[1] = efuse_initialize(ANTIRBK1);
		break;
	case COMMERCIAL:
		if (read_sfr_value(MAIN_EFUSE_VA + 8) & TEST_BIT) {
			regs[1] = TEST_BIT_SET_ALREADY;
			break;
		}
		d_list.data0 = read_sfr_value(MAIN_EFUSE_VA);
		d_list.data1 = read_sfr_value(MAIN_EFUSE_VA + 0x4);
		d_list.data2 = read_sfr_value(MAIN_EFUSE_VA + 0x8) | COMMERCIAL_BIT;
		d_list.data3 = read_sfr_value(MAIN_EFUSE_VA + 0xC);

		regs[1] = efuse_initialize(MAIN_EFUSE);
		break;
	case TEST:
		if (read_sfr_value(MAIN_EFUSE_VA + 8) & COMMERCIAL_BIT) {
			regs[1] = COMMERCIAL_BIT_SET_ALREADY;
			break;
		}
		d_list.data0 = read_sfr_value(MAIN_EFUSE_VA);
		d_list.data1 = read_sfr_value(MAIN_EFUSE_VA + 0x4);
		d_list.data2 = read_sfr_value(MAIN_EFUSE_VA + 0x8) | TEST_BIT;
		d_list.data3 = read_sfr_value(MAIN_EFUSE_VA + 0xC);

		regs[1] = efuse_initialize(MAIN_EFUSE);
		break;
	case WARRANTY:
		d_list.data0 = read_sfr_value(MAIN_EFUSE_VA);;
		d_list.data1 = read_sfr_value(MAIN_EFUSE_VA + 0x4);
		d_list.data2 = read_sfr_value(MAIN_EFUSE_VA + 0x8) | WARRANTY_BIT;
		d_list.data3 = read_sfr_value(MAIN_EFUSE_VA + 0xC);

		regs[1] = efuse_initialize(MAIN_EFUSE);
		break;
	case EFUSE_BLOW:
		regs[1] = efuse_blow();
		break;
	case EFUSE_FINAL:
		regs[1] = efuse_finalize(regs[3]);
		d_list_clean();
		break;
	case READ:
		regs[1] = efuse_read(regs[3]);
		break;
	case W_ETC:
		d_list.data0 = read_sfr_value(MAIN_EFUSE_VA);
		d_list.data1 = read_sfr_value(MAIN_EFUSE_VA + 0x4);
		d_list.data2 = read_sfr_value(MAIN_EFUSE_VA + 0x8) | (1 << regs[3]);
		d_list.data3 = read_sfr_value(MAIN_EFUSE_VA + 0xC);

		regs[1] = efuse_initialize(MAIN_EFUSE);
		break;
	case R_ETC:
		regs[1] = ((read_sfr_value(MAIN_EFUSE_VA + 8) >> regs[3]) & ONE_BIT);
		break;
	default:
		regs[1] = NO_COMMAND;
	}
	return 0;
}
