/*
 * ndfc_v2px.c
 * Copyright (C) 2019 Allwinner.
 * 2019.9.19 cuizhikui<cuizhikui@allwinnertech.com>
 *
 *
 * SPDX-License-Identifier: GPL-2.0
 */
#include <linux/string.h>
#include "../../../nand_osal_uboot.h"
#include "../../nand_physic_interface.h"
#include "../rawnand_cfg.h"
#include "../rawnand_debug.h"
#include "ndfc_ops.h"
/*#include "../rawnand.h"*/
#include <sunxi_nand.h>

#define NDFC_VERSION_2 (0X02)

s32 init_nctri(struct nand_controller_info *nctri)
{
	s32 ret = 0;
	u32 cfg = 0;

	nctri->type = NAND_GetNdfcVersion();
	nctri->dma_type = NAND_GetNdfcDmaMode();

	nctri->write_wait_rb_before_cmd_io = g_phy_cfg->phy_wait_rb_before; //1: before send cmd io; 0: after send cmd io;
	nctri->write_wait_rb_mode = g_phy_cfg->phy_wait_rb_mode;	    //0: query mode; 1: interrupt mode
	nctri->write_wait_dma_mode = g_phy_cfg->phy_wait_dma_mode;
	nctri->rb_ready_flag = 1;
	nctri->dma_ready_flag = 0;

	if (nctri->type == NDFC_VERSION_V1)
		nctri->max_ecc_level = 14;
	else if (nctri->type == NDFC_VERSION_V2)
		nctri->max_ecc_level = 9;
	else {
		RAWNAND_ERR("init nctri, request dma fail!\n");
		ret = ERR_NO_26;
		goto ERR;
	}

	if (NAND_GetVoltage())
		return -1;

	if (nctri->dma_type == DMA_MODE_GENERAL_DMA) {
		if (nand_request_dma() != 0) {
			RAWNAND_ERR("init nctri, request dma fail!\n");
			ret = ERR_NO_25;
			goto ERR;
		}
	}

	if (NAND_PIORequest(nctri->channel_id) != 0) {
		RAWNAND_ERR("init nctri NAND PIORequest error!\n");
		ret = ERR_NO_24;
		goto ERR;
	}

	if (NAND_ClkRequest(nctri->channel_id) != 0) {
		RAWNAND_ERR("init nctri NAND_ClkRequest error!\n");
		ret = ERR_NO_23;
		goto ERR;
	}

	NAND_SetClk(nctri->channel_id, 20, 20 * 2);

	//soft reset ndfc
	ndfc_soft_reset(nctri);

	//set NFC_REG_CTL
	cfg = 0;
	cfg |= ((0x0 & 0x1) << 6);  //ce_ctl
	cfg |= ((0x0 & 0x1) << 7);  //ce_ctl1
	cfg |= ((0x1 & 0xf) << 8);  //page size, 2KB
	cfg |= ((0x0 & 0x1) << 31); //debug
	/**nctri->nreg.reg_ctl = cfg;*/
	writel(cfg, nctri->nreg.reg_ctl);

	//enable nand flash controller
	/**nctri->nreg.reg_glb_cfg |= NDFC_EN;*/
	cfg = readl(nctri->nreg.reg_glb_cfg);
	cfg |= NDFC_EN;
	writel(cfg, nctri->nreg.reg_glb_cfg);

	//set NFC_SPARE_AREA
	/**nctri->nreg.reg_spare_area = 2048; //2KB*/
	writel(2048, nctri->nreg.reg_spare_area);//2KB

	//disable write protect
	/**nctri->nreg.reg_efr = 0x100;*/
	writel(0x100, nctri->nreg.reg_efr);

	//disable randomize
	ndfc_disable_randomize(nctri);

	//init nand flash interface
	ndfc_change_nand_interface(nctri, 0, 1, 0, 0);

	return ret;

ERR:
	return ret;
}

