Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4eb2da89 authored by Lei Wen's avatar Lei Wen Committed by David Woodhouse
Browse files

mtd: pxa3xx_nand: unify prepare command



Make the interface simpler which could make both debug
and enhancement easier.

Signed-off-by: default avatarLei Wen <leiwen@marvell.com>
Signed-off-by: default avatarHaojian Zhuang <haojian.zhuang@marvell.com>
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent 38caf7f6
Loading
Loading
Loading
Loading
+139 −110
Original line number Original line Diff line number Diff line
@@ -28,6 +28,7 @@


#define	CHIP_DELAY_TIMEOUT	(2 * HZ/10)
#define	CHIP_DELAY_TIMEOUT	(2 * HZ/10)
#define NAND_STOP_DELAY		(2 * HZ/50)
#define NAND_STOP_DELAY		(2 * HZ/50)
#define PAGE_CHUNK_SIZE		(2048)


/* registers and bit definitions */
/* registers and bit definitions */
#define NDCR		(0x00) /* Control register */
#define NDCR		(0x00) /* Control register */
@@ -77,6 +78,7 @@
#define NDSR_RDDREQ		(0x1 << 1)
#define NDSR_RDDREQ		(0x1 << 1)
#define NDSR_WRCMDREQ		(0x1)
#define NDSR_WRCMDREQ		(0x1)


#define NDCB0_ST_ROW_EN         (0x1 << 26)
#define NDCB0_AUTO_RS		(0x1 << 25)
#define NDCB0_AUTO_RS		(0x1 << 25)
#define NDCB0_CSEL		(0x1 << 24)
#define NDCB0_CSEL		(0x1 << 24)
#define NDCB0_CMD_TYPE_MASK	(0x7 << 21)
#define NDCB0_CMD_TYPE_MASK	(0x7 << 21)
@@ -319,66 +321,6 @@ static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info)
	nand_writel(info, NDSR, NDSR_MASK);
	nand_writel(info, NDSR, NDSR_MASK);
}
}


static void prepare_read_prog_cmd(struct pxa3xx_nand_info *info,
		uint16_t cmd, int column, int page_addr)
{
	const struct pxa3xx_nand_cmdset *cmdset = info->cmdset;
	pxa3xx_set_datasize(info);

	/* generate values for NDCBx registers */
	info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
	info->ndcb1 = 0;
	info->ndcb2 = 0;
	info->ndcb0 |= NDCB0_ADDR_CYC(info->row_addr_cycles + info->col_addr_cycles);

	if (info->col_addr_cycles == 2) {
		/* large block, 2 cycles for column address
		 * row address starts from 3rd cycle
		 */
		info->ndcb1 |= page_addr << 16;
		if (info->row_addr_cycles == 3)
			info->ndcb2 = (page_addr >> 16) & 0xff;
	} else
		/* small block, 1 cycles for column address
		 * row address starts from 2nd cycle
		 */
		info->ndcb1 = page_addr << 8;

	if (cmd == cmdset->program)
		info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS;
}

static void prepare_erase_cmd(struct pxa3xx_nand_info *info,
			uint16_t cmd, int page_addr)
{
	info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
	info->ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS | NDCB0_ADDR_CYC(3);
	info->ndcb1 = page_addr;
	info->ndcb2 = 0;
}

static void prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd)
{
	const struct pxa3xx_nand_cmdset *cmdset = info->cmdset;

	info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
	info->ndcb1 = 0;
	info->ndcb2 = 0;

	info->oob_size = 0;
	if (cmd == cmdset->read_id) {
		info->ndcb0 |= NDCB0_CMD_TYPE(3) | NDCB0_ADDR_CYC(1);
		info->data_size = 8;
	} else if (cmd == cmdset->read_status) {
		info->ndcb0 |= NDCB0_CMD_TYPE(4);
		info->data_size = 8;
	} else if (cmd == cmdset->reset || cmd == cmdset->lock ||
		   cmd == cmdset->unlock) {
		info->ndcb0 |= NDCB0_CMD_TYPE(5);
	} else
		BUG();
}

static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
{
{
	uint32_t ndcr;
	uint32_t ndcr;
@@ -529,81 +471,167 @@ static inline int is_buf_blank(uint8_t *buf, size_t len)
	return 1;
	return 1;
}
}


