|
28 | 28 |
|
29 | 29 | #define CHIP_DELAY_TIMEOUT (2 * HZ/10)
|
30 | 30 | #define NAND_STOP_DELAY (2 * HZ/50)
|
| 31 | +#define PAGE_CHUNK_SIZE (2048) |
31 | 32 |
|
32 | 33 | /* registers and bit definitions */
|
33 | 34 | #define NDCR (0x00) /* Control register */
|
|
77 | 78 | #define NDSR_RDDREQ (0x1 << 1)
|
78 | 79 | #define NDSR_WRCMDREQ (0x1)
|
79 | 80 |
|
| 81 | +#define NDCB0_ST_ROW_EN (0x1 << 26) |
80 | 82 | #define NDCB0_AUTO_RS (0x1 << 25)
|
81 | 83 | #define NDCB0_CSEL (0x1 << 24)
|
82 | 84 | #define NDCB0_CMD_TYPE_MASK (0x7 << 21)
|
@@ -319,66 +321,6 @@ static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info)
|
319 | 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 | 324 | static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
|
383 | 325 | {
|
384 | 326 | uint32_t ndcr;
|
@@ -529,81 +471,167 @@ static inline int is_buf_blank(uint8_t *buf, size_t len)
|
529 | 471 | return 1;
|
530 | 472 | }
|
531 | 473 |
|
532 |
| -static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, |
533 |
| - int column, int page_addr) |
| 474 | +static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, |
| 475 | + uint16_t column, int page_addr) |
534 | 476 | {
|
535 |
| - struct pxa3xx_nand_info *info = mtd->priv; |
536 |
| - const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; |
537 |
| - int ret, exec_cmd = 0; |
| 477 | + uint16_t cmd; |
| 478 | + int addr_cycle, exec_cmd, ndcb0; |
| 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; |
540 |
| - info->use_ecc = 0; |
541 |
| - info->data_size = 0; |
542 |
| - info->state = 0; |
543 |
| - info->retcode = ERR_NONE; |
| 485 | + /* reset data and oob column point to handle data */ |
| 486 | + info->buf_start = 0; |
| 487 | + info->buf_count = 0; |
| 488 | + info->oob_size = 0; |
| 489 | + info->use_ecc = 0; |
| 490 | + info->retcode = ERR_NONE; |
544 | 491 |
|
545 | 492 | switch (command) {
|
| 493 | + case NAND_CMD_READ0: |
| 494 | + case NAND_CMD_PAGEPROG: |
| 495 | + info->use_ecc = 1; |
546 | 496 | case NAND_CMD_READOOB:
|
547 |
| - /* disable HW ECC to get all the OOB data */ |
548 |
| - info->buf_count = mtd->writesize + mtd->oobsize; |
549 |
| - info->buf_start = mtd->writesize + column; |
550 |
| - memset(info->data_buff, 0xFF, info->buf_count); |
551 |
| - |
552 |
| - prepare_read_prog_cmd(info, cmdset->read1, column, page_addr); |
553 |
| - exec_cmd = 1; |
| 497 | + pxa3xx_set_datasize(info); |
| 498 | + break; |
| 499 | + case NAND_CMD_SEQIN: |
| 500 | + exec_cmd = 0; |
| 501 | + break; |
| 502 | + default: |
| 503 | + info->ndcb1 = 0; |
| 504 | + info->ndcb2 = 0; |
554 | 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 | 514 | case NAND_CMD_READ0:
|
557 |
| - info->use_ecc = 1; |
558 |
| - info->buf_start = column; |
559 |
| - info->buf_count = mtd->writesize + mtd->oobsize; |
560 |
| - memset(info->data_buff, 0xFF, info->buf_count); |
| 515 | + cmd = info->cmdset->read1; |
| 516 | + if (command == NAND_CMD_READOOB) |
| 517 | + info->buf_start = mtd->writesize + column; |
| 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 | 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 | 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 | 551 | break;
|
| 552 | + |
574 | 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, |
578 |
| - info->seqin_column, info->seqin_page_addr); |
579 |
| - exec_cmd = 1; |
580 |
| - break; |
581 |
| - case NAND_CMD_ERASE1: |
582 |
| - prepare_erase_cmd(info, cmdset->erase, page_addr); |
583 |
| - exec_cmd = 1; |
584 |
| - break; |
585 |
| - case NAND_CMD_ERASE2: |
| 560 | + cmd = info->cmdset->program; |
| 561 | + info->ndcb0 |= NDCB0_CMD_TYPE(0x1) |
| 562 | + | NDCB0_AUTO_RS |
| 563 | + | NDCB0_ST_ROW_EN |
| 564 | + | NDCB0_DBC |
| 565 | + | cmd |
| 566 | + | addr_cycle; |
586 | 567 | break;
|
| 568 | + |
587 | 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 | 578 | case NAND_CMD_STATUS:
|
589 |
| - info->use_dma = 0; /* force PIO read */ |
590 |
| - info->buf_start = 0; |
591 |
| - info->buf_count = (command == NAND_CMD_READID) ? |
592 |
| - info->read_id_bytes : 1; |
593 |
| - |
594 |
| - prepare_other_cmd(info, (command == NAND_CMD_READID) ? |
595 |
| - cmdset->read_id : cmdset->read_status); |
596 |
| - exec_cmd = 1; |
| 579 | + cmd = info->cmdset->read_status; |
| 580 | + info->buf_count = 1; |
| 581 | + info->ndcb0 |= NDCB0_CMD_TYPE(4) |
| 582 | + | NDCB0_ADDR_CYC(1) |
| 583 | + | cmd; |
| 584 | + |
| 585 | + info->data_size = 8; |
| 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 | 598 | break;
|
598 | 599 | case NAND_CMD_RESET:
|
599 |
| - prepare_other_cmd(info, cmdset->reset); |
600 |
| - exec_cmd = 1; |
| 600 | + cmd = info->cmdset->reset; |
| 601 | + info->ndcb0 |= NDCB0_CMD_TYPE(5) |
| 602 | + | cmd; |
| 603 | + |
| 604 | + break; |
| 605 | + |
| 606 | + case NAND_CMD_ERASE2: |
| 607 | + exec_cmd = 0; |
601 | 608 | break;
|
| 609 | + |
602 | 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 | 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 | 635 | if (exec_cmd) {
|
608 | 636 | init_completion(&info->cmd_complete);
|
609 | 637 | pxa3xx_nand_start(info);
|
@@ -919,6 +947,7 @@ static void pxa3xx_nand_init_mtd(struct mtd_info *mtd,
|
919 | 947 | struct nand_chip *this = &info->nand_chip;
|
920 | 948 |
|
921 | 949 | this->options = (info->reg_ndcr & NDCR_DWIDTH_C) ? NAND_BUSWIDTH_16: 0;
|
| 950 | + this->options |= NAND_NO_AUTOINCR; |
922 | 951 |
|
923 | 952 | this->waitfunc = pxa3xx_nand_waitfunc;
|
924 | 953 | this->select_chip = pxa3xx_nand_select_chip;
|
|
0 commit comments