/*
 * nand_ids.c
 *
 * Copyright (C) 2019 Allwinner.
 *
 *
 * SPDX-License-Identifier: GPL-2.0
 */

#include "../../../nfd/nand_osal_for_linux.h"
#include "../../nand_physic_interface.h"
#include "../rawnand_cfg.h"
#include "../rawnand_debug.h"
#include "ndfc_ops.h"
#include "../rawnand.h"
#include <asm/io.h>

#define NDFC_VERSION_1 (1)

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

	nctri->type = nand_get_ndfc_version();
	nctri->dma_type = nand_get_ndfc_dma_mode();

	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_get_voltage(&aw_ndfc))
		return -1;

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

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

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

	nand_set_clk(&aw_ndfc, nctri->channel_id, 20, 20 * 2);

	//soft reset ndfc
	ndfc_soft_reset(nctri);

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

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

	//disable write protect
	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_io_data = readl(nctri->nreg.reg_io_data);
	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_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_mbus_dma_dlba = readl(nctri->nreg.reg_mbus_dma_dlba);
	nctri->nreg_bak.reg_mbus_dma_sta = readl(nctri->nreg.reg_mbus_dma_sta);
	nctri->nreg_bak.reg_mdma_int_mask = readl(nctri->nreg.reg_mdma_int_mask);
	nctri->nreg_bak.reg_mdma_cur_desc_addr = readl(nctri->nreg.reg_mdma_cur_desc_addr);
	nctri->nreg_bak.reg_mdma_cur_buf_addr = readl(nctri->nreg.reg_mdma_cur_buf_addr);
	nctri->nreg_bak.reg_dma_cnt = readl(nctri->nreg.reg_dma_cnt);
	nctri->nreg_bak.reg_ndfc_ver = readl(nctri->nreg.reg_ndfc_ver);
	nctri->nreg_bak.reg_ram0_base = readl(nctri->nreg.reg_ram0_base);
	nctri->nreg_bak.reg_ram1_base = readl(nctri->nreg.reg_ram1_base);

	return 0;
}

void ndfc_print_save_reg(struct nand_controller_info *nctri)
{
	RAWNAND_DBG("print ndfc save reg:\n");
	RAWNAND_DBG("reg_ctl:               0x%08x\n", nctri->nreg_bak.reg_ctl);
	RAWNAND_DBG("reg_sta:               0x%08x\n", nctri->nreg_bak.reg_sta);
	RAWNAND_DBG("reg_int:               0x%08x\n", nctri->nreg_bak.reg_int);
	RAWNAND_DBG("reg_timing_ctl:        0x%08x\n", nctri->nreg_bak.reg_timing_ctl);
	RAWNAND_DBG("reg_timing_cfg:        0x%08x\n", nctri->nreg_bak.reg_timing_cfg);
	RAWNAND_DBG("reg_addr_low:          0x%08x\n", nctri->nreg_bak.reg_addr_low);
	RAWNAND_DBG("reg_addr_high:         0x%08x\n", nctri->nreg_bak.reg_addr_high);
	//RAWNAND_DBG("reg_sect_num:          0x%08x\n", nctri->nreg_bak.reg_sect_num);
	RAWNAND_DBG("reg_ndfc_cnt:          0x%08x\n", nctri->nreg_bak.reg_ndfc_cnt);
	RAWNAND_DBG("reg_cmd:               0x%08x\n", nctri->nreg_bak.reg_cmd);
	RAWNAND_DBG("reg_read_cmd_set:      0x%08x\n", nctri->nreg_bak.reg_read_cmd_set);
	RAWNAND_DBG("reg_write_cmd_set:     0x%08x\n", nctri->nreg_bak.reg_write_cmd_set);
	RAWNAND_DBG("reg_io_data:           0x%08x\n", nctri->nreg_bak.reg_io_data);
	RAWNAND_DBG("reg_ecc_ctl:           0x%08x\n", nctri->nreg_bak.reg_ecc_ctl);
	RAWNAND_DBG("reg_ecc_sta:           0x%08x\n", nctri->nreg_bak.reg_ecc_sta);
	RAWNAND_DBG("reg_efr:               0x%08x\n", nctri->nreg_bak.reg_efr);
	RAWNAND_DBG("reg_err_cnt0:          0x%08x\n", nctri->nreg_bak.reg_err_cnt0);
	RAWNAND_DBG("reg_err_cnt1:          0x%08x\n", nctri->nreg_bak.reg_err_cnt1);
	RAWNAND_DBG("reg_err_cnt2:          0x%08x\n", nctri->nreg_bak.reg_err_cnt2);
	RAWNAND_DBG("reg_err_cnt3:          0x%08x\n", nctri->nreg_bak.reg_err_cnt3);
	RAWNAND_DBG("reg_user_data_base:    0x%08x\n", nctri->nreg_bak.reg_efnand_sta);
	RAWNAND_DBG("reg_efnand_sta:        0x%08x\n", nctri->nreg_bak.reg_err_cnt1);
	RAWNAND_DBG("reg_spare_area:        0x%08x\n", nctri->nreg_bak.reg_spare_area);
	RAWNAND_DBG("reg_pat_id:            0x%08x\n", nctri->nreg_bak.reg_pat_id);
	//RAWNAND_DBG("reg_mbus_dma_addr:     0x%08x\n", nctri->nreg_bak.reg_mbus_dma_addr);
	RAWNAND_DBG("reg_dma_cnt:           0x%08x\n", nctri->nreg_bak.reg_dma_cnt);
	RAWNAND_DBG("reg_ram0_base:         0x%08x\n", nctri->nreg_bak.reg_ram0_base);
	RAWNAND_DBG("reg_ram1_base:         0x%08x\n", nctri->nreg_bak.reg_ram1_base);
}