static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
				int column, int page_addr)
		uint16_t column, int page_addr)
{
{
	struct pxa3xx_nand_info *info = mtd->priv;
	uint16_t cmd;
	const struct pxa3xx_nand_cmdset *cmdset = info->cmdset;
	int addr_cycle, exec_cmd, ndcb0;
	int ret, exec_cmd = 0;
	struct mtd_info *mtd = info->mtd;


	info->use_dma = (use_dma) ? 1 : 0;
	ndcb0 = 0;
	addr_cycle = 0;
	exec_cmd = 1;

	/* reset data and oob column point to handle data */
	info->buf_start	= 0;
	info->buf_count	= 0;
	info->oob_size		= 0;
	info->use_ecc		= 0;
	info->use_ecc		= 0;
	info->data_size = 0;
	info->state = 0;
	info->retcode		= ERR_NONE;
	info->retcode		= ERR_NONE;


	switch (command) {
	switch (command) {
	case NAND_CMD_READ0:
	case NAND_CMD_PAGEPROG:
		info->use_ecc = 1;
	case NAND_CMD_READOOB:
	case NAND_CMD_READOOB:
		/* disable HW ECC to get all the OOB data */
		pxa3xx_set_datasize(info);
		info->buf_count = mtd->writesize + mtd->oobsize;
		break;
		info->buf_start = mtd->writesize + column;
	case NAND_CMD_SEQIN:
		memset(info->data_buff, 0xFF, info->buf_count);
		exec_cmd = 0;

		break;
		prepare_read_prog_cmd(info, cmdset->read1, column, page_addr);
	default:
		exec_cmd = 1;
		info->ndcb1 = 0;
		info->ndcb2 = 0;
		break;
		break;
	}

	info->ndcb0 = ndcb0;
	addr_cycle = NDCB0_ADDR_CYC(info->row_addr_cycles
				    + info->col_addr_cycles);


	switch (command) {
	case NAND_CMD_READOOB:
	case NAND_CMD_READ0:
	case NAND_CMD_READ0:
		info->use_ecc = 1;
		cmd = info->cmdset->read1;
		if (command == NAND_CMD_READOOB)
			info->buf_start = mtd->writesize + column;
		else
			info->buf_start = column;
			info->buf_start = column;
		info->buf_count = mtd->writesize + mtd->oobsize;
		memset(info->data_buff, 0xFF, info->buf_count);


		prepare_read_prog_cmd(info, cmdset->read1, column, page_addr);
		if (unlikely(info->page_size < PAGE_CHUNK_SIZE))
		exec_cmd = 1;
			info->ndcb0 |= NDCB0_CMD_TYPE(0)
		break;
					| addr_cycle
					| (cmd & NDCB0_CMD1_MASK);
		else
			info->ndcb0 |= NDCB0_CMD_TYPE(0)
					| NDCB0_DBC
					| addr_cycle
					| cmd;

	case NAND_CMD_SEQIN:
	case NAND_CMD_SEQIN:
		info->buf_start = column;
		/* small page addr setting */
		if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) {
			info->ndcb1 = ((page_addr & 0xFFFFFF) << 8)
					| (column & 0xFF);

			info->ndcb2 = 0;
		} else {
			info->ndcb1 = ((page_addr & 0xFFFF) << 16)
					| (column & 0xFFFF);

			if (page_addr & 0xFF0000)
				info->ndcb2 = (page_addr & 0xFF0000) >> 16;
			else
				info->ndcb2 = 0;
		}

		info->buf_count = mtd->writesize + mtd->oobsize;
		info->buf_count = mtd->writesize + mtd->oobsize;
		memset(info->data_buff, 0xff, info->buf_count);
		memset(info->data_buff, 0xFF, info->buf_count);


		/* save column/page_addr for next CMD_PAGEPROG */
		info->seqin_column = column;
		info->seqin_page_addr = page_addr;
		break;
		break;
	case NAND_CMD_PAGEPROG:
		info->use_ecc = (info->seqin_column >= mtd->writesize) ? 0 : 1;


		prepare_read_prog_cmd(info, cmdset->program,
	case NAND_CMD_PAGEPROG:
				info->seqin_column, info->seqin_page_addr);
		if (is_buf_blank(info->data_buff,
		exec_cmd = 1;
					(mtd->writesize + mtd->oobsize))) {
		break;
			exec_cmd = 0;
	case NAND_CMD_ERASE1:
		prepare_erase_cmd(info, cmdset->erase, page_addr);
		exec_cmd = 1;
			break;
			break;
	case NAND_CMD_ERASE2:
		}

		cmd = info->cmdset->program;
		info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
				| NDCB0_AUTO_RS
				| NDCB0_ST_ROW_EN
				| NDCB0_DBC
				| cmd
				| addr_cycle;
		break;
		break;

	case NAND_CMD_READID:
	case NAND_CMD_READID:
		cmd = info->cmdset->read_id;
		info->buf_count = info->read_id_bytes;
		info->ndcb0 |= NDCB0_CMD_TYPE(3)
				| NDCB0_ADDR_CYC(1)
				| cmd;

		info->data_size = 8;
		break;
	case NAND_CMD_STATUS:
	case NAND_CMD_STATUS:
		info->use_dma = 0;	/* force PIO read */
		cmd = info->cmdset->read_status;
		info->buf_start = 0;
		info->buf_count = 1;
		info->buf_count = (command == NAND_CMD_READID) ?
		info->ndcb0 |= NDCB0_CMD_TYPE(4)
				info->read_id_bytes : 1;
				| NDCB0_ADDR_CYC(1)
				| cmd;

		info->data_size = 8;
		break;

	case NAND_CMD_ERASE1:
		cmd = info->cmdset->erase;
		info->ndcb0 |= NDCB0_CMD_TYPE(2)
				| NDCB0_AUTO_RS
				| NDCB0_ADDR_CYC(3)
				| NDCB0_DBC
				| cmd;
		info->ndcb1 = page_addr;
		info->ndcb2 = 0;


		prepare_other_cmd(info, (command == NAND_CMD_READID) ?
				cmdset->read_id : cmdset->read_status);
		exec_cmd = 1;
		break;
		break;
	case NAND_CMD_RESET:
	case NAND_CMD_RESET:
		prepare_other_cmd(info, cmdset->reset);
		cmd = info->cmdset->reset;
		exec_cmd = 1;
		info->ndcb0 |= NDCB0_CMD_TYPE(5)
				| cmd;

		break;
		break;

	case NAND_CMD_ERASE2:
		exec_cmd = 0;
		break;

	default:
	default:
		printk(KERN_ERR "non-supported command.\n");
		exec_cmd = 0;
		printk(KERN_ERR "pxa3xx-nand: non-supported"
			" command %x\n", command);
		break;
		break;
	}
	}


	return exec_cmd;
}

