diff options
Diffstat (limited to 'firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c')
-rw-r--r-- | firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c | 204 |
1 files changed, 201 insertions, 3 deletions
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c b/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c index 3b5f88d3c2..84bf0e6bb8 100644 --- a/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c +++ b/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c | |||
@@ -99,13 +99,14 @@ static struct wakeup ecc_wakeup; | |||
99 | 99 | ||
100 | static uint8_t nand_data[0x800] __attribute__((aligned(16))); | 100 | static uint8_t nand_data[0x800] __attribute__((aligned(16))); |
101 | static uint8_t nand_ctrl[0x200] __attribute__((aligned(16))); | 101 | static uint8_t nand_ctrl[0x200] __attribute__((aligned(16))); |
102 | static uint8_t nand_spare[0x40] __attribute__((aligned(16))); | 102 | static uint8_t nand_spare[4][0x40] __attribute__((aligned(16))); |
103 | static uint8_t nand_ecc[0x30] __attribute__((aligned(16))); | 103 | static uint8_t nand_ecc[0x30] __attribute__((aligned(16))); |
104 | 104 | ||
105 | 105 | ||
106 | uint32_t nand_unlock(uint32_t rc) | 106 | uint32_t nand_unlock(uint32_t rc) |
107 | { | 107 | { |
108 | led(false); | 108 | led(false); |
109 | nand_last_activity_value = current_tick; | ||
109 | mutex_unlock(&nand_mtx); | 110 | mutex_unlock(&nand_mtx); |
110 | return rc; | 111 | return rc; |
111 | } | 112 | } |
@@ -371,7 +372,7 @@ uint32_t nand_read_page(uint32_t bank, uint32_t page, void* databuffer, | |||
371 | uint32_t checkempty) | 372 | uint32_t checkempty) |
372 | { | 373 | { |
373 | uint8_t* data = nand_data; | 374 | uint8_t* data = nand_data; |
374 | uint8_t* spare = nand_spare; | 375 | uint8_t* spare = nand_spare[0]; |
375 | if (databuffer && !((uint32_t)databuffer & 0xf)) | 376 | if (databuffer && !((uint32_t)databuffer & 0xf)) |
376 | data = (uint8_t*)databuffer; | 377 | data = (uint8_t*)databuffer; |
377 | if (sparebuffer && !((uint32_t)sparebuffer & 0xf)) | 378 | if (sparebuffer && !((uint32_t)sparebuffer & 0xf)) |
@@ -432,7 +433,7 @@ uint32_t nand_write_page(uint32_t bank, uint32_t page, void* databuffer, | |||
432 | void* sparebuffer, uint32_t doecc) | 433 | void* sparebuffer, uint32_t doecc) |
433 | { | 434 | { |
434 | uint8_t* data = nand_data; | 435 | uint8_t* data = nand_data; |
435 | uint8_t* spare = nand_spare; | 436 | uint8_t* spare = nand_spare[0]; |
436 | if (databuffer && !((uint32_t)databuffer & 0xf)) | 437 | if (databuffer && !((uint32_t)databuffer & 0xf)) |
437 | data = (uint8_t*)databuffer; | 438 | data = (uint8_t*)databuffer; |
438 | if (sparebuffer && !((uint32_t)sparebuffer & 0xf)) | 439 | if (sparebuffer && !((uint32_t)sparebuffer & 0xf)) |
@@ -487,6 +488,203 @@ uint32_t nand_block_erase(uint32_t bank, uint32_t page) | |||
487 | return nand_unlock(0); | 488 | return nand_unlock(0); |
488 | } | 489 | } |
489 | 490 | ||
491 | uint32_t nand_read_page_fast(uint32_t page, void* databuffer, | ||
492 | void* sparebuffer, uint32_t doecc, | ||
493 | uint32_t checkempty) | ||
494 | { | ||
495 | uint32_t i, rc = 0; | ||
496 | if (((uint32_t)databuffer & 0xf) || ((uint32_t)sparebuffer & 0xf) | ||
497 | || !databuffer || !sparebuffer || !doecc) | ||
498 | { | ||
499 | for (i = 0; i < 4; i++) | ||
500 | { | ||
501 | if (nand_type[i] == 0xFFFFFFFF) continue; | ||
502 | void* databuf = (void*)0; | ||
503 | void* sparebuf = (void*)0; | ||
504 | if (databuffer) databuf = (void*)((uint32_t)databuffer + 0x800 * i); | ||
505 | if (sparebuffer) sparebuf = (void*)((uint32_t)sparebuffer + 0x40 * i); | ||
506 | uint32_t ret = nand_read_page(i, page, databuf, sparebuf, doecc, checkempty); | ||
507 | if (ret & 1) rc |= 1 << (i << 2); | ||
508 | if (ret & 2) rc |= 2 << (i << 2); | ||
509 | if (ret & 0x10) rc |= 4 << (i << 2); | ||
510 | if (ret & 0x100) rc |= 8 << (i << 2); | ||
511 | } | ||
512 | return rc; | ||
513 | } | ||
514 | mutex_lock(&nand_mtx); | ||
515 | nand_last_activity_value = current_tick; | ||
516 | led(true); | ||
517 | if (!nand_powered) nand_power_up(); | ||
518 | for (i = 0; i < 4; i++) | ||
519 | { | ||
520 | if (nand_type[i] == 0xFFFFFFFF) continue; | ||
521 | nand_set_fmctrl0(i, FMCTRL0_ENABLEDMA); | ||
522 | if (nand_send_cmd(NAND_CMD_READ)) | ||
523 | { | ||
524 | rc |= 1 << (i << 2); | ||
525 | continue; | ||
526 | } | ||
527 | if (nand_send_address(page, databuffer ? 0 : 0x800)) | ||
528 | { | ||
529 | rc |= 1 << (i << 2); | ||
530 | continue; | ||
531 | } | ||
532 | if (nand_send_cmd(NAND_CMD_READ2)) | ||
533 | { | ||
534 | rc |= 1 << (i << 2); | ||
535 | continue; | ||
536 | } | ||
537 | } | ||
538 | for (i = 0; i < 4; i++) | ||
539 | { | ||
540 | if (nand_type[i] == 0xFFFFFFFF) continue; | ||
541 | if (nand_wait_status_ready(i)) | ||
542 | { | ||
543 | rc |= 1 << (i << 2); | ||
544 | continue; | ||
545 | } | ||
546 | if (nand_transfer_data(i, 0, (void*)((uint32_t)databuffer | ||
547 | + 0x800 * i), 0x800)) | ||
548 | { | ||
549 | rc |= 1 << (i << 2); | ||
550 | continue; | ||
551 | } | ||
552 | if (nand_transfer_data(i, 0, (void*)((uint32_t)sparebuffer | ||
553 | + 0x40 * i), 0x40)) | ||
554 | { | ||
555 | rc |= 1 << (i << 2); | ||
556 | continue; | ||
557 | } | ||
558 | memcpy(nand_ecc, (void*)((uint32_t)sparebuffer + 0x40 * i + 0xC), 0x28); | ||
559 | if (ecc_decode(3, (void*)((uint32_t)databuffer + 0x800 * i), nand_ecc) & 1) | ||
560 | rc |= 4 << (i << 2); | ||
561 | memset(nand_ctrl, 0xFF, 0x200); | ||
562 | memcpy(nand_ctrl, (void*)((uint32_t)sparebuffer + 0x40 * i), 0xC); | ||
563 | memcpy(nand_ecc, (void*)((uint32_t)sparebuffer + 0x40 * i + 0x34), 0xC); | ||
564 | if (ecc_decode(0, nand_ctrl, nand_ecc)) | ||
565 | { | ||
566 | rc |= 8 << (i << 2); | ||
567 | memset((void*)((uint32_t)sparebuffer + 0x40 * i), 0xFF, 0xC); | ||
568 | } | ||
569 | else memcpy((void*)((uint32_t)sparebuffer + 0x40 * i), nand_ctrl, 0xC); | ||
570 | if (checkempty) | ||
571 | rc |= nand_check_empty((void*)((uint32_t)sparebuffer | ||
572 | + 0x40 * i)) << ((i << 2) + 1); | ||
573 | } | ||
574 | return nand_unlock(rc); | ||
575 | } | ||
576 | |||
577 | uint32_t nand_write_page_fast(uint32_t page, void* databuffer, | ||
578 | void* sparebuffer, uint32_t doecc) | ||
579 | { | ||
580 | uint32_t i, rc = 0; | ||
581 | if (((uint32_t)databuffer & 0xf) || ((uint32_t)sparebuffer & 0xf) | ||
582 | || !databuffer || !sparebuffer || !doecc) | ||
583 | { | ||
584 | for (i = 0; i < 4; i++) | ||
585 | { | ||
586 | if (nand_type[i] == 0xFFFFFFFF) continue; | ||
587 | void* databuf = (void*)0; | ||
588 | void* sparebuf = (void*)0; | ||
589 | if (databuffer) databuf = (void*)((uint32_t)databuffer + 0x800 * i); | ||
590 | if (sparebuffer) sparebuf = (void*)((uint32_t)sparebuffer + 0x40 * i); | ||
591 | rc |= nand_write_page(i, page, databuf, sparebuf, doecc) << i; | ||
592 | } | ||
593 | return rc; | ||
594 | } | ||
595 | mutex_lock(&nand_mtx); | ||
596 | nand_last_activity_value = current_tick; | ||
597 | led(true); | ||
598 | if (!nand_powered) nand_power_up(); | ||
599 | for (i = 0; i < 4; i++) | ||
600 | { | ||
601 | if (nand_type[i] == 0xFFFFFFFF) continue; | ||
602 | if (ecc_encode(3, (void*)((uint32_t)databuffer + 0x800 * i), nand_ecc)) | ||
603 | { | ||
604 | rc |= 1 << i; | ||
605 | continue; | ||
606 | } | ||
607 | memcpy((void*)((uint32_t)sparebuffer + 0x40 * i + 0xC), nand_ecc, 0x28); | ||
608 | memset(nand_ctrl, 0xFF, 0x200); | ||
609 | memcpy(nand_ctrl, (void*)((uint32_t)sparebuffer + 0x40 * i), 0xC); | ||
610 | if (ecc_encode(0, nand_ctrl, nand_ecc)) | ||
611 | { | ||
612 | rc |= 1 << i; | ||
613 | continue; | ||
614 | } | ||
615 | memcpy((void*)((uint32_t)sparebuffer + 0x40 * i + 0x34), nand_ecc, 0xC); | ||
616 | nand_set_fmctrl0(i, FMCTRL0_ENABLEDMA); | ||
617 | if (nand_send_cmd(NAND_CMD_PROGRAM)) | ||
618 | { | ||
619 | rc |= 1 << i; | ||
620 | continue; | ||
621 | } | ||
622 | if (nand_send_address(page, databuffer ? 0 : 0x800)) | ||
623 | { | ||
624 | rc |= 1 << i; | ||
625 | continue; | ||
626 | } | ||
627 | if (nand_transfer_data(i, 1, (void*)((uint32_t)databuffer | ||
628 | + 0x800 * i), 0x800)) | ||
629 | { | ||
630 | rc |= 1 << i; | ||
631 | continue; | ||
632 | } | ||
633 | if (nand_transfer_data(i, 1, (void*)((uint32_t)sparebuffer | ||
634 | + 0x40 * i), 0x40)) | ||
635 | { | ||
636 | rc |= 1 << i; | ||
637 | continue; | ||
638 | } | ||
639 | if (nand_send_cmd(NAND_CMD_PROGCNFRM)) | ||
640 | { | ||
641 | rc |= 1 << i; | ||
642 | continue; | ||
643 | } | ||
644 | } | ||
645 | for (i = 0; i < 4; i++) | ||
646 | { | ||
647 | if (nand_type[i] == 0xFFFFFFFF) continue; | ||
648 | rc |= nand_wait_status_ready(i) << i; | ||
649 | } | ||
650 | return nand_unlock(rc); | ||
651 | } | ||
652 | |||
653 | uint32_t nand_block_erase_fast(uint32_t page) | ||
654 | { | ||
655 | uint32_t i, rc = 0; | ||
656 | mutex_lock(&nand_mtx); | ||
657 | nand_last_activity_value = current_tick; | ||
658 | led(true); | ||
659 | if (!nand_powered) nand_power_up(); | ||
660 | for (i = 0; i < 4; i++) | ||
661 | { | ||
662 | if (nand_type[i] == 0xFFFFFFFF) continue; | ||
663 | nand_set_fmctrl0(i, 0); | ||
664 | if (nand_send_cmd(NAND_CMD_BLOCKERASE)) | ||
665 | { | ||
666 | rc |= 1 << i; | ||
667 | continue; | ||
668 | } | ||
669 | FMANUM = 2; | ||
670 | FMADDR0 = page; | ||
671 | FMCTRL1 = FMCTRL1_DOTRANSADDR; | ||
672 | if (nand_wait_cmddone()) | ||
673 | { | ||
674 | rc |= 1 << i; | ||
675 | continue; | ||
676 | } | ||
677 | if (nand_send_cmd(NAND_CMD_ERASECNFRM)) rc |= 1 << i; | ||
678 | } | ||
679 | for (i = 0; i < 4; i++) | ||
680 | { | ||
681 | if (nand_type[i] == 0xFFFFFFFF) continue; | ||
682 | if (rc & (1 << i)) continue; | ||
683 | if (nand_wait_status_ready(i)) rc |= 1 << i; | ||
684 | } | ||
685 | return nand_unlock(rc); | ||
686 | } | ||
687 | |||
490 | const struct nand_device_info_type* nand_get_device_type(uint32_t bank) | 688 | const struct nand_device_info_type* nand_get_device_type(uint32_t bank) |
491 | { | 689 | { |
492 | if (nand_type[bank] == 0xFFFFFFFF) | 690 | if (nand_type[bank] == 0xFFFFFFFF) |