diff options
-rw-r--r-- | firmware/target/arm/ata-nand-telechips.c | 415 |
1 files changed, 212 insertions, 203 deletions
diff --git a/firmware/target/arm/ata-nand-telechips.c b/firmware/target/arm/ata-nand-telechips.c index a6a901d222..60d2211977 100644 --- a/firmware/target/arm/ata-nand-telechips.c +++ b/firmware/target/arm/ata-nand-telechips.c | |||
@@ -25,18 +25,11 @@ | |||
25 | #include "led.h" | 25 | #include "led.h" |
26 | #include "panic.h" | 26 | #include "panic.h" |
27 | #include "nand_id.h" | 27 | #include "nand_id.h" |
28 | |||
29 | /* The NAND driver is currently work-in-progress and as such contains | ||
30 | some dead code and debug stuff, such as the next few lines. */ | ||
31 | #include "lcd.h" | ||
32 | #include "font.h" | ||
33 | #include "button.h" | ||
34 | #include "storage.h" | 28 | #include "storage.h" |
35 | #include <sprintf.h> | 29 | #include "buffer.h" |
36 | 30 | ||
37 | #define SECTOR_SIZE 512 | 31 | #define SECTOR_SIZE 512 |
38 | 32 | ||
39 | /* #define USE_TCC_LPT */ | ||
40 | /* #define USE_ECC_CORRECTION */ | 33 | /* #define USE_ECC_CORRECTION */ |
41 | 34 | ||
42 | /* for compatibility */ | 35 | /* for compatibility */ |
@@ -50,31 +43,41 @@ static bool initialized = false; | |||
50 | static struct mutex ata_mtx SHAREDBSS_ATTR; | 43 | static struct mutex ata_mtx SHAREDBSS_ATTR; |
51 | 44 | ||
52 | #if defined(COWON_D2) || defined(IAUDIO_7) | 45 | #if defined(COWON_D2) || defined(IAUDIO_7) |
53 | #define SEGMENT_ID_BIGENDIAN | 46 | #define FTL_V2 |
54 | #define BLOCKS_PER_SEGMENT 4 | 47 | #define BLOCKS_PER_SEGMENT 4 |
48 | #define MAX_WRITE_CACHES 8 | ||
55 | #else | 49 | #else |
50 | #define FTL_V1 | ||
56 | #define BLOCKS_PER_SEGMENT 1 | 51 | #define BLOCKS_PER_SEGMENT 1 |
52 | #define MAX_WRITE_CACHES 4 | ||
57 | #endif | 53 | #endif |
58 | /* NB: blocks_per_segment should become a runtime check based on NAND id */ | ||
59 | 54 | ||
60 | /* Segment type identifiers - main data area */ | 55 | /* Sector type identifiers - main data area */ |
61 | #define SEGMENT_MAIN_LPT 0x12 | 56 | |
62 | #define SEGMENT_MAIN_DATA1 0x13 | 57 | #define SECTYPE_MAIN_LPT 0x12 |
63 | #define SEGMENT_MAIN_CACHE 0x15 | 58 | #define SECTYPE_MAIN_DATA 0x13 |
64 | #define SEGMENT_MAIN_DATA2 0x17 | 59 | #define SECTYPE_MAIN_RANDOM_CACHE 0x15 |
60 | #define SECTYPE_MAIN_INPLACE_CACHE 0x17 | ||
65 | 61 | ||
66 | /* We don't touch the hidden area at all - these are for reference */ | 62 | /* We don't touch the hidden area at all - these are for reference */ |
67 | #define SEGMENT_HIDDEN_LPT 0x22 | 63 | #define SECTYPE_HIDDEN_LPT 0x22 |
68 | #define SEGMENT_HIDDEN_DATA1 0x23 | 64 | #define SECTYPE_HIDDEN_DATA 0x23 |
69 | #define SEGMENT_HIDDEN_CACHE 0x25 | 65 | #define SECTYPE_HIDDEN_RANDOM_CACHE 0x25 |
70 | #define SEGMENT_HIDDEN_DATA2 0x27 | 66 | #define SECTYPE_HIDDEN_INPLACE_CACHE 0x27 |
67 | |||
68 | #ifdef FTL_V1 | ||
69 | #define SECTYPE_FIRMWARE 0x40 | ||
70 | #else | ||
71 | #define SECTYPE_FIRMWARE 0xE0 | ||
72 | #endif | ||
73 | |||
74 | /* Offsets to data within sector's spare area */ | ||
71 | 75 | ||
72 | /* Offsets to spare area data */ | ||
73 | #define OFF_CACHE_PAGE_LOBYTE 2 | 76 | #define OFF_CACHE_PAGE_LOBYTE 2 |
74 | #define OFF_CACHE_PAGE_HIBYTE 3 | 77 | #define OFF_CACHE_PAGE_HIBYTE 3 |
75 | #define OFF_SEGMENT_TYPE 4 | 78 | #define OFF_SECTOR_TYPE 4 |
76 | 79 | ||
77 | #ifdef SEGMENT_ID_BIGENDIAN | 80 | #ifdef FTL_V2 |
78 | #define OFF_LOG_SEG_LOBYTE 7 | 81 | #define OFF_LOG_SEG_LOBYTE 7 |
79 | #define OFF_LOG_SEG_HIBYTE 6 | 82 | #define OFF_LOG_SEG_HIBYTE 6 |
80 | #else | 83 | #else |
@@ -114,29 +117,29 @@ struct lpt_entry | |||
114 | short bank; | 117 | short bank; |
115 | short phys_segment; | 118 | short phys_segment; |
116 | }; | 119 | }; |
120 | #ifdef BOOTLOADER | ||
117 | static struct lpt_entry lpt_lookup[MAX_SEGMENTS]; | 121 | static struct lpt_entry lpt_lookup[MAX_SEGMENTS]; |
122 | #else | ||
123 | /* buffer_alloc'd in nand_init() when the correct size has been determined */ | ||
124 | static struct lpt_entry* lpt_lookup = NULL; | ||
125 | #endif | ||
118 | 126 | ||
119 | /* Write Caches */ | 127 | /* Write Caches */ |
120 | 128 | ||
121 | #define MAX_WRITE_CACHES 8 | ||
122 | |||
123 | struct write_cache | 129 | struct write_cache |
124 | { | 130 | { |
125 | short bank; | ||
126 | short phys_segment; | ||
127 | short log_segment; | 131 | short log_segment; |
132 | short inplace_bank; | ||
133 | short inplace_phys_segment; | ||
134 | short inplace_pages_used; | ||
135 | short random_bank; | ||
136 | short random_phys_segment; | ||
128 | short page_map[MAX_PAGES_PER_BLOCK * BLOCKS_PER_SEGMENT]; | 137 | short page_map[MAX_PAGES_PER_BLOCK * BLOCKS_PER_SEGMENT]; |
129 | }; | 138 | }; |
130 | static struct write_cache write_caches[MAX_WRITE_CACHES]; | 139 | static struct write_cache write_caches[MAX_WRITE_CACHES]; |
131 | 140 | ||
132 | static int write_caches_in_use = 0; | 141 | static int write_caches_in_use = 0; |
133 | 142 | ||
134 | #ifdef USE_TCC_LPT | ||
135 | /* Read buffer (used for reading LPT blocks only) */ | ||
136 | static unsigned char page_buf[MAX_PAGE_SIZE + MAX_SPARE_SIZE] | ||
137 | __attribute__ ((aligned (4))); | ||
138 | #endif | ||
139 | |||
140 | #ifdef USE_ECC_CORRECTION | 143 | #ifdef USE_ECC_CORRECTION |
141 | static unsigned int ecc_sectors_corrected = 0; | 144 | static unsigned int ecc_sectors_corrected = 0; |
142 | static unsigned int ecc_bits_corrected = 0; | 145 | static unsigned int ecc_bits_corrected = 0; |
@@ -501,18 +504,30 @@ static bool nand_read_sector_of_logical_segment(int log_segment, int sector, | |||
501 | 504 | ||
502 | while (!found && cache_num < write_caches_in_use) | 505 | while (!found && cache_num < write_caches_in_use) |
503 | { | 506 | { |
504 | if (write_caches[cache_num].log_segment == log_segment | 507 | if (write_caches[cache_num].log_segment == log_segment) |
505 | && write_caches[cache_num].page_map[page_in_segment] != -1) | ||
506 | { | ||
507 | found = true; | ||
508 | bank = write_caches[cache_num].bank; | ||
509 | phys_segment = write_caches[cache_num].phys_segment; | ||
510 | page_in_segment = write_caches[cache_num].page_map[page_in_segment]; | ||
511 | } | ||
512 | else | ||
513 | { | 508 | { |
514 | cache_num++; | 509 | if (write_caches[cache_num].page_map[page_in_segment] != -1) |
510 | { | ||
511 | /* data is located in random pages cache */ | ||
512 | found = true; | ||
513 | |||
514 | bank = write_caches[cache_num].random_bank; | ||
515 | phys_segment = write_caches[cache_num].random_phys_segment; | ||
516 | |||
517 | page_in_segment = | ||
518 | write_caches[cache_num].page_map[page_in_segment]; | ||
519 | } | ||
520 | else if (write_caches[cache_num].inplace_pages_used != -1 && | ||
521 | write_caches[cache_num].inplace_pages_used > page_in_segment) | ||
522 | { | ||
523 | /* data is located in in-place pages cache */ | ||
524 | found = true; | ||
525 | |||
526 | bank = write_caches[cache_num].inplace_bank; | ||
527 | phys_segment = write_caches[cache_num].inplace_phys_segment; | ||
528 | } | ||
515 | } | 529 | } |
530 | cache_num++; | ||
516 | } | 531 | } |
517 | 532 | ||
518 | return nand_read_sector_of_phys_segment(bank, phys_segment, | 533 | return nand_read_sector_of_phys_segment(bank, phys_segment, |
@@ -523,15 +538,21 @@ static bool nand_read_sector_of_logical_segment(int log_segment, int sector, | |||
523 | 538 | ||
524 | /* Miscellaneous helper functions */ | 539 | /* Miscellaneous helper functions */ |
525 | 540 | ||
526 | static inline char get_segment_type(char* spare_buf) | 541 | static inline unsigned char get_sector_type(char* spare_buf) |
527 | { | 542 | { |
528 | return spare_buf[OFF_SEGMENT_TYPE]; | 543 | return spare_buf[OFF_SECTOR_TYPE]; |
529 | } | 544 | } |
530 | 545 | ||
531 | static inline unsigned short get_log_segment_id(char* spare_buf) | 546 | static inline unsigned short get_log_segment_id(int phys_seg, char* spare_buf) |
532 | { | 547 | { |
533 | return (spare_buf[OFF_LOG_SEG_HIBYTE] << 8) | | 548 | (void)phys_seg; |
534 | spare_buf[OFF_LOG_SEG_LOBYTE]; | 549 | |
550 | return ((spare_buf[OFF_LOG_SEG_HIBYTE] << 8) | | ||
551 | spare_buf[OFF_LOG_SEG_LOBYTE]) | ||
552 | #if defined(FTL_V1) | ||
553 | + 984 * (phys_seg / 1024) | ||
554 | #endif | ||
555 | ; | ||
535 | } | 556 | } |
536 | 557 | ||
537 | static inline unsigned short get_cached_page_id(char* spare_buf) | 558 | static inline unsigned short get_cached_page_id(char* spare_buf) |
@@ -540,123 +561,123 @@ static inline unsigned short get_cached_page_id(char* spare_buf) | |||
540 | spare_buf[OFF_CACHE_PAGE_LOBYTE]; | 561 | spare_buf[OFF_CACHE_PAGE_LOBYTE]; |
541 | } | 562 | } |
542 | 563 | ||
564 | static int find_write_cache(int log_segment) | ||
565 | { | ||
566 | int i; | ||
543 | 567 | ||
568 | for (i = 0; i < write_caches_in_use; i++) | ||
569 | if (write_caches[i].log_segment == log_segment) | ||
570 | return i; | ||
544 | 571 | ||
545 | #ifdef USE_TCC_LPT | 572 | return -1; |
573 | } | ||
546 | 574 | ||
547 | /* Reading the LPT from NAND is not yet fully understood. This code is therefore | ||
548 | not enabled by default, as it gives much worse results than the bank-scanning | ||
549 | approach currently used. | ||
550 | |||
551 | The LPT is stored in a number of physical segments marked with type 0x12. | ||
552 | These are spread non-contiguously across the NAND, and are not stored in | ||
553 | sequential order. | ||
554 | |||
555 | The LPT data is stored in Sector 0 of the first <n> pages of each segment. | ||
556 | Each 32-bit value in sequence represents the physical location of a logical | ||
557 | segment. This is stored as (physical segment number * bank number). | ||
558 | |||
559 | NOTE: The bank numbers stored appear to be in reverse order to that required | ||
560 | by the nand_chip_select() function. The reason for this anomoly is unknown. | ||
561 | */ | ||
562 | 575 | ||
563 | static void read_lpt_block(int bank, int phys_segment) | 576 | static void read_random_writes_cache(int bank, int phys_segment) |
564 | { | 577 | { |
565 | int page = 1; /* table starts at page 1 of segment */ | 578 | int page = 0; |
566 | bool cont = true; | 579 | short log_segment; |
567 | 580 | unsigned char spare_buf[16]; | |
568 | struct lpt_entry* lpt_ptr = NULL; | ||
569 | |||
570 | while (cont && page < pages_per_block) | ||
571 | { | ||
572 | int i = 0; | ||
573 | unsigned int* int_buf = (int*)page_buf; | ||
574 | |||
575 | nand_read_sector_of_phys_segment(bank, phys_segment, | ||
576 | page, 0, /* only sector 0 is used */ | ||
577 | page_buf); | ||
578 | |||
579 | /* Find out which chunk of the LPT table this section contains. | ||
580 | Do this by reading the logical segment number of entry 0 */ | ||
581 | if (lpt_ptr == NULL) | ||
582 | { | ||
583 | int first_bank = int_buf[0] / segments_per_bank; | ||
584 | int first_phys_segment = int_buf[0] % segments_per_bank; | ||
585 | |||
586 | /* Reverse the stored bank number */ | ||
587 | if (total_banks > 1) | ||
588 | first_bank = (total_banks-1) - first_bank; | ||
589 | 581 | ||
590 | unsigned char spare_buf[16]; | 582 | nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, page), |
583 | SECTOR_SIZE, /* offset to first sector's spare */ | ||
584 | 16, spare_buf); | ||
591 | 585 | ||
592 | nand_read_raw(first_bank, | 586 | log_segment = get_log_segment_id(phys_segment, spare_buf); |
593 | phys_segment_to_page_addr(first_phys_segment, 0), | 587 | |
594 | SECTOR_SIZE, /* offset */ | 588 | if (log_segment == -1) |
595 | 16, spare_buf); | 589 | return; |
596 | 590 | ||
597 | int first_log_segment = get_log_segment_id(spare_buf); | 591 | /* Find which cache this is related to */ |
592 | int cache_no = find_write_cache(log_segment); | ||
598 | 593 | ||
599 | lpt_ptr = &lpt_lookup[first_log_segment]; | 594 | if (cache_no == -1) |
595 | { | ||
596 | if (write_caches_in_use < MAX_WRITE_CACHES) | ||
597 | { | ||
598 | cache_no = write_caches_in_use; | ||
599 | write_caches_in_use++; | ||
600 | } | 600 | } |
601 | 601 | else | |
602 | while (cont && (i < SECTOR_SIZE/4)) | ||
603 | { | 602 | { |
604 | if (int_buf[i] != 0xFFFFFFFF) | 603 | panicf("Max NAND write caches reached"); |
605 | { | ||
606 | int bank = int_buf[i] / segments_per_bank; | ||
607 | int phys_segment = int_buf[i] % segments_per_bank; | ||
608 | |||
609 | /* Reverse the stored bank number */ | ||
610 | if (total_banks > 1) | ||
611 | bank = (total_banks-1) - bank; | ||
612 | |||
613 | lpt_ptr->bank = bank; | ||
614 | lpt_ptr->phys_segment = phys_segment; | ||
615 | |||
616 | lpt_ptr++; | ||
617 | i++; | ||
618 | } | ||
619 | else cont = false; | ||
620 | } | 604 | } |
621 | page++; | ||
622 | } | 605 | } |
623 | } | ||
624 | |||
625 | #endif /* USE_TCC_LPT */ | ||
626 | 606 | ||
607 | write_caches[cache_no].log_segment = log_segment; | ||
608 | write_caches[cache_no].random_bank = bank; | ||
609 | write_caches[cache_no].random_phys_segment = phys_segment; | ||
627 | 610 | ||
628 | static void read_write_cache_segment(int bank, int phys_segment) | 611 | #ifndef FTL_V1 |
629 | { | ||
630 | int page; | ||
631 | unsigned char spare_buf[16]; | ||
632 | |||
633 | if (write_caches_in_use == MAX_WRITE_CACHES) | ||
634 | panicf("Max NAND write caches reached"); | ||
635 | |||
636 | write_caches[write_caches_in_use].bank = bank; | ||
637 | write_caches[write_caches_in_use].phys_segment = phys_segment; | ||
638 | |||
639 | /* Loop over each page in the phys segment (from page 1 onwards). | 612 | /* Loop over each page in the phys segment (from page 1 onwards). |
640 | Read spare for 1st sector, store location of page in array. */ | 613 | Read spare for 1st sector, store location of page in array. */ |
641 | for (page = 1; page < pages_per_block * BLOCKS_PER_SEGMENT; page++) | 614 | for (page = 1; page < pages_per_block * BLOCKS_PER_SEGMENT; page++) |
642 | { | 615 | { |
643 | unsigned short cached_page; | 616 | unsigned short cached_page; |
644 | unsigned short log_segment; | ||
645 | 617 | ||
646 | nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, page), | 618 | nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, page), |
647 | SECTOR_SIZE, /* offset to first sector's spare */ | 619 | SECTOR_SIZE, /* offset to first sector's spare */ |
648 | 16, spare_buf); | 620 | 16, spare_buf); |
649 | 621 | ||
650 | cached_page = get_cached_page_id(spare_buf); | 622 | cached_page = get_cached_page_id(spare_buf); |
651 | log_segment = get_log_segment_id(spare_buf); | 623 | |
652 | |||
653 | if (cached_page != 0xFFFF) | 624 | if (cached_page != 0xFFFF) |
625 | write_caches[cache_no].page_map[cached_page] = page; | ||
626 | } | ||
627 | #endif /* !FTL_V1 */ | ||
628 | } | ||
629 | |||
630 | |||
631 | static void read_inplace_writes_cache(int bank, int phys_segment) | ||
632 | { | ||
633 | int page = 0; | ||
634 | short log_segment; | ||
635 | unsigned char spare_buf[16]; | ||
636 | |||
637 | nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, page), | ||
638 | SECTOR_SIZE, /* offset to first sector's spare */ | ||
639 | 16, spare_buf); | ||
640 | |||
641 | log_segment = get_log_segment_id(phys_segment, spare_buf); | ||
642 | |||
643 | if (log_segment == -1) | ||
644 | return; | ||
645 | |||
646 | /* Find which cache this is related to */ | ||
647 | int cache_no = find_write_cache(log_segment); | ||
648 | |||
649 | if (cache_no == -1) | ||
650 | { | ||
651 | if (write_caches_in_use < MAX_WRITE_CACHES) | ||
652 | { | ||
653 | cache_no = write_caches_in_use; | ||
654 | write_caches_in_use++; | ||
655 | } | ||
656 | else | ||
654 | { | 657 | { |
655 | write_caches[write_caches_in_use].log_segment = log_segment; | 658 | panicf("Max NAND write caches reached"); |
656 | write_caches[write_caches_in_use].page_map[cached_page] = page; | ||
657 | } | 659 | } |
658 | } | 660 | } |
659 | write_caches_in_use++; | 661 | |
662 | write_caches[cache_no].log_segment = log_segment; | ||
663 | |||
664 | /* Find how many pages have been written to the new segment */ | ||
665 | while (log_segment != -1 && | ||
666 | page < (pages_per_block * BLOCKS_PER_SEGMENT) - 1) | ||
667 | { | ||
668 | page++; | ||
669 | nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, page), | ||
670 | SECTOR_SIZE, 16, spare_buf); | ||
671 | |||
672 | log_segment = get_log_segment_id(phys_segment, spare_buf); | ||
673 | } | ||
674 | |||
675 | if (page != 0) | ||
676 | { | ||
677 | write_caches[cache_no].inplace_bank = bank; | ||
678 | write_caches[cache_no].inplace_phys_segment = phys_segment; | ||
679 | write_caches[cache_no].inplace_pages_used = page; | ||
680 | } | ||
660 | } | 681 | } |
661 | 682 | ||
662 | 683 | ||
@@ -700,6 +721,7 @@ int nand_read_sectors(IF_MV2(int drive,) unsigned long start, int incount, | |||
700 | return 0; | 721 | return 0; |
701 | } | 722 | } |
702 | 723 | ||
724 | |||
703 | int nand_write_sectors(IF_MV2(int drive,) unsigned long start, int count, | 725 | int nand_write_sectors(IF_MV2(int drive,) unsigned long start, int count, |
704 | const void* outbuf) | 726 | const void* outbuf) |
705 | { | 727 | { |
@@ -714,6 +736,7 @@ int nand_write_sectors(IF_MV2(int drive,) unsigned long start, int count, | |||
714 | return -1; | 736 | return -1; |
715 | } | 737 | } |
716 | 738 | ||
739 | |||
717 | #ifdef STORAGE_GET_INFO | 740 | #ifdef STORAGE_GET_INFO |
718 | void nand_get_info(struct storage_info *info) | 741 | void nand_get_info(struct storage_info *info) |
719 | { | 742 | { |
@@ -724,15 +747,15 @@ void nand_get_info(struct storage_info *info) | |||
724 | info->product="Internal Storage"; | 747 | info->product="Internal Storage"; |
725 | 748 | ||
726 | /* blocks count */ | 749 | /* blocks count */ |
727 | info->num_sectors = (pages_per_block * blocks_per_bank / SECTOR_SIZE) | 750 | info->num_sectors = sectors_per_segment * segments_per_bank * total_banks; |
728 | * page_size * total_banks; | 751 | info->sector_size = SECTOR_SIZE; |
729 | info->sector_size=SECTOR_SIZE; | ||
730 | } | 752 | } |
731 | #endif | 753 | #endif |
732 | 754 | ||
755 | |||
733 | int nand_init(void) | 756 | int nand_init(void) |
734 | { | 757 | { |
735 | int i, bank, phys_segment; | 758 | int bank, phys_segment, lptbuf_size; |
736 | unsigned char spare_buf[16]; | 759 | unsigned char spare_buf[16]; |
737 | 760 | ||
738 | if (initialized) return 0; | 761 | if (initialized) return 0; |
@@ -750,28 +773,20 @@ int nand_init(void) | |||
750 | /* Get chip characteristics and number of banks */ | 773 | /* Get chip characteristics and number of banks */ |
751 | nand_get_chip_info(); | 774 | nand_get_chip_info(); |
752 | 775 | ||
753 | for (i = 0; i < MAX_SEGMENTS; i++) | 776 | #ifndef BOOTLOADER |
754 | { | 777 | /* Use chip info to allocate the correct size LPT buffer */ |
755 | lpt_lookup[i].bank = -1; | 778 | lptbuf_size = sizeof(struct lpt_entry) * segments_per_bank * total_banks; |
756 | lpt_lookup[i].phys_segment = -1; | 779 | lpt_lookup = buffer_alloc(lptbuf_size); |
757 | } | 780 | #else |
781 | /* Use a static array in the bootloader */ | ||
782 | lptbuf_size = sizeof(lpt_lookup); | ||
783 | #endif | ||
758 | 784 | ||
785 | memset(lpt_lookup, 0xff, lptbuf_size); | ||
786 | memset(write_caches, 0xff, sizeof(write_caches)); | ||
787 | |||
759 | write_caches_in_use = 0; | 788 | write_caches_in_use = 0; |
760 | 789 | ||
761 | for (i = 0; i < MAX_WRITE_CACHES; i++) | ||
762 | { | ||
763 | int page; | ||
764 | |||
765 | write_caches[i].log_segment = -1; | ||
766 | write_caches[i].bank = -1; | ||
767 | write_caches[i].phys_segment = -1; | ||
768 | |||
769 | for (page = 0; page < MAX_PAGES_PER_BLOCK * BLOCKS_PER_SEGMENT; page++) | ||
770 | { | ||
771 | write_caches[i].page_map[page] = -1; | ||
772 | } | ||
773 | } | ||
774 | |||
775 | /* Scan banks to build up block translation table */ | 790 | /* Scan banks to build up block translation table */ |
776 | for (bank = 0; bank < total_banks; bank++) | 791 | for (bank = 0; bank < total_banks; bank++) |
777 | { | 792 | { |
@@ -781,71 +796,65 @@ int nand_init(void) | |||
781 | nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, 0), | 796 | nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, 0), |
782 | SECTOR_SIZE, /* offset */ | 797 | SECTOR_SIZE, /* offset */ |
783 | 16, spare_buf); | 798 | 16, spare_buf); |
784 | 799 | ||
785 | switch (get_segment_type(spare_buf)) | 800 | int type = get_sector_type(spare_buf); |
801 | |||
802 | if (type == SECTYPE_MAIN_INPLACE_CACHE) | ||
786 | { | 803 | { |
787 | #ifdef USE_TCC_LPT | 804 | /* Check last sector of sequential write cache block */ |
788 | case SEGMENT_MAIN_LPT: | 805 | nand_read_raw(bank, |
806 | phys_segment_to_page_addr(phys_segment, | ||
807 | (pages_per_block * BLOCKS_PER_SEGMENT) - 1), | ||
808 | page_size + spare_size - 16, | ||
809 | 16, spare_buf); | ||
810 | |||
811 | /* If last sector has been written, treat block as main data */ | ||
812 | if (get_sector_type(spare_buf) != 0xff) | ||
789 | { | 813 | { |
790 | /* Log->Phys Translation table (for Main data area) */ | 814 | type = SECTYPE_MAIN_DATA; |
791 | read_lpt_block(bank, phys_segment); | ||
792 | break; | ||
793 | } | 815 | } |
794 | #else | 816 | } |
795 | case SEGMENT_MAIN_DATA2: | 817 | |
818 | switch (type) | ||
819 | { | ||
820 | case SECTYPE_MAIN_DATA: | ||
796 | { | 821 | { |
797 | /* Main data area segment */ | 822 | /* Main data area segment */ |
798 | unsigned short log_segment = get_log_segment_id(spare_buf); | 823 | unsigned short log_segment = |
824 | get_log_segment_id(phys_segment, spare_buf); | ||
799 | 825 | ||
800 | if (log_segment < MAX_SEGMENTS) | 826 | if (log_segment < segments_per_bank * total_banks) |
801 | { | 827 | { |
802 | lpt_lookup[log_segment].bank = bank; | 828 | if (lpt_lookup[log_segment].bank == -1 || |
803 | lpt_lookup[log_segment].phys_segment = phys_segment; | 829 | lpt_lookup[log_segment].phys_segment == -1) |
830 | { | ||
831 | lpt_lookup[log_segment].bank = bank; | ||
832 | lpt_lookup[log_segment].phys_segment = phys_segment; | ||
833 | } | ||
834 | else | ||
835 | { | ||
836 | //panicf("duplicate data segment 0x%x!", log_segment); | ||
837 | } | ||
804 | } | 838 | } |
805 | break; | 839 | break; |
806 | } | 840 | } |
807 | #endif | 841 | |
808 | 842 | case SECTYPE_MAIN_RANDOM_CACHE: | |
809 | case SEGMENT_MAIN_CACHE: | ||
810 | { | 843 | { |
811 | /* Recently-written page data (for Main data area) */ | 844 | /* Newly-written random page data (Main data area) */ |
812 | read_write_cache_segment(bank, phys_segment); | 845 | read_random_writes_cache(bank, phys_segment); |
813 | break; | 846 | break; |
814 | } | 847 | } |
815 | } | 848 | |
816 | } | 849 | case SECTYPE_MAIN_INPLACE_CACHE: |
817 | } | ||
818 | |||
819 | #ifndef USE_TCC_LPT | ||
820 | /* Scan banks a second time as 0x13 segments appear to override 0x17 */ | ||
821 | for (bank = 0; bank < total_banks; bank++) | ||
822 | { | ||
823 | for (phys_segment = 0; phys_segment < segments_per_bank; phys_segment++) | ||
824 | { | ||
825 | /* Read spare bytes from first sector of each segment */ | ||
826 | nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, 0), | ||
827 | SECTOR_SIZE, /* offset */ | ||
828 | 16, spare_buf); | ||
829 | |||
830 | switch (get_segment_type(spare_buf)) /* block type */ | ||
831 | { | ||
832 | case SEGMENT_MAIN_DATA1: | ||
833 | { | 850 | { |
834 | /* Main data area segment */ | 851 | /* Newly-written sequential page data (Main data area) */ |
835 | unsigned short log_segment = get_log_segment_id(spare_buf); | 852 | read_inplace_writes_cache(bank, phys_segment); |
836 | |||
837 | if (log_segment < MAX_SEGMENTS) | ||
838 | { | ||
839 | /* 0x13 seems to override 0x17, so store in our LPT */ | ||
840 | lpt_lookup[log_segment].bank = bank; | ||
841 | lpt_lookup[log_segment].phys_segment = phys_segment; | ||
842 | } | ||
843 | break; | 853 | break; |
844 | } | 854 | } |
845 | } | 855 | } |
846 | } | 856 | } |
847 | } | 857 | } |
848 | #endif | ||
849 | 858 | ||
850 | initialized = true; | 859 | initialized = true; |
851 | 860 | ||