s32 fill_nctri(struct nand_controller_info *nctri)
{
	void *reg_base = nctri->nreg_base;

	nctri->type = nand_get_ndfc_version();
	nctri->dma_type = nand_get_ndfc_dma_mode();
	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_io_data = (volatile u32 *)((u8 *)reg_base + 0x0300);
	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_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_mbus_dma_dlba = (volatile u32 *)((u8 *)reg_base + 0x0200);
	nctri->nreg.reg_mbus_dma_sta = (volatile u32 *)((u8 *)reg_base + 0x0204);
	nctri->nreg.reg_mdma_int_mask = (volatile u32 *)((u8 *)reg_base + 0x0208);
	nctri->nreg.reg_mdma_cur_desc_addr = (volatile u32 *)((u8 *)reg_base + 0x020c);
	nctri->nreg.reg_mdma_cur_buf_addr = (volatile u32 *)((u8 *)reg_base + 0x0210);
	nctri->nreg.reg_dma_cnt = (volatile u32 *)((u8 *)reg_base + 0x0214);
	nctri->nreg.reg_ndfc_ver = (volatile u32 *)((u8 *)reg_base + 0x02f0);
	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 *)nand_malloc(sizeof(u32)); //simulate,don't care reg_glb_cfg's value

	return 0;
}

int ndfc_soft_reset(struct nand_controller_info *nctri)
{
	int ret;
	u32 val = 0;
	RAWNAND_DBG("Reset NDFC start %d  %x\n", nctri->channel_id, readl(nctri->nreg.reg_ctl));

	val = readl(nctri->nreg.reg_ctl);
	val |= NDFC_RESET;
	writel(val, nctri->nreg.reg_ctl);

	ret = wait_reg_status(nctri->nreg.reg_ctl, NDFC_RESET, 0, 3);

	RAWNAND_DBG("Reset NDFC end %d	%x\n", nctri->channel_id, readl(nctri->nreg.reg_ctl));

	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_io_data, nctri->nreg.reg_io_data);
	writel(nctri->nreg_bak.reg_efr, nctri->nreg.reg_efr);
	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);
	return 0;
}