static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
				int column, int page_addr)
{
	struct pxa3xx_nand_info *info = mtd->priv;
	int ret, exec_cmd;

	/*
	 * if this is a x16 device ,then convert the input
	 * "byte" address into a "word" address appropriate
	 * for indexing a word-oriented device
	 */
	if (info->reg_ndcr & NDCR_DWIDTH_M)
		column /= 2;

	exec_cmd = prepare_command_pool(info, command, column, page_addr);
	if (exec_cmd) {
	if (exec_cmd) {
		init_completion(&info->cmd_complete);
		init_completion(&info->cmd_complete);
		pxa3xx_nand_start(info);
		pxa3xx_nand_start(info);
@@ -919,6 +947,7 @@ static void pxa3xx_nand_init_mtd(struct mtd_info *mtd,
	struct nand_chip *this = &info->nand_chip;
	struct nand_chip *this = &info->nand_chip;


	this->options = (info->reg_ndcr & NDCR_DWIDTH_C) ? NAND_BUSWIDTH_16: 0;
	this->options = (info->reg_ndcr & NDCR_DWIDTH_C) ? NAND_BUSWIDTH_16: 0;
	this->options |= NAND_NO_AUTOINCR;


	this->waitfunc		= pxa3xx_nand_waitfunc;
	this->waitfunc		= pxa3xx_nand_waitfunc;
	this->select_chip	= pxa3xx_nand_select_chip;
	this->select_chip	= pxa3xx_nand_select_chip;