aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand
diff options
context:
space:
mode:
authorLei Wen <leiwen@marvell.com>2011-02-27 21:32:13 -0500
committerDavid Woodhouse <David.Woodhouse@intel.com>2011-03-11 09:22:50 -0500
commit4eb2da8994042d68e84e31138788429a102da2ea (patch)
tree15cadde3a7f28d923096c315ce0fd6942ff4ffc5 /drivers/mtd/nand
parent38caf7f68e6b4ad84094095887a490e3fa2ec501 (diff)
mtd: pxa3xx_nand: unify prepare command
Make the interface simpler which could make both debug and enhancement easier. Signed-off-by: Lei Wen <leiwen@marvell.com> Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r--drivers/mtd/nand/pxa3xx_nand.c249
1 files changed, 139 insertions, 110 deletions
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index be0aa44ada42..de0a2a25eb01 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -28,6 +28,7 @@
28 28
29#define CHIP_DELAY_TIMEOUT (2 * HZ/10) 29#define CHIP_DELAY_TIMEOUT (2 * HZ/10)
30#define NAND_STOP_DELAY (2 * HZ/50) 30#define NAND_STOP_DELAY (2 * HZ/50)
31#define PAGE_CHUNK_SIZE (2048)
31 32
32/* registers and bit definitions */ 33/* registers and bit definitions */
33#define NDCR (0x00) /* Control register */ 34#define NDCR (0x00) /* Control register */
@@ -77,6 +78,7 @@
77#define NDSR_RDDREQ (0x1 << 1) 78#define NDSR_RDDREQ (0x1 << 1)
78#define NDSR_WRCMDREQ (0x1) 79#define NDSR_WRCMDREQ (0x1)
79 80
81#define NDCB0_ST_ROW_EN (0x1 << 26)
80#define NDCB0_AUTO_RS (0x1 << 25) 82#define NDCB0_AUTO_RS (0x1 << 25)
81#define NDCB0_CSEL (0x1 << 24) 83#define NDCB0_CSEL (0x1 << 24)
82#define NDCB0_CMD_TYPE_MASK (0x7 << 21) 84#define NDCB0_CMD_TYPE_MASK (0x7 << 21)
@@ -319,66 +321,6 @@ static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info)
319 nand_writel(info, NDSR, NDSR_MASK); 321 nand_writel(info, NDSR, NDSR_MASK);
320} 322}
321 323
322static void prepare_read_prog_cmd(struct pxa3xx_nand_info *info,
323 uint16_t cmd, int column, int page_addr)
324{
325 const struct pxa3xx_nand_cmdset *cmdset = info->cmdset;
326 pxa3xx_set_datasize(info);
327
328 /* generate values for NDCBx registers */
329 info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
330 info->ndcb1 = 0;
331 info->ndcb2 = 0;
332 info->ndcb0 |= NDCB0_ADDR_CYC(info->row_addr_cycles + info->col_addr_cycles);
333
334 if (info->col_addr_cycles == 2) {
335 /* large block, 2 cycles for column address
336 * row address starts from 3rd cycle
337 */
338 info->ndcb1 |= page_addr << 16;
339 if (info->row_addr_cycles == 3)
340 info->ndcb2 = (page_addr >> 16) & 0xff;
341 } else
342 /* small block, 1 cycles for column address
343 * row address starts from 2nd cycle
344 */
345 info->ndcb1 = page_addr << 8;
346
347 if (cmd == cmdset->program)
348 info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS;
349}
350
351static void prepare_erase_cmd(struct pxa3xx_nand_info *info,
352 uint16_t cmd, int page_addr)
353{
354 info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
355 info->ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS | NDCB0_ADDR_CYC(3);
356 info->ndcb1 = page_addr;
357 info->ndcb2 = 0;
358}
359
360static void prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd)
361{
362 const struct pxa3xx_nand_cmdset *cmdset = info->cmdset;
363
364 info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
365 info->ndcb1 = 0;
366 info->ndcb2 = 0;
367
368 info->oob_size = 0;
369 if (cmd == cmdset->read_id) {
370 info->ndcb0 |= NDCB0_CMD_TYPE(3) | NDCB0_ADDR_CYC(1);
371 info->data_size = 8;
372 } else if (cmd == cmdset->read_status) {
373 info->ndcb0 |= NDCB0_CMD_TYPE(4);
374 info->data_size = 8;
375 } else if (cmd == cmdset->reset || cmd == cmdset->lock ||
376 cmd == cmdset->unlock) {
377 info->ndcb0 |= NDCB0_CMD_TYPE(5);
378 } else
379 BUG();
380}
381
382static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask) 324static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
383{ 325{
384 uint32_t ndcr; 326 uint32_t ndcr;
@@ -529,81 +471,167 @@ static inline int is_buf_blank(uint8_t *buf, size_t len)
529 return 1; 471 return 1;
530} 472}
531 473
532static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, 474static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
533 int column, int page_addr) 475 uint16_t column, int page_addr)
534{ 476{
535 struct pxa3xx_nand_info *info = mtd->priv; 477 uint16_t cmd;
536 const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; 478 int addr_cycle, exec_cmd, ndcb0;
537 int ret, exec_cmd = 0; 479 struct mtd_info *mtd = info->mtd;
480
481 ndcb0 = 0;
482 addr_cycle = 0;
483 exec_cmd = 1;
538 484
539 info->use_dma = (use_dma) ? 1 : 0; 485 /* reset data and oob column point to handle data */
540 info->use_ecc = 0; 486 info->buf_start = 0;
541 info->data_size = 0; 487 info->buf_count = 0;
542 info->state = 0; 488 info->oob_size = 0;
543 info->retcode = ERR_NONE; 489 info->use_ecc = 0;
490 info->retcode = ERR_NONE;
544 491
545 switch (command) { 492 switch (command) {
493 case NAND_CMD_READ0:
494 case NAND_CMD_PAGEPROG:
495 info->use_ecc = 1;
546 case NAND_CMD_READOOB: 496 case NAND_CMD_READOOB:
547 /* disable HW ECC to get all the OOB data */ 497 pxa3xx_set_datasize(info);
548 info->buf_count = mtd->writesize + mtd->oobsize; 498 break;
549 info->buf_start = mtd->writesize + column; 499 case NAND_CMD_SEQIN:
550 memset(info->data_buff, 0xFF, info->buf_count); 500 exec_cmd = 0;
551 501 break;
552 prepare_read_prog_cmd(info, cmdset->read1, column, page_addr); 502 default:
553 exec_cmd = 1; 503 info->ndcb1 = 0;
504 info->ndcb2 = 0;
554 break; 505 break;
506 }
507
508 info->ndcb0 = ndcb0;
509 addr_cycle = NDCB0_ADDR_CYC(info->row_addr_cycles
510 + info->col_addr_cycles);
555 511
512 switch (command) {
513 case NAND_CMD_READOOB:
556 case NAND_CMD_READ0: 514 case NAND_CMD_READ0:
557 info->use_ecc = 1; 515 cmd = info->cmdset->read1;
558 info->buf_start = column; 516 if (command == NAND_CMD_READOOB)
559 info->buf_count = mtd->writesize + mtd->oobsize; 517 info->buf_start = mtd->writesize + column;
560 memset(info->data_buff, 0xFF, info->buf_count); 518 else
519 info->buf_start = column;
520
521 if (unlikely(info->page_size < PAGE_CHUNK_SIZE))
522 info->ndcb0 |= NDCB0_CMD_TYPE(0)
523 | addr_cycle
524 | (cmd & NDCB0_CMD1_MASK);
525 else
526 info->ndcb0 |= NDCB0_CMD_TYPE(0)
527 | NDCB0_DBC
528 | addr_cycle
529 | cmd;
561 530
562 prepare_read_prog_cmd(info, cmdset->read1, column, page_addr);
563 exec_cmd = 1;
564 break;
565 case NAND_CMD_SEQIN: 531 case NAND_CMD_SEQIN:
566 info->buf_start = column; 532 /* small page addr setting */
533 if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) {
534 info->ndcb1 = ((page_addr & 0xFFFFFF) << 8)
535 | (column & 0xFF);
536
537 info->ndcb2 = 0;
538 } else {
539 info->ndcb1 = ((page_addr & 0xFFFF) << 16)
540 | (column & 0xFFFF);
541
542 if (page_addr & 0xFF0000)
543 info->ndcb2 = (page_addr & 0xFF0000) >> 16;
544 else
545 info->ndcb2 = 0;
546 }
547
567 info->buf_count = mtd->writesize + mtd->oobsize; 548 info->buf_count = mtd->writesize + mtd->oobsize;
568 memset(info->data_buff, 0xff, info->buf_count); 549 memset(info->data_buff, 0xFF, info->buf_count);
569 550
570 /* save column/page_addr for next CMD_PAGEPROG */
571 info->seqin_column = column;
572 info->seqin_page_addr = page_addr;
573 break; 551 break;
552
574 case NAND_CMD_PAGEPROG: 553 case NAND_CMD_PAGEPROG:
575 info->use_ecc = (info->seqin_column >= mtd->writesize) ? 0 : 1; 554 if (is_buf_blank(info->data_buff,
555 (mtd->writesize + mtd->oobsize))) {
556 exec_cmd = 0;
557 break;
558 }
576 559
577 prepare_read_prog_cmd(info, cmdset->program, 560 cmd = info->cmdset->program;
578 info->seqin_column, info->seqin_page_addr); 561 info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
579 exec_cmd = 1; 562 | NDCB0_AUTO_RS
580 break; 563 | NDCB0_ST_ROW_EN
581 case NAND_CMD_ERASE1: 564 | NDCB0_DBC
582 prepare_erase_cmd(info, cmdset->erase, page_addr); 565 | cmd
583 exec_cmd = 1; 566 | addr_cycle;
584 break;
585 case NAND_CMD_ERASE2:
586 break; 567 break;
568
587 case NAND_CMD_READID: 569 case NAND_CMD_READID:
570 cmd = info->cmdset->read_id;
571 info->buf_count = info->read_id_bytes;
572 info->ndcb0 |= NDCB0_CMD_TYPE(3)
573 | NDCB0_ADDR_CYC(1)
574 | cmd;
575
576 info->data_size = 8;
577 break;
588 case NAND_CMD_STATUS: 578 case NAND_CMD_STATUS:
589 info->use_dma = 0; /* force PIO read */ 579 cmd = info->cmdset->read_status;
590 info->buf_start = 0; 580 info->buf_count = 1;
591 info->buf_count = (command == NAND_CMD_READID) ? 581 info->ndcb0 |= NDCB0_CMD_TYPE(4)
592 info->read_id_bytes : 1; 582 | NDCB0_ADDR_CYC(1)
593 583 | cmd;
594 prepare_other_cmd(info, (command == NAND_CMD_READID) ? 584
595 cmdset->read_id : cmdset->read_status); 585 info->data_size = 8;
596 exec_cmd = 1; 586 break;
587
588 case NAND_CMD_ERASE1:
589 cmd = info->cmdset->erase;
590 info->ndcb0 |= NDCB0_CMD_TYPE(2)
591 | NDCB0_AUTO_RS
592 | NDCB0_ADDR_CYC(3)
593 | NDCB0_DBC
594 | cmd;
595 info->ndcb1 = page_addr;
596 info->ndcb2 = 0;
597
597 break; 598 break;
598 case NAND_CMD_RESET: 599 case NAND_CMD_RESET:
599 prepare_other_cmd(info, cmdset->reset); 600 cmd = info->cmdset->reset;
600 exec_cmd = 1; 601 info->ndcb0 |= NDCB0_CMD_TYPE(5)
602 | cmd;
603
604 break;
605
606 case NAND_CMD_ERASE2:
607 exec_cmd = 0;
601 break; 608 break;
609
602 default: 610 default:
603 printk(KERN_ERR "non-supported command.\n"); 611 exec_cmd = 0;
612 printk(KERN_ERR "pxa3xx-nand: non-supported"
613 " command %x\n", command);
604 break; 614 break;
605 } 615 }
606 616
617 return exec_cmd;
618}
619
620static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
621 int column, int page_addr)
622{
623 struct pxa3xx_nand_info *info = mtd->priv;
624 int ret, exec_cmd;
625
626 /*
627 * if this is a x16 device ,then convert the input
628 * "byte" address into a "word" address appropriate
629 * for indexing a word-oriented device
630 */
631 if (info->reg_ndcr & NDCR_DWIDTH_M)
632 column /= 2;
633
634 exec_cmd = prepare_command_pool(info, command, column, page_addr);
607 if (exec_cmd) { 635 if (exec_cmd) {
608 init_completion(&info->cmd_complete); 636 init_completion(&info->cmd_complete);
609 pxa3xx_nand_start(info); 637 pxa3xx_nand_start(info);
@@ -919,6 +947,7 @@ static void pxa3xx_nand_init_mtd(struct mtd_info *mtd,
919 struct nand_chip *this = &info->nand_chip; 947 struct nand_chip *this = &info->nand_chip;
920 948
921 this->options = (info->reg_ndcr & NDCR_DWIDTH_C) ? NAND_BUSWIDTH_16: 0; 949 this->options = (info->reg_ndcr & NDCR_DWIDTH_C) ? NAND_BUSWIDTH_16: 0;
950 this->options |= NAND_NO_AUTOINCR;
922 951
923 this->waitfunc = pxa3xx_nand_waitfunc; 952 this->waitfunc = pxa3xx_nand_waitfunc;
924 this->select_chip = pxa3xx_nand_select_chip; 953 this->select_chip = pxa3xx_nand_select_chip;