void ndfc_print_reg(struct nand_controller_info *nctri)
{
	RAWNAND_DBG("print ndfc reg:\n");
	RAWNAND_DBG("reg_ctl:		%p 0x%08x\n", nctri->nreg.reg_ctl, readl(nctri->nreg.reg_ctl));
	RAWNAND_DBG("reg_sta:		%p 0x%08x\n", nctri->nreg.reg_sta, readl(nctri->nreg.reg_sta));
	RAWNAND_DBG("reg_int:		%p 0x%08x\n", nctri->nreg.reg_int, readl(nctri->nreg.reg_int));
	RAWNAND_DBG("reg_timing_ctl:	%p 0x%08x\n", nctri->nreg.reg_timing_ctl, readl(nctri->nreg.reg_timing_ctl));
	RAWNAND_DBG("reg_timing_cfg:	%p 0x%08x\n", nctri->nreg.reg_timing_cfg, readl(nctri->nreg.reg_timing_cfg));
	RAWNAND_DBG("reg_addr_low:	%p 0x%08x\n", nctri->nreg.reg_addr_low, readl(nctri->nreg.reg_addr_low));
	RAWNAND_DBG("reg_addr_high:	%p 0x%08x\n", nctri->nreg.reg_addr_high, readl(nctri->nreg.reg_addr_high));
	RAWNAND_DBG("reg_ndfc_cnt:	%p 0x%08x\n", nctri->nreg.reg_ndfc_cnt, readl(nctri->nreg.reg_ndfc_cnt));
	RAWNAND_DBG("reg_cmd:		%p 0x%08x\n", nctri->nreg.reg_cmd, readl(nctri->nreg.reg_cmd));
	RAWNAND_DBG("reg_read_cmd_set:	%p 0x%08x\n", nctri->nreg.reg_read_cmd_set, readl(nctri->nreg.reg_read_cmd_set));
	RAWNAND_DBG("reg_write_cmd_set:	%p 0x%08x\n", nctri->nreg.reg_write_cmd_set, readl(nctri->nreg.reg_write_cmd_set));
	RAWNAND_DBG("reg_io_data:	%p 0x%08x\n", nctri->nreg.reg_io_data, readl(nctri->nreg.reg_io_data));
	RAWNAND_DBG("reg_ecc_ctl:	%p 0x%08x\n", nctri->nreg.reg_ecc_ctl, readl(nctri->nreg.reg_ecc_ctl));
	RAWNAND_DBG("reg_ecc_sta:	%p 0x%08x\n", nctri->nreg.reg_ecc_sta, readl(nctri->nreg.reg_ecc_sta));
	RAWNAND_DBG("reg_efr: 		%p 0x%08x\n", nctri->nreg.reg_efr, readl(nctri->nreg.reg_efr));
	RAWNAND_DBG("reg_err_cnt0:	%p 0x%08x\n", nctri->nreg.reg_err_cnt0, readl(nctri->nreg.reg_err_cnt0));
	RAWNAND_DBG("reg_err_cnt1:	%p 0x%08x\n", nctri->nreg.reg_err_cnt1, readl(nctri->nreg.reg_err_cnt1));
	RAWNAND_DBG("reg_err_cnt2:	%p 0x%08x\n", nctri->nreg.reg_err_cnt2, readl(nctri->nreg.reg_err_cnt2));
	RAWNAND_DBG("reg_err_cnt3:	%p 0x%08x\n", nctri->nreg.reg_err_cnt3, readl(nctri->nreg.reg_err_cnt3));
	RAWNAND_DBG("reg_user_data_base:%p 0x%08x\n", nctri->nreg.reg_efnand_sta, readl(nctri->nreg.reg_efnand_sta));
	RAWNAND_DBG("reg_efnand_sta:	%p 0x%08x\n", nctri->nreg.reg_err_cnt1, readl(nctri->nreg.reg_err_cnt1));
	RAWNAND_DBG("reg_spare_area:	%p 0x%08x\n", nctri->nreg.reg_spare_area, readl(nctri->nreg.reg_spare_area));
	RAWNAND_DBG("reg_pat_id:	%p 0x%08x\n", nctri->nreg.reg_pat_id, readl(nctri->nreg.reg_pat_id));
	RAWNAND_DBG("reg_dma_cnt:	%p 0x%08x\n", nctri->nreg.reg_dma_cnt, readl(nctri->nreg.reg_dma_cnt));
	RAWNAND_DBG("reg_ram0_base:	%p 0x%08x\n", nctri->nreg.reg_ram0_base, readl(nctri->nreg.reg_ram0_base));
	RAWNAND_DBG("reg_ram1_base:	%p 0x%08x\n", nctri->nreg.reg_ram1_base, readl(nctri->nreg.reg_ram1_base));

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

void ndfc_channel_select(struct nand_controller_info *nctri, u32 channel_sel)
{
	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_sta |= *nctri->nreg.reg_sta & (NDFC_RB_B2R | NDFC_CMD_INT_FLAG | NDFC_DMA_INT_FLAG);*///czk delete 2019.9.30
	 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);

	//===================================
	//	   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
		writel((((cmd1 & 0xff) << 0) | ((cmd2 & 0xff) << 8)),
				nctri->nreg.reg_write_cmd_set);
	} else {
		//batch read cmd set
		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) {
		val = readl(nctri->nreg.reg_read_cmd_set);
		val |= (nctri->random_cmd2 << 24);
		writel(val, nctri->nreg.reg_read_cmd_set);
		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);
	//if (cmd_list->row_addr_auto_inc)
	//if((NAND_EF_INSERT_CMD == 1)&&(cmd_list->nctri_cmd[0].cmd_direction == 0)&&(NAND_EF_TYPE == 1))
	//	cmd_val |= 0x3<<28; 	//insert EF command
	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;
	}
	/*
	//===================================
	//	   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))	{
	print_cmd_seq(cmd_list);
	RAWNAND_ERR("_batch_cmd io_send, wait cmd fifo free timeout!\n");
	return ERR_TIMEOUT;
	}
	*/
	//===================================
	//	   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);

	//===================================
	//	   send cmd io
	//===================================
	//	if ((cmd_list->nctri_cmd[0].cmd_direction == 0)&&(cmd_list->nctri_cmd[0].cmd_mdata_addr != 0))
	//	{
	//		RAWNAND_DBG("1n1\n");
	//	}
	save_nctri(nctri);

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

	return ret;
}