s32 save_nctri(struct nand_controller_info *nctri)
{
	nctri->nreg_bak.reg_ctl = readl(nctri->nreg.reg_ctl);
	nctri->nreg_bak.reg_sta = readl(nctri->nreg.reg_sta);
	nctri->nreg_bak.reg_int = readl(nctri->nreg.reg_int);
	nctri->nreg_bak.reg_timing_ctl = readl(nctri->nreg.reg_timing_ctl);
	nctri->nreg_bak.reg_timing_cfg = readl(nctri->nreg.reg_timing_cfg);
	nctri->nreg_bak.reg_addr_low = readl(nctri->nreg.reg_addr_low);
	nctri->nreg_bak.reg_addr_high = readl(nctri->nreg.reg_addr_high);
	nctri->nreg_bak.reg_data_block_mask = readl(nctri->nreg.reg_data_block_mask);
	nctri->nreg_bak.reg_ndfc_cnt = readl(nctri->nreg.reg_ndfc_cnt);
	nctri->nreg_bak.reg_cmd = readl(nctri->nreg.reg_cmd);
	nctri->nreg_bak.reg_read_cmd_set = readl(nctri->nreg.reg_read_cmd_set);
	nctri->nreg_bak.reg_write_cmd_set = readl(nctri->nreg.reg_write_cmd_set);
	nctri->nreg_bak.reg_ecc_ctl = readl(nctri->nreg.reg_ecc_ctl);
	nctri->nreg_bak.reg_ecc_sta = readl(nctri->nreg.reg_ecc_sta);
	nctri->nreg_bak.reg_data_pattern_sta = readl(nctri->nreg.reg_data_pattern_sta);
	nctri->nreg_bak.reg_efr = readl(nctri->nreg.reg_efr);
	nctri->nreg_bak.reg_rdata_sta_ctl = readl(nctri->nreg.reg_rdata_sta_ctl);
	nctri->nreg_bak.reg_rdata_sta_0 = readl(nctri->nreg.reg_rdata_sta_0);
	nctri->nreg_bak.reg_rdata_sta_1 = readl(nctri->nreg.reg_rdata_sta_1);
	nctri->nreg_bak.reg_err_cnt0 = readl(nctri->nreg.reg_err_cnt0);
	nctri->nreg_bak.reg_err_cnt1 = readl(nctri->nreg.reg_err_cnt1);
	nctri->nreg_bak.reg_err_cnt2 = readl(nctri->nreg.reg_err_cnt2);
	nctri->nreg_bak.reg_err_cnt3 = readl(nctri->nreg.reg_err_cnt3);
	nctri->nreg_bak.reg_err_cnt4 = readl(nctri->nreg.reg_err_cnt4);
	nctri->nreg_bak.reg_err_cnt5 = readl(nctri->nreg.reg_err_cnt5);
	nctri->nreg_bak.reg_err_cnt6 = readl(nctri->nreg.reg_err_cnt6);
	nctri->nreg_bak.reg_err_cnt7 = readl(nctri->nreg.reg_err_cnt7;
	nctri->nreg_bak.reg_user_data_len_base = readl(nctri->nreg.reg_user_data_len_base);
	nctri->nreg_bak.reg_user_data_base = readl(nctri->nreg.reg_user_data_base);
	nctri->nreg_bak.reg_flash_sta = readl(nctri->nreg.reg_flash_sta);
	nctri->nreg_bak.reg_cmd_repeat_cnt = readl(nctri->nreg.reg_cmd_repeat_cnt);
	nctri->nreg_bak.reg_cmd_repeat_interval = readl(nctri->nreg.reg_cmd_repeat_interval);
	nctri->nreg_bak.reg_efnand_sta = readl(nctri->nreg.reg_efnand_sta);
	nctri->nreg_bak.reg_spare_area = readl(nctri->nreg.reg_spare_area);
	nctri->nreg_bak.reg_pat_id = readl(nctri->nreg.reg_pat_id);
	nctri->nreg_bak.reg_ddr2_spec_ctl = readl(nctri->nreg.reg_ddr2_spec_ctl);
	nctri->nreg_bak.reg_ndma_mode_ctl = readl(nctri->nreg.reg_ndma_mode_ctl);
	nctri->nreg_bak.reg_valid_data_dma_cnt = readl(nctri->nreg.reg_valid_data_dma_cnt);
	nctri->nreg_bak.reg_data_dma_base = readl(nctri->nreg.reg_data_dma_base);
	nctri->nreg_bak.reg_data_dma_size_2x = readl(nctri->nreg.reg_data_dma_size_2x);
	nctri->nreg_bak.reg_random_seed_x = readl(nctri->nreg.reg_random_seed_x);
	nctri->nreg_bak.reg_dma_cnt = readl(nctri->nreg.reg_dma_cnt);
	nctri->nreg_bak.reg_emce_ctl = readl(nctri->nreg.reg_emce_ctl);
	nctri->nreg_bak.reg_emce_iv_fac_cmp_val = readl(nctri->nreg.reg_emce_iv_fac_cmp_val);
	nctri->nreg_bak.reg_emce_iv_cal_fac_base = readl(nctri->nreg.reg_emce_iv_cal_fac_base);
	nctri->nreg_bak.reg_io_data = readl(nctri->nreg.reg_io_data);
	nctri->nreg_bak.reg_ndfc_ver = readl(nctri->nreg.reg_ndfc_ver);
	nctri->nreg_bak.reg_ldpc_ctl = readl(nctri->nreg.reg_ldpc_ctl);
	nctri->nreg_bak.reg_enc_ldpc_mode_set = readl(nctri->nreg.reg_enc_ldpc_mode_set);
	nctri->nreg_bak.reg_cor_ldpc_mode_set = readl(nctri->nreg.reg_cor_ldpc_mode_set);
	nctri->nreg_bak.reg_c0_llr_tbl_addr = readl(nctri->nreg.reg_c0_llr_tbl_addr);
	nctri->nreg_bak.reg_c1_llr_tbl_addr = readl(nctri->nreg.reg_c1_llr_tbl_addr);
	nctri->nreg_bak.reg_ram0_base = readl(nctri->nreg.reg_ram0_base);
	nctri->nreg_bak.reg_ram1_base = readl(nctri->nreg.reg_ram1_base);
	nctri->nreg_bak.reg_glb_cfg = readl(nctri->nreg.reg_glb_cfg);
	nctri->nreg_bak.reg_cmd_descr_base_addr = readl(nctri->nreg.reg_cmd_descr_base_addr);
	nctri->nreg_bak.reg_cmd_descr_sta = readl(nctri->nreg.reg_cmd_descr_sta);
	nctri->nreg_bak.reg_cmd_descr_intr = readl(nctri->nreg.reg_cmd_descr_intr);
	nctri->nreg_bak.reg_csic_bist_ctl_reg = readl(nctri->nreg.reg_csic_bist_ctl_reg);
	nctri->nreg_bak.reg_bist_start_addr = readl(nctri->nreg.reg_bist_start_addr);
	nctri->nreg_bak.reg_bist_end_addr = readl(nctri->nreg.reg_bist_end_addr);
	nctri->nreg_bak.reg_bist_data_mask = readl(nctri->nreg.reg_bist_data_mask);
	return 0;
}

void ndfc_print_save_reg(struct nand_controller_info *nctri)
{
	RAWNAND_DBG("print ndfc save reg:\n");
	RAWNAND_DBG("0x0000 reg_ctl:			0x%08x\n", nctri->nreg.reg_ctl);
	RAWNAND_DBG("0x0004 reg_sta:			0x%08x\n", nctri->nreg.reg_sta);
	RAWNAND_DBG("0x0008 reg_int:			0x%08x\n", nctri->nreg.reg_int);
	RAWNAND_DBG("0x000C reg_timing_ctl:		0x%08x\n", nctri->nreg.reg_timing_ctl);
	RAWNAND_DBG("0x0010 reg_timing_cfg:		0x%08x\n", nctri->nreg.reg_timing_cfg);
	RAWNAND_DBG("0x0014 reg_addr_low:		0x%08x\n", nctri->nreg.reg_addr_low);
	RAWNAND_DBG("0x0018 reg_addr_high:		0x%08x\n", nctri->nreg.reg_addr_high);
	RAWNAND_DBG("0x001C reg_data_block_mask:	0x%08x\n", nctri->nreg.reg_data_block_mask);
	RAWNAND_DBG("0x0020 reg_ndfc_cnt:	0x%08x\n", nctri->nreg.reg_ndfc_cnt);
	RAWNAND_DBG("0x0024 reg_cmd:			0x%08x\n", nctri->nreg.reg_cmd);
	RAWNAND_DBG("0x0028 reg_read_cmd_set:	0x%08x\n", nctri->nreg.reg_read_cmd_set);
	RAWNAND_DBG("0x002C reg_write_cmd_set:	0x%08x\n", nctri->nreg.reg_write_cmd_set);
	RAWNAND_DBG("0x0034 reg_ecc_ctl:		0x%08x\n", nctri->nreg.reg_ecc_ctl);
	RAWNAND_DBG("0x0038 reg_ecc_sta:		0x%08x\n", nctri->nreg.reg_ecc_sta);
	RAWNAND_DBG("0x003C reg_data_pattern_sta:	0x%08x\n", nctri->nreg.reg_data_pattern_sta);
	RAWNAND_DBG("0x0040 reg_efr:			0x%08x\n", nctri->nreg.reg_efr);
	RAWNAND_DBG("0x0044 reg_rdata_sta_ctl:	0x%08x\n", nctri->nreg.reg_rdata_sta_ctl);
	RAWNAND_DBG("0x0048 reg_rdata_sta_0:	0x%08x\n", nctri->nreg.reg_rdata_sta_0);
	RAWNAND_DBG("0x004C reg_rdata_sta_1:	0x%08x\n", nctri->nreg.reg_rdata_sta_1);
	RAWNAND_DBG("0x0050 reg_err_cnt0:		0x%08x\n", nctri->nreg.reg_err_cnt0);
	RAWNAND_DBG("0x0054 reg_err_cnt1:		0x%08x\n", nctri->nreg.reg_err_cnt1);
	RAWNAND_DBG("0x0058 reg_err_cnt2:		0x%08x\n", nctri->nreg.reg_err_cnt2);
	RAWNAND_DBG("0x005C reg_err_cnt3:		0x%08x\n", nctri->nreg.reg_err_cnt3);
	RAWNAND_DBG("0x0060 reg_err_cnt4:		0x%08x\n", nctri->nreg.reg_err_cnt4);
	RAWNAND_DBG("0x0064 reg_err_cnt5:		0x%08x\n", nctri->nreg.reg_err_cnt5);
	RAWNAND_DBG("0x0068 reg_err_cnt6:		0x%08x\n", nctri->nreg.reg_err_cnt6);
	RAWNAND_DBG("0x006C reg_err_cnt7:		0x%08x\n", nctri->nreg.reg_err_cnt7);
	RAWNAND_DBG("0x0070 reg_user_data_len_base:	0x%08x\n", nctri->nreg.reg_user_data_len_base);
	RAWNAND_DBG("0x0080 reg_user_data_base:	0x%08x\n", nctri->nreg.reg_user_data_base);
	RAWNAND_DBG("0x0100 reg_flash_sta:		0x%08x\n", nctri->nreg.reg_flash_sta);
	RAWNAND_DBG("0x0104 reg_cmd_repeat_cnt:	0x%08x\n", nctri->nreg.reg_cmd_repeat_cnt);
	RAWNAND_DBG("0x0108 reg_cmd_repeat_interval:	0x%08x\n", nctri->nreg.reg_cmd_repeat_interval);
	RAWNAND_DBG("0x0110 reg_efnand_sta:		0x%08x\n", nctri->nreg.reg_efnand_sta);
	RAWNAND_DBG("0x0114 reg_spare_area:		0x%08x\n", nctri->nreg.reg_spare_area);
	RAWNAND_DBG("0x0118 reg_pat_id:			0x%08x\n", nctri->nreg.reg_pat_id);
	RAWNAND_DBG("0x011C reg_ddr2_spec_ctl:	0x%08x\n", nctri->nreg.reg_ddr2_spec_ctl);
	RAWNAND_DBG("0x0120 reg_ndma_mode_ctl:	0x%08x\n", nctri->nreg.reg_ndma_mode_ctl);
	RAWNAND_DBG("0x012C reg_valid_data_dma_cnt:	0x%08x\n", nctri->nreg.reg_valid_data_dma_cnt);
	RAWNAND_DBG("0x0130 reg_data_dma_base_0:	0x%08x\n", nctri->nreg.reg_data_dma_base);
	RAWNAND_DBG("0x0170 reg_data_dma_size_2x:	0x%08x\n", nctri->nreg.reg_data_dma_size_2x);
	RAWNAND_DBG("0x0190 reg_random_seed_x:		0x%08x\n", nctri->nreg.reg_random_seed_x);
	RAWNAND_DBG("0x0214 reg_dma_cnt:           0x%08x\n", nctri->nreg.reg_dma_cnt);
	RAWNAND_DBG("0x0218 reg_emce_ctl: 		0x%08x\n", nctri->nreg.reg_emce_ctl);
	RAWNAND_DBG("0x021C reg_emce_iv_fac_cmp_val:	0x%08x\n", nctri->nreg.reg_emce_iv_fac_cmp_val);
	RAWNAND_DBG("0x0220 reg_emce_iv_cal_fac_base:	0x%08x\n", nctri->nreg.reg_emce_iv_cal_fac_base);
	RAWNAND_DBG("0x02A0 reg_io_data:		0x%08x\n", nctri->nreg.reg_io_data);
	RAWNAND_DBG("0x02F0 reg_ndfc_ver:           0x%08x\n", nctri->nreg.reg_ndfc_ver);
	RAWNAND_DBG("0x02FC reg_ldpc_ctl: 		0x%08x\n", nctri->nreg.reg_ldpc_ctl);
	RAWNAND_DBG("0x0300 reg_enc_ldpc_mode_set:	0x%08x\n", nctri->nreg.reg_enc_ldpc_mode_set);
	RAWNAND_DBG("0x0304 reg_cor_ldpc_mode_set:	0x%08x\n", nctri->nreg.reg_cor_ldpc_mode_set);
	RAWNAND_DBG("0x0308 reg_c0_llr_tbl_addr:	0x%08x\n", nctri->nreg.reg_c0_llr_tbl_addr);
	RAWNAND_DBG("0x0328 reg_c1_llr_tbl_addr:	0x%08x\n", nctri->nreg.reg_c1_llr_tbl_addr);
	RAWNAND_DBG("0x0400 reg_ram0_base:			0x%08x\n", nctri->nreg.reg_ram0_base);
	RAWNAND_DBG("0x0800 reg_ram1_base:			0x%08x\n", nctri->nreg.reg_ram1_base);
	RAWNAND_DBG("0x0C00 reg_glb_cfg:			0x%08x\n", nctri->nreg.reg_glb_cfg);
	RAWNAND_DBG("0x0C04 reg_cmd_descr_base_addr:	0x%08x\n", nctri->nreg.reg_cmd_descr_base_addr);
	RAWNAND_DBG("0x0C08 reg_cmd_descr_sta:		0x%08x\n", nctri->nreg.reg_cmd_descr_sta);
	RAWNAND_DBG("0x0C0C reg_cmd_descr_intr:		0x%08x\n", nctri->nreg.reg_cmd_descr_intr);
	RAWNAND_DBG("0x0C10 reg_csic_bist_ctl_reg:	0x%08x\n", nctri->nreg.reg_csic_bist_ctl_reg);
	RAWNAND_DBG("0x0C14 reg_bist_start_addr:	0x%08x\n", nctri->nreg.reg_bist_start_addr);
	RAWNAND_DBG("0x0C18 reg_bist_end_addr:		0x%08x\n", nctri->nreg.reg_bist_end_addr);
	RAWNAND_DBG("0x0C1C reg_bist_data_mask:		0x%08x\n", nctri->nreg.reg_bist_data_mask);
}

s32 fill_nctri(struct nand_controller_info *nctri)
{

	void *reg_base = nctri->nreg_base;

	nctri->type = NAND_GetNdfcVersion();
	nctri->dma_type = NAND_GetNdfcDmaMode();
	nctri->nreg.reg_ctl = (volatile u32 *)((u8 *)reg_base + 0x0000);
	nctri->nreg.reg_sta = (volatile u32 *)((u8 *)reg_base + 0x0004);
	nctri->nreg.reg_int = (volatile u32 *)((u8 *)reg_base + 0x0008);
	nctri->nreg.reg_timing_ctl = (volatile u32 *)((u8 *)reg_base + 0x000c);
	nctri->nreg.reg_timing_cfg = (volatile u32 *)((u8 *)reg_base + 0x0010);
	nctri->nreg.reg_addr_low = (volatile u32 *)((u8 *)reg_base + 0x0014);
	nctri->nreg.reg_addr_high = (volatile u32 *)((u8 *)reg_base + 0x0018);
	nctri->nreg.reg_data_block_mask = (volatile u32 *)((u8 *)reg_base + 0x001c);
	nctri->nreg.reg_ndfc_cnt = (volatile u32 *)((u8 *)reg_base + 0x0020);
	nctri->nreg.reg_cmd = (volatile u32 *)((u8 *)reg_base + 0x0024);
	nctri->nreg.reg_read_cmd_set = (volatile u32 *)((u8 *)reg_base + 0x0028);
	nctri->nreg.reg_write_cmd_set = (volatile u32 *)((u8 *)reg_base + 0x002c);
	nctri->nreg.reg_ecc_ctl = (volatile u32 *)((u8 *)reg_base + 0x0034);
	nctri->nreg.reg_ecc_sta = (volatile u32 *)((u8 *)reg_base + 0x0038);
	nctri->nreg.reg_data_pattern_sta = (volatile u32 *)((u8 *)reg_base + 0x003c);
	nctri->nreg.reg_efr = (volatile u32 *)((u8 *)reg_base + 0x0040);
	nctri->nreg.reg_rdata_sta_ctl = (volatile u32 *)((u8 *)reg_base + 0x0044);
	nctri->nreg.reg_rdata_sta_0 = (volatile u32 *)((u8 *)reg_base + 0x0048);
	nctri->nreg.reg_rdata_sta_1 = (volatile u32 *)((u8 *)reg_base + 0x004c);
	nctri->nreg.reg_err_cnt0 = (volatile u32 *)((u8 *)reg_base + 0x0050);
	nctri->nreg.reg_err_cnt1 = (volatile u32 *)((u8 *)reg_base + 0x0054);
	nctri->nreg.reg_err_cnt2 = (volatile u32 *)((u8 *)reg_base + 0x0058);
	nctri->nreg.reg_err_cnt3 = (volatile u32 *)((u8 *)reg_base + 0x005c);
	nctri->nreg.reg_err_cnt4 = (volatile u32 *)((u8 *)reg_base + 0x0060);
	nctri->nreg.reg_err_cnt5 = (volatile u32 *)((u8 *)reg_base + 0x0064);
	nctri->nreg.reg_err_cnt6 = (volatile u32 *)((u8 *)reg_base + 0x0068);
	nctri->nreg.reg_err_cnt7 = (volatile u32 *)((u8 *)reg_base + 0x006c);
	nctri->nreg.reg_user_data_len_base = (volatile u32 *)((u8 *)reg_base + 0x0070);
	nctri->nreg.reg_user_data_base = (volatile u32 *)((u8 *)reg_base + 0x0080);
	nctri->nreg.reg_flash_sta = (volatile u32 *)((u8 *)reg_base + 0x00100);
	nctri->nreg.reg_cmd_repeat_cnt = (volatile u32 *)((u8 *)reg_base + 0x00104);
	nctri->nreg.reg_cmd_repeat_interval = (volatile u32 *)((u8 *)reg_base + 0x00108);
	nctri->nreg.reg_efnand_sta = (volatile u32 *)((u8 *)reg_base + 0x0110);
	nctri->nreg.reg_spare_area = (volatile u32 *)((u8 *)reg_base + 0x0114);
	nctri->nreg.reg_pat_id = (volatile u32 *)((u8 *)reg_base + 0x0118);
	nctri->nreg.reg_ddr2_spec_ctl = (volatile u32 *)((u8 *)reg_base + 0x011c);
	nctri->nreg.reg_ndma_mode_ctl = (volatile u32 *)((u8 *)reg_base + 0x0120);
	nctri->nreg.reg_valid_data_dma_cnt = (volatile u32 *)((u8 *)reg_base + 0x012c);
	nctri->nreg.reg_data_dma_base = (volatile u32 *)((u8 *)reg_base + 0x0130);
	nctri->nreg.reg_data_dma_size_2x = (volatile u32 *)((u8 *)reg_base + 0x0170);
	nctri->nreg.reg_random_seed_x = (volatile u32 *)((u8 *)reg_base + 0x0190);
	nctri->nreg.reg_dma_cnt = (volatile u32 *)((u8 *)reg_base + 0x0214);
	nctri->nreg.reg_emce_ctl = (volatile u32 *)((u8 *)reg_base + 0x0218);
	nctri->nreg.reg_emce_iv_fac_cmp_val = (volatile u32 *)((u8 *)reg_base + 0x021c);
	nctri->nreg.reg_emce_iv_cal_fac_base = (volatile u32 *)((u8 *)reg_base + 0x0220);
	nctri->nreg.reg_io_data = (volatile u32 *)((u8 *)reg_base + 0x02a0);
	nctri->nreg.reg_ndfc_ver = (volatile u32 *)((u8 *)reg_base + 0x02f0);
	nctri->nreg.reg_ldpc_ctl = (volatile u32 *)((u8 *)reg_base + 0x02fc);
	nctri->nreg.reg_enc_ldpc_mode_set = (volatile u32 *)((u8 *)reg_base + 0x0300);
	nctri->nreg.reg_cor_ldpc_mode_set = (volatile u32 *)((u8 *)reg_base + 0x0304);
	nctri->nreg.reg_c0_llr_tbl_addr = (volatile u32 *)((u8 *)reg_base + 0x0308);
	nctri->nreg.reg_c1_llr_tbl_addr = (volatile u32 *)((u8 *)reg_base + 0x0328);
	nctri->nreg.reg_ram0_base = (volatile u32 *)((u8 *)reg_base + 0x0400);
	nctri->nreg.reg_ram1_base = (volatile u32 *)((u8 *)reg_base + 0x0800);
	nctri->nreg.reg_glb_cfg = (volatile u32 *)((u8 *)reg_base + 0x0c00);
	nctri->nreg.reg_cmd_descr_base_addr = (volatile u32 *)((u8 *)reg_base + 0x0c04);
	nctri->nreg.reg_cmd_descr_sta = (volatile u32 *)((u8 *)reg_base + 0x0c08);
	nctri->nreg.reg_cmd_descr_intr = (volatile u32 *)((u8 *)reg_base + 0x0c0c);
	nctri->nreg.reg_csic_bist_ctl_reg = (volatile u32 *)((u8 *)reg_base + 0x0c10);
	nctri->nreg.reg_bist_start_addr = (volatile u32 *)((u8 *)reg_base + 0x0c14);
	nctri->nreg.reg_bist_end_addr = (volatile u32 *)((u8 *)reg_base + 0x0c18);
	nctri->nreg.reg_bist_data_mask = (volatile u32 *)((u8 *)reg_base + 0x0c1c);
	return 0;
}

int ndfc_soft_reset(struct nand_controller_info *nctri)
{
	int ret;
	u32 cfg = 0;

	//RAWNAND_DBG("Reset NDFC start %d  %x\n", nctri->channel_id,*nctri->nreg.reg_glb_cfg);

	/**nctri->nreg.reg_glb_cfg |= NDFC_RESET;*/
	cfg = readl(nctri->nreg.reg_glb_cfg);
	cfg |= NDFC_RESET;
	writel(cfg, nctri->nreg.reg_glb_cfg);
	ret = wait_reg_status(nctri->nreg.reg_glb_cfg, NDFC_RESET, 0, 3);
	//RAWNAND_DBG("Reset NDFC end %d  %x\n", nctri->channel_id,*nctri->nreg.reg_glb_cfg);

	return ret;
}

s32 recover_nctri(struct nand_controller_info *nctri)
{
	writel(nctri->nreg_bak.reg_timing_ctl, nctri->nreg.reg_timing_ctl);
	writel(nctri->nreg_bak.reg_timing_cfg, nctri->nreg.reg_timing_cfg);
	writel(nctri->nreg_bak.reg_pat_id, nctri->nreg.reg_pat_id);
	writel(nctri->nreg_bak.reg_dma_cnt, nctri->nreg.reg_dma_cnt);
	writel(nctri->nreg_bak.reg_ctl, nctri->nreg.reg_ctl);
	writel(nctri->nreg_bak.reg_ddr2_spec_ctl, nctri->nreg.reg_ddr2_spec_ctl);
	writel(nctri->nreg_bak.reg_glb_cfg, nctri->nreg.reg_glb_cfg);

	return 0;
}

void ndfc_print_reg(struct nand_controller_info *nctri)
{
	RAWNAND_DBG("print ndfc reg:\n");
	RAWNAND_DBG("0x0000 reg_ctl:			0x%08x\n",
			readl(nctri->nreg.reg_ctl));
	RAWNAND_DBG("0x0004 reg_sta:			0x%08x\n",
			readl(nctri->nreg.reg_sta));
	RAWNAND_DBG("0x0008 reg_int:			0x%08x\n",
			readl(nctri->nreg.reg_int));
	RAWNAND_DBG("0x000C reg_timing_ctl:		0x%08x\n",
			readl(nctri->nreg.reg_timing_ctl));
	RAWNAND_DBG("0x0010 reg_timing_cfg:		0x%08x\n",
			readl(nctri->nreg.reg_timing_cfg));
	RAWNAND_DBG("0x0014 reg_addr_low:		0x%08x\n",
			readl(nctri->nreg.reg_addr_low));
	RAWNAND_DBG("0x0018 reg_addr_high:		0x%08x\n",
			readl(nctri->nreg.reg_addr_high));
	RAWNAND_DBG("0x001C reg_data_block_mask:	0x%08x\n",
			readl(nctri->nreg.reg_data_block_mask));
	RAWNAND_DBG("0x0020 reg_ndfc_cnt:		0x%08x\n",
			readl(nctri->nreg.reg_ndfc_cnt));
	RAWNAND_DBG("0x0024 reg_cmd:			0x%08x\n",
			readl(nctri->nreg.reg_cmd));
	RAWNAND_DBG("0x0028 reg_read_cmd_set:		0x%08x\n",
			readl(nctri->nreg.reg_read_cmd_set));
	RAWNAND_DBG("0x002C reg_write_cmd_set:	0x%08x\n",
			readl(nctri->nreg.reg_write_cmd_set));
	RAWNAND_DBG("0x0034 reg_ecc_ctl:		0x%08x\n",
			readl(nctri->nreg.reg_ecc_ctl));
	RAWNAND_DBG("0x0038 reg_ecc_sta:		0x%08x\n",
			readl(nctri->nreg.reg_ecc_sta));
	RAWNAND_DBG("0x003C reg_data_pattern_sta:	0x%08x\n",
			readl(nctri->nreg.reg_data_pattern_sta));
	RAWNAND_DBG("0x0040 reg_efr:			0x%08x\n",
			readl(nctri->nreg.reg_efr));
	RAWNAND_DBG("0x0044 reg_rdata_sta_ctl:	0x%08x\n",
			readl(nctri->nreg.reg_rdata_sta_ctl));
	RAWNAND_DBG("0x0048 reg_rdata_sta_0:		0x%08x\n",
			readl(nctri->nreg.reg_rdata_sta_0));
	RAWNAND_DBG("0x004C reg_rdata_sta_1:		0x%08x\n",
			readl(nctri->nreg.reg_rdata_sta_1));
	RAWNAND_DBG("0x0050 reg_err_cnt0:		0x%08x\n",
			readl(nctri->nreg.reg_err_cnt0));
	RAWNAND_DBG("0x0054 reg_err_cnt1:		0x%08x\n",
			readl(nctri->nreg.reg_err_cnt1));
	RAWNAND_DBG("0x0058 reg_err_cnt2:		0x%08x\n",
			readl(nctri->nreg.reg_err_cnt2));
	RAWNAND_DBG("0x005C reg_err_cnt3:		0x%08x\n",
			readl(nctri->nreg.reg_err_cnt3));
	RAWNAND_DBG("0x0060 reg_err_cnt4:		0x%08x\n",
			readl(nctri->nreg.reg_err_cnt4));
	RAWNAND_DBG("0x0064 reg_err_cnt5:		0x%08x\n",
			readl(nctri->nreg.reg_err_cnt5));
	RAWNAND_DBG("0x0068 reg_err_cnt6:		0x%08x\n",
			readl(nctri->nreg.reg_err_cnt6));
	RAWNAND_DBG("0x006C reg_err_cnt7:		0x%08x\n",
			readl(nctri->nreg.reg_err_cnt7));
	RAWNAND_DBG("0x0070 reg_user_data_len_base:	0x%08x\n",
			readl(nctri->nreg.reg_user_data_len_base));
	RAWNAND_DBG("0x0080 reg_user_data_base:	0x%08x\n",
			readl(nctri->nreg.reg_user_data_base));
	RAWNAND_DBG("0x0100 reg_flash_sta:		0x%08x\n",
			readl(nctri->nreg.reg_flash_sta));
	RAWNAND_DBG("0x0104 reg_cmd_repeat_cnt:	0x%08x\n",
			readl(nctri->nreg.reg_cmd_repeat_cnt));
	RAWNAND_DBG("0x0108 reg_cmd_repeat_interval:	0x%08x\n",
			readl(nctri->nreg.reg_cmd_repeat_interval));
	RAWNAND_DBG("0x0110 reg_efnand_sta:		0x%08x\n",
			readl(nctri->nreg.reg_efnand_sta));
	RAWNAND_DBG("0x0114 reg_spare_area:		0x%08x\n",
			readl(nctri->nreg.reg_spare_area));
	RAWNAND_DBG("0x0118 reg_pat_id:		0x%08x\n",
			readl(nctri->nreg.reg_pat_id));
	RAWNAND_DBG("0x011C reg_ddr2_spec_ctl:	0x%08x\n",
			readl(nctri->nreg.reg_ddr2_spec_ctl));
	RAWNAND_DBG("0x0120 reg_ndma_mode_ctl:	0x%08x\n",
			readl(nctri->nreg.reg_ndma_mode_ctl));
	RAWNAND_DBG("0x012C reg_valid_data_dma_cnt:	0x%08x\n",
			readl(nctri->nreg.reg_valid_data_dma_cnt));
	RAWNAND_DBG("0x0130 reg_data_dma_base_0:	0x%08x\n",
			readl(nctri->nreg.reg_data_dma_base));
	RAWNAND_DBG("0x0170 reg_data_dma_size_2x:	0x%08x\n",
			readl(nctri->nreg.reg_data_dma_size_2x));
	RAWNAND_DBG("0x0190 reg_random_seed_x:	0x%08x\n",
			readl(nctri->nreg.reg_random_seed_x));
	RAWNAND_DBG("0x0214 reg_dma_cnt:		0x%08x\n",
			readl(nctri->nreg.reg_dma_cnt));
	RAWNAND_DBG("0x0218 reg_emce_ctl: 		0x%08x\n",
			readl(nctri->nreg.reg_emce_ctl));
	RAWNAND_DBG("0x021C reg_emce_iv_fac_cmp_val:	0x%08x\n",
			readl(nctri->nreg.reg_emce_iv_fac_cmp_val));
	RAWNAND_DBG("0x0220 reg_emce_iv_cal_fac_base:	0x%08x\n",
			readl(nctri->nreg.reg_emce_iv_cal_fac_base));
	RAWNAND_DBG("0x02A0 reg_io_data:		0x%08x\n",
			readl(nctri->nreg.reg_io_data));
	RAWNAND_DBG("0x02F0 reg_ndfc_ver:		0x%08x\n",
			readl(nctri->nreg.reg_ndfc_ver));
	RAWNAND_DBG("0x02FC reg_ldpc_ctl: 		0x%08x\n",
			readl(nctri->nreg.reg_ldpc_ctl));
	RAWNAND_DBG("0x0300 reg_enc_ldpc_mode_set:	0x%08x\n",
			readl(nctri->nreg.reg_enc_ldpc_mode_set));
	RAWNAND_DBG("0x0304 reg_cor_ldpc_mode_set:	0x%08x\n",
			readl(nctri->nreg.reg_cor_ldpc_mode_set));
	RAWNAND_DBG("0x0308 reg_c0_llr_tbl_addr:	0x%08x\n",
			readl(nctri->nreg.reg_c0_llr_tbl_addr));
	RAWNAND_DBG("0x0328 reg_c1_llr_tbl_addr:	0x%08x\n",
			readl(nctri->nreg.reg_c1_llr_tbl_addr));
	RAWNAND_DBG("0x0400 reg_ram0_base:		0x%08x\n",
			readl(nctri->nreg.reg_ram0_base));
	RAWNAND_DBG("0x0800 reg_ram1_base:		0x%08x\n",
			readl(nctri->nreg.reg_ram1_base));
	RAWNAND_DBG("0x0C00 reg_glb_cfg:		0x%08x\n",
			readl(nctri->nreg.reg_glb_cfg));
	RAWNAND_DBG("0x0C04 reg_cmd_descr_base_addr:	0x%08x\n",
			readl(nctri->nreg.reg_cmd_descr_base_addr));
	RAWNAND_DBG("0x0C08 reg_cmd_descr_sta:	0x%08x\n",
			readl(nctri->nreg.reg_cmd_descr_sta));
	RAWNAND_DBG("0x0C0C reg_cmd_descr_intr:	0x%08x\n",
			readl(nctri->nreg.reg_cmd_descr_intr));
	RAWNAND_DBG("0x0C10 reg_csic_bist_ctl_reg:	0x%08x\n",
			readl(nctri->nreg.reg_csic_bist_ctl_reg));
	RAWNAND_DBG("0x0C14 reg_bist_start_addr:	0x%08x\n",
			readl(nctri->nreg.reg_bist_start_addr));
	RAWNAND_DBG("0x0C18 reg_bist_end_addr:	0x%08x\n",
			readl(nctri->nreg.reg_bist_end_addr));
	RAWNAND_DBG("0x0C1C reg_bist_data_mask:	0x%08x\n",
			readl(nctri->nreg.reg_bist_data_mask));
}
void ndfc_encode_select(struct nand_controller_info *nctri)
{
	nctri->channel_sel = BCH;

	return;
}
void ndfc_encode_default(struct nand_controller_info *nctri)
{
	nctri->channel_sel = BCH;

	return;
}

void ndfc_channel_select(struct nand_controller_info *nctri, u32 channel_sel)
{
	u32 cfg;

	//	nctri->channel_sel = channel_sel;
	ndfc_soft_reset(nctri);
	cfg = readl(nctri->nreg.reg_glb_cfg);
	cfg &= ~NDFC_CHANNEL_SEL;
	cfg |= (channel_sel & 0x1) << 2;
	writel(cfg, nctri->nreg.reg_glb_cfg);
	/**nctri->nreg.reg_glb_cfg = cfg;*/
	ndfc_soft_reset(nctri);

	return;
}

s32 batch_cmd_io_send(struct nand_controller_info *nctri, struct _nctri_cmd_seq *cmd_list)
{
	s32 ret = 0;
	u32 cmd0, cmd1, cmd2, cmd3, cmd_val = 0;
	u32 rb = ndfc_get_selected_rb_no(nctri);
	u32 val = 0;

	//RAWNAND_DBG("before send cmd: %d 0x%x 0x%x\n", nctri->nci->randomizer, *(nctri->nreg.reg_ecc_ctl), *(nctri->nreg.reg_ecc_sta));

	if (cmd_list->cmd_type != 1) {
		RAWNAND_ERR("_batch_cmd io_send, cmd type error, %d!\n", cmd_list->cmd_type);
		return ERR_NO_32;
	}

	//===================================
	//     check FSM
	//===================================
	if (nctri->write_wait_rb_before_cmd_io) {
		ndfc_write_wait_rb_ready(nctri, rb);
	}
	ndfc_wait_rb_ready(nctri, rb);

	if ((ndfc_wait_cmdfifo_free(nctri) != 0) || (ndfc_wait_fsm_ready(nctri) != 0)) {
		RAWNAND_ERR("_batch cmd io send, wait cmd fifo free timeout!\n");
		//print_cmd_seq(cmd_list);
		return ERR_TIMEOUT;
	}
	/**nctri->nreg.reg_ctl |= 1 << 14; //songwj 20171115*/
	val = readl(nctri->nreg.reg_ctl);
	val |= NDFC_DMA_METHOD;
	writel(val, nctri->nreg.reg_ctl);
	if (nctri->channel_sel == 0) {
		/**nctri->nreg.reg_ndfc_cnt = 0x400; //songwj 20171115*/
		/**nctri->nreg.reg_sta |= *nctri->nreg.reg_sta & (NDFC_RB_B2R | NDFC_CMD_INT_FLAG | NDFC_DMA_INT_FLAG);*/
		writel(0x400, nctri->nreg.reg_ndfc_cnt);

		val = readl(nctri->nreg.reg_sta);
		val &= (NDFC_RB_B2R | NDFC_CMD_INT_FLAG | NDFC_DMA_INT_FLAG);
		val |= readl(nctri->nreg.reg_sta);
		writel(val, nctri->nreg.reg_sta);
	} else {
		//*nctri->nreg.reg_ndfc_cnt = 0x800; //zhouk for ldpc (why is no 0x800? by Zzm)
		//*nctri->nreg.reg_sta |= (NDFC_RB_B2R | NDFC_CMD_INT_FLAG | NDFC_DMA_INT_FLAG);
		writel(0x800, nctri->nreg.reg_ndfc_cnt);

		val = readl(nctri->nreg.reg_sta);
		val |= (NDFC_RB_B2R | NDFC_CMD_INT_FLAG | NDFC_DMA_INT_FLAG);
		writel(val, nctri->nreg.reg_sta);

	}

	//===================================
	//     configure cmd
	//===================================
	cmd0 = cmd_list->nctri_cmd[0].cmd;
	cmd1 = cmd_list->nctri_cmd[1].cmd;
	cmd2 = cmd_list->nctri_cmd[2].cmd;
	cmd3 = cmd_list->nctri_cmd[3].cmd;
	if (cmd_list->nctri_cmd[0].cmd_direction == 1) {
		//batch write cmd set
		/**nctri->nreg.reg_write_cmd_set = (((cmd1 & 0xff) << 0) | ((cmd2 & 0xff) << 8));*/
		writel((((cmd1 & 0xff) << 0) | ((cmd2 & 0xff) << 8)),
				nctri->nreg.reg_write_cmd_set);
	} else {
		//batch read cmd set
		/**nctri->nreg.reg_read_cmd_set = (((cmd1 & 0xff) << 0) | ((cmd2 & 0xff) << 8) | ((cmd3 & 0xff) << 16));*/
		writel((((cmd1 & 0xff) << 0) | ((cmd2 & 0xff) << 8) |
			((cmd3 & 0xff) << 16)), nctri->nreg.reg_read_cmd_set);
	}

	cmd_val |= cmd0 & 0xff;
	if (cmd_list->nctri_cmd[0].cmd_direction) {
		cmd_val |= NDFC_ACCESS_DIR;
	}
	cmd_val |= NDFC_DATA_TRANS;
	cmd_val |= NDFC_SEND_CMD1;
	if (nctri->current_op_type != 1) {
		/*only write controller don't wait rb*/
		cmd_val |= NDFC_WAIT_FLAG; //wait rb
	}
	cmd_val |= NDFC_SEND_CMD2;
	if (cmd_list->nctri_cmd[0].cmd_swap_data) {
		cmd_val |= NDFC_DATA_SWAP_METHOD; //dma
	}
	if (cmd_list->ecc_layout) {
		cmd_val |= NDFC_SEQ;
	}
	if (nctri->random_cmd2_send_flag) {
		/**nctri->nreg.reg_read_cmd_set |= (nctri->random_cmd2 << 24);*/
		val = readl(nctri->nreg.reg_read_cmd_set);
		val |= (nctri->random_cmd2 << 24);
		writel(val, nctri->random_cmd2);

		cmd_val |= NDFC_SEND_RAN_CMD2;
	} else {
		/**nctri->nreg.reg_read_cmd_set &= (~(0xff << 24));*/
		val = readl(nctri->nreg.reg_read_cmd_set);
		val &= ~NDFC_RANDOM_CMD2;
		writel(val, nctri->nreg.reg_read_cmd_set);

		cmd_val &= (~NDFC_SEND_RAN_CMD2);
	}

	cmd_val |= ((nctri->random_addr_num << 8) & NDFC_ADR_NUM_IN_PAGECMD);

	cmd_val |= 0x2U << 30; //page command

	//===================================
	//     configure address
	//===================================
	if (cmd_list->nctri_cmd[0].cmd_acnt) {
		_set_addr(nctri, cmd_list->nctri_cmd[0].cmd_acnt, cmd_list->nctri_cmd[0].cmd_addr);
		cmd_val |= ((cmd_list->nctri_cmd[0].cmd_acnt - 1) & 0x7) << 16;
		cmd_val |= NDFC_SEND_ADR;
	}
	//===================================
	//     configure dma
	//===================================
	if (cmd_list->nctri_cmd[0].cmd_mdata_addr != NULL) {
		ndfc_dma_config_start(nctri, cmd_list->nctri_cmd[0].cmd_direction, cmd_list->nctri_cmd[0].cmd_mdata_addr, cmd_list->nctri_cmd[0].cmd_mdata_len);
	}
	/**nctri->nreg.reg_data_block_mask = cmd_list->nctri_cmd[0].cmd_data_block_mask;*/
	writel(cmd_list->nctri_cmd[0].cmd_data_block_mask, nctri->nreg.reg_data_block_mask);


	/*boot0 LDPC*/
	if (nctri->channel_sel == 1) {
		ndfc_channel_select(nctri, 1);
		ndfc_boot0_ldpc_mode(nctri);
	}

	save_nctri(nctri);
	//ndfc_df_ops.ndfc_print_reg(nctri);

	/**nctri->nreg.reg_cmd = cmd_val;*/
	writel(cmd_val, nctri->nreg.reg_cmd);

	return ret;
}

int ndfc_dma_config_start(struct nand_controller_info *nctri, u8 rw, void *buff_addr, u32 len)
{
	u32 reg_val;
	//	u32 config_addr=0;
	int i, valid_data_dma_cnt;
	u32 data_dma_size_temp[8] = {0};

	NAND_CleanFlushDCacheRegion(buff_addr, len);

	if (nctri->dma_type == 1) {
		/*MBUS DMA*/
		nctri->dma_addr = (unsigned long)NAND_DMASingleMap(rw, buff_addr, len);
		if (nctri->dma_addr & 0x1f) { //zhouk for DMA addr must be 32B aligned
			RAWNAND_ERR("ndfc_dma_config_start: buff addr(0x%x) is not 32Bytes aligned", nctri->dma_addr);
		}

		/*BCH*/
		if (nctri->channel_sel == 0) {
			/*
			 **nctri->nreg.reg_valid_data_dma_cnt = 1;
			 **nctri->nreg.reg_data_dma_base = nctri->dma_addr;
			 **nctri->nreg.reg_data_dma_size_2x = (len | (8 << 16));
			 */

			writel(1, nctri->nreg.reg_valid_data_dma_cnt);
			writel(nctri->dma_addr, nctri->nreg.reg_data_dma_base);
			writel((len | (8 << 16)), nctri->nreg.reg_data_dma_size_2x);

			for (i = 1; i < 8; i++) {
				/**(nctri->nreg.reg_data_dma_size_2x + i) = (8 | (8 << 16));*/
				writel((8 | (8 << 16)), (nctri->nreg.reg_data_dma_size_2x + i));
			}
		} else {
			/*LDPC*/
			valid_data_dma_cnt = len / 0x800;
			/**nctri->nreg.reg_valid_data_dma_cnt = valid_data_dma_cnt;*/
			writel(valid_data_dma_cnt, nctri->nreg.reg_valid_data_dma_cnt);

			for (i = 0; i < 8; i++) {
				/**(nctri->nreg.reg_data_dma_size_2x + i) = (8 | (8 << 16));*/
				writel((8 | (8 << 16)), (nctri->nreg.reg_data_dma_size_2x + i));
			}
			if (!(valid_data_dma_cnt % 2)) {		   // valid_data_dma_cnt is even
				for (i = 0; i < valid_data_dma_cnt; i++) { // valid_data_dma_cnt
					/**(nctri->nreg.reg_data_dma_base + i) = nctri->dma_addr + (i * 0x800);*/
					writel(nctri->dma_addr + (i * 0x800),
							(nctri->nreg.reg_data_dma_base + i));
					if (!(i % 2)) {
						data_dma_size_temp[i / 2] = 0x800 | (0x800 << 16);
						/**(nctri->nreg.reg_data_dma_size_2x + (i / 2)) = data_dma_size_temp[i / 2];*/
						writel(data_dma_size_temp[i / 2],
								(nctri->nreg.reg_data_dma_size_2x + (i / 2)));
					}
				}
			} else {					       // valid_data_dma_cnt is odd
				for (i = 0; i < valid_data_dma_cnt - 1; i++) { // valid_data_dma_cnt-1
					/**(nctri->nreg.reg_data_dma_base + i) = nctri->dma_addr + (i * 0x800);*/
					writel(nctri->dma_addr + (i * 0x800), (nctri->nreg.reg_data_dma_base + i));
					if (!(i % 2)) {
						data_dma_size_temp[i / 2] = 0x800 | (0x800 << 16);
						/**(nctri->nreg.reg_data_dma_size_2x + (i / 2)) = data_dma_size_temp[i / 2];*/
						writel(data_dma_size_temp[i / 2],
									(nctri->nreg.reg_data_dma_size_2x + (i / 2)));

					}
				} // for(i=0; i<valid_data_dma_cnt; i++)
				// The last DATA_DMA Configuration
				/*
				 **(nctri->nreg.reg_data_dma_base + (valid_data_dma_cnt - 1)) = nctri->dma_addr + ((valid_data_dma_cnt - 1) * 0x800);
				 *data_dma_size_temp[(valid_data_dma_cnt - 1) / 2] = 0x800 | (0x8 << 16);
				 **(nctri->nreg.reg_data_dma_size_2x + ((valid_data_dma_cnt - 1) / 2)) = data_dma_size_temp[(valid_data_dma_cnt - 1) / 2];
				 */
				writel(nctri->dma_addr + ((valid_data_dma_cnt - 1) * 0x800),
							(nctri->nreg.reg_data_dma_base + (valid_data_dma_cnt - 1)));
				writel(data_dma_size_temp[(valid_data_dma_cnt - 1) / 2],
							(nctri->nreg.reg_data_dma_size_2x + ((valid_data_dma_cnt - 1) / 2)));


			}
		}
	} else if (nctri->dma_type == 0) {
		/*General DMA*/
		/*
		 *reg_val = *nctri->nreg.reg_ctl;
		 *reg_val |= 0x1U << 15;
		 *reg_val |= 0x1U << 14;
		 **nctri->nreg.reg_ctl = reg_val;
		 **nctri->nreg.reg_dma_cnt = len;
		 */
		reg_val = readl(nctri->nreg.reg_ctl);
		reg_val |= NDFC_NORMAL_DMA;
		reg_val |= NDFC_DMA_METHOD;
		writel(reg_val, nctri->nreg.reg_ctl);
		writel(len, nctri->nreg.reg_dma_cnt);

		nctri->dma_addr = (unsigned long)NAND_DMASingleMap(rw, buff_addr, len);
		nand_dma_config_start(rw, nctri->dma_addr, len);
	} else {
		RAWNAND_ERR("_dma_config_start, wrong dma mode, %d\n", nctri->dma_type);
		return ERR_NO_51;
	}

	return 0;
}
