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

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
......@@ -28,6 +28,7 @@
#define CHIP_DELAY_TIMEOUT (2 * HZ/10)
#define NAND_STOP_DELAY (2 * HZ/50)
#define PAGE_CHUNK_SIZE (2048)
/* registers and bit definitions */
#define NDCR (0x00) /* Control register */
......@@ -77,6 +78,7 @@
#define NDSR_RDDREQ (0x1 << 1)
#define NDSR_WRCMDREQ (0x1)
#define NDCB0_ST_ROW_EN (0x1 << 26)
#define NDCB0_AUTO_RS (0x1 << 25)
#define NDCB0_CSEL (0x1 << 24)
#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);
}
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)
{
uint32_t ndcr;
......@@ -529,81 +471,167 @@ static inline int is_buf_blank(uint8_t *buf, size_t len)
return 1;
}
static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
int column, int page_addr)
static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
uint16_t column, int page_addr)
{
struct pxa3xx_nand_info *info = mtd->priv;
const struct pxa3xx_nand_cmdset *cmdset = info->cmdset;
int ret, exec_cmd = 0;
uint16_t cmd;
int addr_cycle, exec_cmd, ndcb0;
struct mtd_info *mtd = info->mtd;
ndcb0 = 0;
addr_cycle = 0;
exec_cmd = 1;
info->use_dma = (use_dma) ? 1 : 0;
info->use_ecc = 0;
info->data_size = 0;
info->state = 0;
info->retcode = ERR_NONE;
/* 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->retcode = ERR_NONE;
switch (command) {
case NAND_CMD_READ0:
case NAND_CMD_PAGEPROG:
info->use_ecc = 1;
case NAND_CMD_READOOB:
/* disable HW ECC to get all the OOB data */
info->buf_count = mtd->writesize + mtd->oobsize;
info->buf_start = mtd->writesize + column;
memset(info->data_buff, 0xFF, info->buf_count);
prepare_read_prog_cmd(info, cmdset->read1, column, page_addr);
exec_cmd = 1;
pxa3xx_set_datasize(info);
break;
case NAND_CMD_SEQIN:
exec_cmd = 0;
break;
default:
info->ndcb1 = 0;
info->ndcb2 = 0;
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:
info->use_ecc = 1;
info->buf_start = column;
info->buf_count = mtd->writesize + mtd->oobsize;
memset(info->data_buff, 0xFF, info->buf_count);
cmd = info->cmdset->read1;
if (command == NAND_CMD_READOOB)
info->buf_start = mtd->writesize + column;
else
info->buf_start = column;
if (unlikely(info->page_size < PAGE_CHUNK_SIZE))
info->ndcb0 |= NDCB0_CMD_TYPE(0)
| addr_cycle
| (cmd & NDCB0_CMD1_MASK);
else
info->ndcb0 |= NDCB0_CMD_TYPE(0)
| NDCB0_DBC
| addr_cycle
| cmd;
prepare_read_prog_cmd(info, cmdset->read1, column, page_addr);
exec_cmd = 1;
break;
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;
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;
case NAND_CMD_PAGEPROG:
info->use_ecc = (info->seqin_column >= mtd->writesize) ? 0 : 1;
if (is_buf_blank(info->data_buff,
(mtd->writesize + mtd->oobsize))) {
exec_cmd = 0;
break;
}
prepare_read_prog_cmd(info, cmdset->program,
info->seqin_column, info->seqin_page_addr);
exec_cmd = 1;
break;
case NAND_CMD_ERASE1:
prepare_erase_cmd(info, cmdset->erase, page_addr);
exec_cmd = 1;
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;
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:
info->use_dma = 0; /* force PIO read */
info->buf_start = 0;
info->buf_count = (command == NAND_CMD_READID) ?
info->read_id_bytes : 1;
prepare_other_cmd(info, (command == NAND_CMD_READID) ?
cmdset->read_id : cmdset->read_status);
exec_cmd = 1;
cmd = info->cmdset->read_status;
info->buf_count = 1;
info->ndcb0 |= NDCB0_CMD_TYPE(4)
| 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;
break;
case NAND_CMD_RESET:
prepare_other_cmd(info, cmdset->reset);
exec_cmd = 1;
cmd = info->cmdset->reset;
info->ndcb0 |= NDCB0_CMD_TYPE(5)
| cmd;
break;
case NAND_CMD_ERASE2:
exec_cmd = 0;
break;
default:
printk(KERN_ERR "non-supported command.\n");
exec_cmd = 0;
printk(KERN_ERR "pxa3xx-nand: non-supported"
" command %x\n", command);
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) {
init_completion(&info->cmd_complete);
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;
this->options = (info->reg_ndcr & NDCR_DWIDTH_C) ? NAND_BUSWIDTH_16: 0;
this->options |= NAND_NO_AUTOINCR;
this->waitfunc = pxa3xx_nand_waitfunc;
this->select_chip = pxa3xx_nand_select_chip;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment