static int hinfc610_onfi_enable_sync(struct nand_chip *chip)
{
	struct hinfc_host *host = chip->priv;
	unsigned char micron_sync_param[4] = {
		0x14, /* set sync mode timing */ 0x00, 0x00, 0x00,
	};

	host->enable_ecc_randomizer(host, DISABLE, DISABLE);

	hinfc_write(host, 1, HINFC610_DATA_NUM);
	hinfc_write(host, 0xEF, HINFC610_CMD);
	hinfc_write(host, 0x01, HINFC610_ADDRL);
	writel(micron_sync_param[0], host->chip->IO_ADDR_R);
	hinfc_write(host, HINFC610_WRITE_1CMD_1ADD_DATA, HINFC610_OP);
	WAIT_CONTROLLER_FINISH();

	writel(micron_sync_param[1], host->chip->IO_ADDR_R);
	hinfc_write(host, HINFC610_WRITE_0CMD_1ADD_DATA, HINFC610_OP);
	WAIT_CONTROLLER_FINISH();

	writel(micron_sync_param[2], host->chip->IO_ADDR_R);
	hinfc_write(host, HINFC610_WRITE_0CMD_1ADD_DATA, HINFC610_OP);
	WAIT_CONTROLLER_FINISH();

	/* need to config WAIT_READY_EN, here config this bit. */
	writel(micron_sync_param[3], host->chip->IO_ADDR_R);
	hinfc_write(host, HINFC610_WRITE_0CMD_1ADD_DATA_WAIT_READY,
			HINFC610_OP);
	WAIT_CONTROLLER_FINISH();

	host->enable_ecc_randomizer(host, ENABLE, ENABLE);

	return 0;
}
static int hinfc610_onfi_disable_sync(struct nand_chip *chip)
{
	struct hinfc_host *host = chip->priv;
	unsigned char micron_sync_param[4] = {
		0x00, 0x00, 0x00, 0x00,
	};

	host->enable_ecc_randomizer(host, DISABLE, DISABLE);

	hinfc_write(host, 1, HINFC610_DATA_NUM);
	hinfc_write(host, 0xEF, HINFC610_CMD);
	hinfc_write(host, 0x01, HINFC610_ADDRL);
	writel(micron_sync_param[0], host->chip->IO_ADDR_R);
	hinfc_write(host, HINFC610_WRITE_1CMD_1ADD_DATA_SYNC, HINFC610_OP);
	WAIT_CONTROLLER_FINISH();

	writel(micron_sync_param[1], host->chip->IO_ADDR_R);
	hinfc_write(host, HINFC610_WRITE_0CMD_1ADD_DATA_SYNC, HINFC610_OP);
	WAIT_CONTROLLER_FINISH();

	writel(micron_sync_param[2], host->chip->IO_ADDR_R);
	hinfc_write(host, HINFC610_WRITE_0CMD_1ADD_DATA_SYNC, HINFC610_OP);
	WAIT_CONTROLLER_FINISH();

	writel(micron_sync_param[3], host->chip->IO_ADDR_R);
	hinfc_write(host, HINFC610_WRITE_0CMD_1ADD_DATA_SYNC_WAIT_READY,
			HINFC610_OP);
	WAIT_CONTROLLER_FINISH();

	host->enable_ecc_randomizer(host, ENABLE, ENABLE);

	return 0;
}
Exemplo n.º 3
0
static int hinfc610_onfi_support_sync(struct hinfc_host *host)
{
	char buf[6];

	host->enable_ecc_randomizer(host, DISABLE, DISABLE);

	hinfc_write(host, sizeof(buf), HINFC610_DATA_NUM);
	hinfc_write(host, NAND_CMD_READID, HINFC610_CMD);
	hinfc_write(host, 0x20, HINFC610_ADDRL);
	hinfc_write(host, HINFC610_READ_1CMD_1ADD_DATA, HINFC610_OP);

	WAIT_CONTROLLER_FINISH();
	memcpy(buf, host->chip->IO_ADDR_R, sizeof(buf));

	if (memcmp(buf, "ONFI", 4))
		return 0;

	hinfc_write(host, sizeof(buf), HINFC610_DATA_NUM);
	hinfc_write(host, NAND_CMD_READID, HINFC610_CMD);
	hinfc_write(host, 0x40, HINFC610_ADDRL);
	hinfc_write(host, HINFC610_READ_1CMD_1ADD_DATA, HINFC610_OP);

	WAIT_CONTROLLER_FINISH();
	memcpy(buf, host->chip->IO_ADDR_R, sizeof(buf));

	if (memcmp(buf, "JEDEC", 5))
		return 0;

	return (buf[5] == 0x05);
}
Exemplo n.º 4
0
static int hinfc504_samsung_set_rr_reg(struct hinfc_host *host,int param)
{
#define SAMSUNG_RR_CMD     0xA1

	unsigned char samsung_rr_params[15][4] = {
		{0x00, 0x00, 0x00, 0x00},
		{0x05, 0x0A, 0x00, 0x00},
		{0x28, 0x00, 0xEC, 0xD8},
		{0xED, 0xF5, 0xED, 0xE6},
		{0x0A, 0x0F, 0x05, 0x00},
		{0x0F, 0x0A, 0xFB, 0xEC},
		{0xE8, 0xEF, 0xE8, 0xDC},
		{0xF1, 0xFB, 0xFE, 0xF0},
		{0x0A, 0x00, 0xFB, 0xEC},
		{0xD0, 0xE2, 0xD0, 0xC2},
		{0x14, 0x0F, 0xFB, 0xEC},
		{0xE8, 0xFB, 0xE8, 0xDC},
		{0x1E, 0x14, 0xFB, 0xEC},
		{0xFB, 0xFF, 0xFB, 0xF8},
		{0x07, 0x0C, 0x02, 0x00}
	};

	if (param >= 15)
		param = (param % 15);

	hinfc_write(host, 1, HINFC504_DATA_NUM);

	writel(samsung_rr_params[param][0], host->chip->IO_ADDR_R);
	hinfc_write(host, 0xA700, HINFC504_ADDRL);
	hinfc_write(host, SAMSUNG_RR_CMD, HINFC504_CMD);
	hinfc_write(host, HINFC504_WRITE_1CMD_2ADD_DATA, HINFC504_OP);
	WAIT_CONTROLLER_FINISH();

	writel(samsung_rr_params[param][1], host->chip->IO_ADDR_R);
	hinfc_write(host, 0xA400, HINFC504_ADDRL);
	hinfc_write(host, SAMSUNG_RR_CMD, HINFC504_CMD);
	hinfc_write(host, HINFC504_WRITE_1CMD_2ADD_DATA, HINFC504_OP);
	WAIT_CONTROLLER_FINISH();

	writel(samsung_rr_params[param][2], host->chip->IO_ADDR_R);
	hinfc_write(host, 0xA500, HINFC504_ADDRL);
	hinfc_write(host, SAMSUNG_RR_CMD, HINFC504_CMD);
	hinfc_write(host, HINFC504_WRITE_1CMD_2ADD_DATA, HINFC504_OP);
	WAIT_CONTROLLER_FINISH();

	writel(samsung_rr_params[param][3], host->chip->IO_ADDR_R);
	hinfc_write(host, 0xA600, HINFC504_ADDRL);
	hinfc_write(host, SAMSUNG_RR_CMD, HINFC504_CMD);
	hinfc_write(host, HINFC504_WRITE_1CMD_2ADD_DATA, HINFC504_OP);
	WAIT_CONTROLLER_FINISH();

	return 0;

#undef SAMSUNG_RR_CMD
}
Exemplo n.º 5
0
static int hinfc610_toshiba_24nm_set_rr_param(struct hinfc_host *host, int param)
{
	hinfc_write(host, HINFC_CMD_SEQ(0x5C, 0xC5), HINFC610_CMD);
	hinfc_write(host, HINFC610_WRITE_2CMD_0ADD_NODATA, HINFC610_OP);
	WAIT_CONTROLLER_FINISH();

	hinfc610_toshiba_24nm_set_rr_reg(host, param);

	hinfc_write(host, HINFC_CMD_SEQ(0x26, 0x5D), HINFC610_CMD);
	hinfc_write(host, HINFC610_WRITE_2CMD_0ADD_NODATA, HINFC610_OP);
	WAIT_CONTROLLER_FINISH();

	return 0;
}
static int hinfc610_toshiba_24nm_set_rr_reg(struct hinfc_host *host, int param)
{
#define TOSHIBA_RR_CMD     0x55
	int opval;
	static char toshiba_rr_param[] = {0x00, 0x04, 0x7c, 0x78, 0x74, 0x08};

	if (!param) {
		host->send_cmd_reset(host, host->chipselect);
		return 0;
	}

	if (param >= 6)
		param = (param % 6);

	/*
	 * no need to config WAIT_READY_EN, here not config WAIT_READY_EN
	 */
	opval = (HINFC610_IS_SYNC(host) ? HINFC610_WRITE_1CMD_1ADD_DATA_SYNC
		: HINFC610_WRITE_1CMD_1ADD_DATA);

	hinfc_write(host, 1, HINFC610_DATA_NUM);

	writel(toshiba_rr_param[param], host->chip->IO_ADDR_R);
	hinfc_write(host, 0x4, HINFC610_ADDRL);
	hinfc_write(host, TOSHIBA_RR_CMD, HINFC610_CMD);
	hinfc_write(host, opval, HINFC610_OP);
	WAIT_CONTROLLER_FINISH();

	writel(toshiba_rr_param[param], host->chip->IO_ADDR_R);
	hinfc_write(host, 0x5, HINFC610_ADDRL);
	hinfc_write(host, TOSHIBA_RR_CMD, HINFC610_CMD);
	hinfc_write(host, opval, HINFC610_OP);
	WAIT_CONTROLLER_FINISH();

	writel(toshiba_rr_param[param], host->chip->IO_ADDR_R);
	hinfc_write(host, 0x6, HINFC610_ADDRL);
	hinfc_write(host, TOSHIBA_RR_CMD, HINFC610_CMD);
	hinfc_write(host, opval, HINFC610_OP);
	WAIT_CONTROLLER_FINISH();

	writel(toshiba_rr_param[param], host->chip->IO_ADDR_R);
	hinfc_write(host, 0x7, HINFC610_ADDRL);
	hinfc_write(host, TOSHIBA_RR_CMD, HINFC610_CMD);
	hinfc_write(host, opval, HINFC610_OP);
	WAIT_CONTROLLER_FINISH();

	return 0;

#undef TOSHIBA_RR_CMD
}
static void hinfc504_hynix_cg_adie_get_rr(struct hinfc_host *host)
{
	int index;

	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
	hinfc_write(host, 1, HINFC504_DATA_NUM);

	for (index = 0; index < 8; index++) {
		memset(host->chip->IO_ADDR_R, 0xff, 1024);
		hinfc_write(host, 
			0x37, HINFC504_CMD);
		hinfc_write(host, 
			hinfc504_hynix_cg_adie__rr_reg[index], 
			HINFC504_ADDRL);
		hinfc_write(host, 
			HINFC504_READ_1CMD_1ADD_DATA, 
			HINFC504_OP);

		WAIT_CONTROLLER_FINISH();
	
		printf("%02X ", readl(host->chip->IO_ADDR_R) & 0xff);
	}

	host->enable_ecc_randomizer(host, ENABLE, ENABLE);
}
Exemplo n.º 8
0
static int hinfc610_get_onfi_info(struct hinfc_host *host, int *type)
{
	char buf[6];

	*type = 0;

	if (!hinfc610_onfi_support_sync(host))
		return 0;

	host->enable_ecc_randomizer(host, DISABLE, DISABLE);

	hinfc_write(host, sizeof(buf), HINFC610_DATA_NUM);
	hinfc_write(host, NAND_CMD_PARAM, HINFC610_CMD);
	hinfc_write(host, 0x00, HINFC610_ADDRL);
	hinfc_write(host, HINFC610_READ_1CMD_1ADD_DATA, HINFC610_OP);

	WAIT_CONTROLLER_FINISH();
	memcpy(buf, host->chip->IO_ADDR_R, sizeof(buf));

	if (memcmp(buf, "ONFI", 4))
		return 0;

	if (buf[4] & (1 << 6))
		*type = NAND_TYPE_ONFI_30;
	else if (buf[4] & (1 << 5) ||
		 buf[4] & (1 << 4) ||
		 buf[4] & (1 << 3) ||
		 buf[4] & (1 << 2))
		*type = NAND_TYPE_ONFI_23;

	return 1;
}
Exemplo n.º 9
0
static int hinfc610_get_toggle_info(struct hinfc_host *host, int *type)
{
	char buf[8];

	*type = 0;

	if (!hinfc610_toggle_support_sync(host))
		return 0;

	host->enable_ecc_randomizer(host, DISABLE, DISABLE);

	hinfc_write(host, sizeof(buf), HINFC610_DATA_NUM);
	hinfc_write(host, NAND_CMD_PARAM, HINFC610_CMD);
	hinfc_write(host, 0x40, HINFC610_ADDRL);
	hinfc_write(host, HINFC610_READ_1CMD_1ADD_DATA, HINFC610_OP);

	WAIT_CONTROLLER_FINISH();

	memcpy(buf, host->chip->IO_ADDR_R, sizeof(buf));

	if (memcmp(buf, "JESD", 4))
		return 0;

	if (buf[4] & (1 << 1))
		/* supports revision 1.0 */
		*type = NAND_TYPE_TOGGLE_10;
	else
		pr_warn("sync NAND has unknown toggle revision.\n");

	return 1;
}
Exemplo n.º 10
0
static int hinfc610_toshiba_24nm_set_rr_reg(struct hinfc_host *host, int param)
{
#define TOSHIBA_RR_CMD     0x55

	static char toshiba_rr_param[] = {0x00, 0x04, 0x7c, 0x78, 0x74, 0x08};

	if (!param) {
		host->send_cmd_reset(host, host->chipselect);
		return 0;
	}

	if (param >= 6)
		param = (param % 6);

	hinfc_write(host, 1, HINFC610_DATA_NUM);

	writel(toshiba_rr_param[param], host->chip->IO_ADDR_R);
	hinfc_write(host, 0x4, HINFC610_ADDRL);
	hinfc_write(host, TOSHIBA_RR_CMD, HINFC610_CMD);
	hinfc_write(host, HINFC610_WRITE_1CMD_1ADD_DATA, HINFC610_OP);
	WAIT_CONTROLLER_FINISH();

	writel(toshiba_rr_param[param], host->chip->IO_ADDR_R);
	hinfc_write(host, 0x5, HINFC610_ADDRL);
	hinfc_write(host, TOSHIBA_RR_CMD, HINFC610_CMD);
	hinfc_write(host, HINFC610_WRITE_1CMD_1ADD_DATA, HINFC610_OP);
	WAIT_CONTROLLER_FINISH();

	writel(toshiba_rr_param[param], host->chip->IO_ADDR_R);
	hinfc_write(host, 0x6, HINFC610_ADDRL);
	hinfc_write(host, TOSHIBA_RR_CMD, HINFC610_CMD);
	hinfc_write(host, HINFC610_WRITE_1CMD_1ADD_DATA, HINFC610_OP);
	WAIT_CONTROLLER_FINISH();

	writel(toshiba_rr_param[param], host->chip->IO_ADDR_R);
	hinfc_write(host, 0x7, HINFC610_ADDRL);
	hinfc_write(host, TOSHIBA_RR_CMD, HINFC610_CMD);
	hinfc_write(host, HINFC610_WRITE_1CMD_1ADD_DATA, HINFC610_OP);
	WAIT_CONTROLLER_FINISH();

	return 0;

#undef TOSHIBA_RR_CMD
}
static int hinfc610_toshiba_24nm_set_rr_param(struct hinfc_host *host,
		int param)
{
	int opval;

	host->enable_ecc_randomizer(host, DISABLE, DISABLE);

	opval = (HINFC610_IS_SYNC(host) ? HINFC610_WRITE_2CMD_0ADD_NODATA_SYNC
		: HINFC610_WRITE_2CMD_0ADD_NODATA);

	hinfc_write(host, HINFC_CMD_SEQ(0x5C, 0xC5), HINFC610_CMD);
	hinfc_write(host, opval, HINFC610_OP);
	WAIT_CONTROLLER_FINISH();

	hinfc610_toshiba_24nm_set_rr_reg(host, param);

	hinfc_write(host, HINFC_CMD_SEQ(0x26, 0x5D), HINFC610_CMD);
	hinfc_write(host, opval, HINFC610_OP);
	WAIT_CONTROLLER_FINISH();

	host->enable_ecc_randomizer(host, ENABLE, ENABLE);

	return 0;
}
static int hinfc504_hynix_cg_adie_set_rr_reg(struct hinfc_host *host, char *val)
{
	int i;
	
	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
	hinfc_write(host, 1, HINFC504_DATA_NUM);/* data length 1 */

	for (i = 0; i <= 8; i++) {
		switch (i) {
		case 0:
			writel(val[i], host->chip->IO_ADDR_R);
			hinfc_write(host, 
				hinfc504_hynix_cg_adie__rr_reg[i], HINFC504_ADDRL);
			hinfc_write(host,
				0x36, HINFC504_CMD);
			hinfc_write(host,
				HINFC504_WRITE_1CMD_1ADD_DATA,
				HINFC504_OP);
			break;
		case 8:
			hinfc_write(host,
				0x16, HINFC504_CMD);
			hinfc_write(host,
				HINFC504_WRITE_1CMD_0ADD_NODATA,
				HINFC504_OP);
			break;
		default:
			writel(val[i], host->chip->IO_ADDR_R);
			hinfc_write(host, 
				hinfc504_hynix_cg_adie__rr_reg[i], HINFC504_ADDRL);
			hinfc_write(host,
				HINFC504_WRITE_0CMD_1ADD_DATA,
				HINFC504_OP);
			break;
		}
		WAIT_CONTROLLER_FINISH();
	}
	host->enable_ecc_randomizer(host, ENABLE, ENABLE);
	return 0;
}
static int hinfc610_hynix_bg_bdie_set_rr_reg(struct hinfc_host *host, int index)
{
	int ix;
	char HYNIX_BG_BDIE_RR_REG[4] = {0xA7,  0xAD,  0xAE,  0xAF};
	char value_offset[7][4] = {
		{0x00,  0x00,  0x00,  0x00},
		{0x00,  0x06,  0x0A,  0x06},
		{0x7F, -0x03, -0x07, -0x08},
		{0x7F, -0x06, -0x0D, -0x0F},
		{0x7F, -0x09, -0x14, -0x17},
		{0x7F,  0x7F, -0x1A, -0x1E},
		{0x7F,  0x7F, -0x20, -0x25}
	};
	char *value = &value_offset[index][0];

	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
	hinfc_write(host, 1, HINFC610_DATA_NUM);

	if (!hynix_bg_bdie_rr_org_exist) {

		for (ix = 0; ix < 4; ix++) {

			memset(host->chip->IO_ADDR_R, 0xff, 32);

			hinfc_write(host, 0x37, HINFC610_CMD);
			hinfc_write(host, HYNIX_BG_BDIE_RR_REG[ix],
				HINFC610_ADDRL);
			/* 
			 * according to hynix doc, no need to config HINFC610_OP_WAIT_READY_EN,
			 * here not config this bit, confirmed by yubingxu.
			 */
			hinfc_write(host, HINFC610_READ_1CMD_1ADD_DATA,
				HINFC610_OP);
			WAIT_CONTROLLER_FINISH();

			hynix_bg_bdie_rr_org[ix]
				= (char)(readl(host->chip->IO_ADDR_R) & 0xff);
		}
		hynix_bg_bdie_rr_org_exist = 1;
	}

	for (ix = 0; ix < 4; ix++) {
		if (value[ix] == 0x7F)
			value[ix] = 0x00;
		else
			value[ix] += hynix_bg_bdie_rr_org[ix];
	}

	writel(value[0], host->chip->IO_ADDR_W);
	hinfc_write(host, HYNIX_BG_BDIE_RR_REG[0], HINFC610_ADDRL);
	hinfc_write(host, 0x36, HINFC610_CMD);
	/*
	 * according to hynix doc, no need to config HINFC610_OP_WAIT_READY_EN,
	 * here not config this bit.
	 */
	hinfc_write(host, HINFC610_WRITE_1CMD_1ADD_DATA, HINFC610_OP);
	WAIT_CONTROLLER_FINISH();

	for (ix = 1; ix < 4; ix++) {
		writel(value[ix], host->chip->IO_ADDR_W);
		hinfc_write(host, HYNIX_BG_BDIE_RR_REG[ix], HINFC610_ADDRL);
		/*
		 * according to hynix doc, no need to config HINFC610_OP_WAIT_READY_EN,
		 * here not config this bit.
		 */		
		hinfc_write(host, HINFC610_WRITE_0CMD_1ADD_DATA, HINFC610_OP);
		WAIT_CONTROLLER_FINISH();
	}

	hinfc_write(host, 0x16, HINFC610_CMD);
	/*
	 * according to hynix doc, only 1 cmd: 0x16. 
	 * And no need to config HINFC610_OP_WAIT_READY_EN, here not config this bit.
	 */
	hinfc_write(host, HINFC610_WRITE_1CMD_0ADD_NODATA, HINFC610_OP);
	WAIT_CONTROLLER_FINISH();

	host->enable_ecc_randomizer(host, ENABLE, ENABLE);

	return 0;
}
static int hinfc504_hynix_cg_adie_get_rr_param(struct hinfc_host *host)
{
	char *otp;

	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
	/* step1: reset the chip */
	host->send_cmd_reset(host, host->chipselect);

	/* step2: cmd: 0x36, address: 0xFF, data: 0x40 */
	hinfc_write(host, 1, HINFC504_DATA_NUM);/* data length 1 */
	writel(0x40, host->chip->IO_ADDR_R); /* data: 0x00 */
	hinfc_write(host, 0xFF, HINFC504_ADDRL);/* address: 0xAE */
	hinfc_write(host, 0x36, HINFC504_CMD);  /* cmd: 0x36 */
	hinfc_write(host, HINFC504_WRITE_1CMD_1ADD_DATA, HINFC504_OP);
	WAIT_CONTROLLER_FINISH();

	/* step3: address: 0xCC, data: 0x4D */
	hinfc_write(host, 1, HINFC504_DATA_NUM);/* data length 1 */
	writel(0x4D, host->chip->IO_ADDR_R); /* data: 0x4d */
	hinfc_write(host, 0xCC, HINFC504_ADDRL);/* address: 0xB0 */
	/* only address and data, without cmd */
	hinfc_write(host, HINFC504_WRITE_0CMD_1ADD_DATA, HINFC504_OP);
	WAIT_CONTROLLER_FINISH();

	/* step4: cmd: 0x16, 0x17, 0x04, 0x19 */
	hinfc_write(host, 0x17 << 8 | 0x16, HINFC504_CMD);
	hinfc_write(host, HINFC504_WRITE_2CMD_0ADD_NODATA, HINFC504_OP);
	WAIT_CONTROLLER_FINISH();

	hinfc_write(host, 0x19 << 8 | 0x04, HINFC504_CMD);
	hinfc_write(host, HINFC504_WRITE_2CMD_0ADD_NODATA, HINFC504_OP);
	WAIT_CONTROLLER_FINISH();

	/* step5: cmd: 0x00 0x30, address: 0x02 00 00 00 */
	hinfc_write(host, 0x2000000, HINFC504_ADDRL);
	hinfc_write(host, 0x00, HINFC504_ADDRH);
	hinfc_write(host, 0x30 << 8 | 0x00, HINFC504_CMD);
	hinfc_write(host, 0x800, HINFC504_DATA_NUM);
	hinfc_write(host, HINFC504_READ_2CMD_5ADD, HINFC504_OP);
	WAIT_CONTROLLER_FINISH();

	/*step6 save otp read retry table to mem*/
	otp = hinfc504_hynix_cg_adie_otp_check(host->chip->IO_ADDR_R + 2);
	if (!otp) {
		printf("Read Retry select parameter failed, "
		       "this Nand Chip maybe unstable!\n");
		return -1;
	}
	memcpy(host->rr_data, otp, 64);
	host->need_rr_data = 1;

	/* step7: reset the chip */
	host->send_cmd_reset(host, host->chipselect);

	/* step8: cmd: 0x38 */
	hinfc_write(host, 0x38, HINFC504_CMD);
	hinfc_write(host, HINFC504_WRITE_1CMD_0ADD_NODATA_WAIT_READY, HINFC504_OP);
	WAIT_CONTROLLER_FINISH();

	host->enable_ecc_randomizer(host, ENABLE, ENABLE);
	/* get hynix otp table finish */
	return 0;
}
static int hinfc504_hynix_cg_adie_eslc_enable(struct hinfc_host *host, int enable)
{
	int ix;
	char HYNIX_CG_ADIE_ESLC_REG[4] = {0xB0, 0xB1, 0xA0, 0xA1};

	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
	hinfc_write(host, 1, HINFC504_DATA_NUM);

	for (ix = 0; enable && ix < 4; ix++) {
		memset(host->chip->IO_ADDR_R, 0xff, 32);
		hinfc_write(host, 
			0x37, HINFC504_CMD);
		hinfc_write(host, 
			HYNIX_CG_ADIE_ESLC_REG[ix], 
			HINFC504_ADDRL);
		hinfc_write(host, 
			HINFC504_READ_1CMD_1ADD_DATA, 
			HINFC504_OP);
		WAIT_CONTROLLER_FINISH();

		HYNIX_CG_ADIE_ESLC_PARAM[ix] = 
			(char)(readl(host->chip->IO_ADDR_R) & 0xff);
	}

	for (ix = 0; ix <= 4; ix++) {
		int offset = enable ? 0x0A : 0x00;
		switch (ix) {
		case 0:
			writel(HYNIX_CG_ADIE_ESLC_PARAM[ix] + offset, 
				host->chip->IO_ADDR_R);
			hinfc_write(host, 
				HYNIX_CG_ADIE_ESLC_REG[ix], 
				HINFC504_ADDRL);
			hinfc_write(host,
				0x36, HINFC504_CMD);
			hinfc_write(host,
				HINFC504_WRITE_1CMD_1ADD_DATA,
				HINFC504_OP);
			break;
		case 4:
			hinfc_write(host,
				0x16, HINFC504_CMD);
			hinfc_write(host,
				HINFC504_WRITE_1CMD_0ADD_NODATA,
				HINFC504_OP);
			break;
		default:
			writel(HYNIX_CG_ADIE_ESLC_PARAM[ix] + offset, 
				host->chip->IO_ADDR_R);
			hinfc_write(host, 
				HYNIX_CG_ADIE_ESLC_REG[ix], 
				HINFC504_ADDRL);
			hinfc_write(host,
				HINFC504_WRITE_0CMD_1ADD_DATA,
				HINFC504_OP);
			break;
		}
		WAIT_CONTROLLER_FINISH();
	}

	host->enable_ecc_randomizer(host, ENABLE, ENABLE);

	if (!enable) {
		hinfc_write(host, 
			host->addr_value[0] & 0xffff0000, 
			HINFC504_ADDRL);
		hinfc_write(host, 
			host->addr_value[1], 
			HINFC504_ADDRH);
		hinfc_write(host, 
			NAND_CMD_READSTART << 8 | NAND_CMD_READ0,
			HINFC504_CMD);
		hinfc_write(host,
			HINFC504_READ_2CMD_5ADD,
			HINFC504_OP);

		WAIT_CONTROLLER_FINISH();
	}

	return 0;
}
static int hinfc504_hynix_bg_bdie_set_rr_reg(struct hinfc_host *host, int index)
{
	int ix;
	char HYNIX_BG_BDIE_RR_REG[4] = {0xA7,  0xAD,  0xAE,  0xAF};
	char value_offset[7][4] = {
		{0x00,  0x00,  0x00,  0x00},
		{0x00,  0x06,  0x0A,  0x06},
		{0x7F, -0x03, -0x07, -0x08},
		{0x7F, -0x06, -0x0D, -0x0F},
		{0x7F, -0x09, -0x14, -0x17},
		{0x7F,  0x7F, -0x1A, -0x1E},
		{0x7F,  0x7F, -0x20, -0x25}
	};
	char *value = &value_offset[index][0];

	host->enable_ecc_randomizer(host, DISABLE, DISABLE);
	hinfc_write(host, 1, HINFC504_DATA_NUM);

	if (!hynix_bg_bdie_rr_org_exist) {

		for (ix = 0; ix < 4; ix++) {

			memset(host->chip->IO_ADDR_R, 0xff, 32);

			hinfc_write(host, 0x37, HINFC504_CMD);
			hinfc_write(host, HYNIX_BG_BDIE_RR_REG[ix],
				HINFC504_ADDRL);
			hinfc_write(host, HINFC504_READ_1CMD_1ADD_DATA,
				HINFC504_OP);
			WAIT_CONTROLLER_FINISH();

			hynix_bg_bdie_rr_org[ix]
				= (char)(readl(host->chip->IO_ADDR_R) & 0xff);
		}
		hynix_bg_bdie_rr_org_exist = 1;
	}

	for (ix = 0; ix < 4; ix++) {
		if (value[ix] == 0x7F)
			value[ix] = 0x00;
		else
			value[ix] += hynix_bg_bdie_rr_org[ix];
	}

	writel(value[0], host->chip->IO_ADDR_W);
	hinfc_write(host, HYNIX_BG_BDIE_RR_REG[0], HINFC504_ADDRL);
	hinfc_write(host, 0x36, HINFC504_CMD);
	hinfc_write(host, HINFC504_WRITE_1CMD_1ADD_DATA, HINFC504_OP);
	WAIT_CONTROLLER_FINISH();

	for (ix = 1; ix < 4; ix++) {
		writel(value[ix], host->chip->IO_ADDR_W);
		hinfc_write(host, HYNIX_BG_BDIE_RR_REG[ix], HINFC504_ADDRL);
		hinfc_write(host, HINFC504_WRITE_0CMD_1ADD_DATA, HINFC504_OP);
		WAIT_CONTROLLER_FINISH();
	}

	hinfc_write(host, 0x16, HINFC504_CMD);
	hinfc_write(host, HINFC504_WRITE_1CMD_0ADD_NODATA, HINFC504_OP);
	WAIT_CONTROLLER_FINISH();

	host->enable_ecc_randomizer(host, ENABLE, ENABLE);

	return 0;
}