/*****************************************************************************
 *Name         : _dma_config_start
 *Description  :
 *Parameter    :
 *Return       : NULL
 *Note         :
 *****************************************************************************/
int ndfc_dma_config_start(struct nand_controller_info *nctri, u8 rw, void *buff_addr, u32 len)
{
	u32 reg_val;
	u32 config_addr = 0;

	/*nand_clean_flush_dcache_region(buff_addr, len);*/

	if (nctri->dma_type == 1) {
		//MBUS DMA
		nctri->dma_addr = (unsigned long)nand_dma_map_single(&aw_ndfc, rw, buff_addr, len);
		if (nctri->dma_addr & 0x3) {
			RAWNAND_ERR("ndfc_dma_config_start_v1: buff addr(0x%llx) is not 32bit aligned", nctri->dma_addr);
		}

		//set mbus dma mode
		/*reg_val = *nctri->nreg.reg_ctl;*/
		reg_val = readl(nctri->nreg.reg_ctl);
		reg_val &= ~(0x1U << 15);
		reg_val |= 0x1U << 14;
		writel(reg_val, nctri->nreg.reg_ctl);
		/**nctri->nreg.reg_ctl = reg_val;*/

		nctri->ndfc_dma_desc_cpu[0].bcnt = 0;
		nctri->ndfc_dma_desc_cpu[0].bcnt |= NDFC_DESC_BSIZE(len);
		nctri->ndfc_dma_desc_cpu[0].buff = nctri->dma_addr; //buff_addr;

		nctri->ndfc_dma_desc_cpu[0].cfg = 0;
		nctri->ndfc_dma_desc_cpu[0].cfg |= NDFC_DESC_FIRST_FLAG;
		nctri->ndfc_dma_desc_cpu[0].cfg |= NDFC_DESC_LAST_FLAG;
		nctri->ndfc_dma_desc_cpu[0].next = &nctri->ndfc_dma_desc_cpu[0];

		config_addr = (unsigned long)nand_dma_map_single(&aw_ndfc, rw, nctri->ndfc_dma_desc_cpu, 1024);
		/*nand_clean_flush_dcache_region((void *)config_addr, 1024);*/
		writel(config_addr, nctri->nreg.reg_mbus_dma_dlba);

	} 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_dma_map_single(&aw_ndfc, 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;
}
