diff options
author | Lei Wen <leiwen@marvell.com> | 2011-02-27 21:32:13 -0500 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2011-03-11 09:22:50 -0500 |
commit | 4eb2da8994042d68e84e31138788429a102da2ea (patch) | |
tree | 15cadde3a7f28d923096c315ce0fd6942ff4ffc5 /drivers/mtd/nand | |
parent | 38caf7f68e6b4ad84094095887a490e3fa2ec501 (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.c | 249 |
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 | ||
322 | static 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 | |||
351 | static 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 | |||
360 | static 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 | |||
382 | static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask) | 324 | static 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 | ||
532 | static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, | 474 | static 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 | |||
620 | static 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; |