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 @@ ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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;
......
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