summaryrefslogtreecommitdiff
path: root/firmware/target
diff options
context:
space:
mode:
authorMichael Sparmann <theseven@rockbox.org>2010-03-10 03:00:43 +0000
committerMichael Sparmann <theseven@rockbox.org>2010-03-10 03:00:43 +0000
commit287eff2149cb94b4121147fd86acd91c546558a3 (patch)
treee709df3ed2857534394dc1adf7874e69d9c1f16a /firmware/target
parent3710ae92cc1aa7e13095003635ea9ed6a6e419d6 (diff)
downloadrockbox-287eff2149cb94b4121147fd86acd91c546558a3.tar.gz
rockbox-287eff2149cb94b4121147fd86acd91c546558a3.zip
iPod Nano 2G FTL performance enhancements. Still not quite as fast as the OFW, but way better than before.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25099 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target')
-rw-r--r--firmware/target/arm/s5l8700/ipodnano2g/ftl-nano2g.c470
-rw-r--r--firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c204
-rw-r--r--firmware/target/arm/s5l8700/ipodnano2g/nand-target.h7
3 files changed, 555 insertions, 126 deletions
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/ftl-nano2g.c b/firmware/target/arm/s5l8700/ipodnano2g/ftl-nano2g.c
index 0cc7841cd5..b4cdaebf99 100644
--- a/firmware/target/arm/s5l8700/ipodnano2g/ftl-nano2g.c
+++ b/firmware/target/arm/s5l8700/ipodnano2g/ftl-nano2g.c
@@ -372,7 +372,7 @@ struct ftl_cxt_type ftl_cxt;
372uint8_t ftl_buffer[0x800] __attribute__((aligned(16))); 372uint8_t ftl_buffer[0x800] __attribute__((aligned(16)));
373 373
374/* Temporary spare byte buffer for internal use by the FTL */ 374/* Temporary spare byte buffer for internal use by the FTL */
375union ftl_spare_data_type ftl_sparebuffer __attribute__((aligned(16))); 375union ftl_spare_data_type ftl_sparebuffer[4] __attribute__((aligned(16)));
376 376
377 377
378#ifndef FTL_READONLY 378#ifndef FTL_READONLY
@@ -402,7 +402,8 @@ uint8_t ftl_erasectr_dirt[8];
402/* Buffer needed for copying pages around while moving or committing blocks. 402/* Buffer needed for copying pages around while moving or committing blocks.
403 This can't be shared with ftl_buffer, because this one could be overwritten 403 This can't be shared with ftl_buffer, because this one could be overwritten
404 during the copying operation in order to e.g. commit a CXT. */ 404 during the copying operation in order to e.g. commit a CXT. */
405uint8_t ftl_copybuffer[0x800] __attribute__((aligned(16))); 405uint8_t ftl_copybuffer[4][0x800] __attribute__((aligned(16)));
406union ftl_spare_data_type ftl_copyspare[4] __attribute__((aligned(16)));
406 407
407/* Needed to store the old scattered page offsets in order to be able to roll 408/* Needed to store the old scattered page offsets in order to be able to roll
408 back if something fails while compacting a scattered page block. */ 409 back if something fails while compacting a scattered page block. */
@@ -430,7 +431,7 @@ uint32_t ftl_find_devinfo(uint32_t bank)
430 { 431 {
431 pagenum = block * (*ftl_nand_type).pagesperblock + page; 432 pagenum = block * (*ftl_nand_type).pagesperblock + page;
432 if ((nand_read_page(bank, pagenum, ftl_buffer, 433 if ((nand_read_page(bank, pagenum, ftl_buffer,
433 &ftl_sparebuffer, 1, 0) & 0x11F) != 0) 434 &ftl_sparebuffer[0], 1, 0) & 0x11F) != 0)
434 continue; 435 continue;
435 if (memcmp(ftl_buffer, "DEVICEINFOSIGN\0", 0x10) == 0) 436 if (memcmp(ftl_buffer, "DEVICEINFOSIGN\0", 0x10) == 0)
436 return pagenum; 437 return pagenum;
@@ -534,34 +535,34 @@ uint32_t ftl_vfl_store_cxt(uint32_t bank)
534 ftl_vfl_cxt[bank].usn = ++ftl_vfl_usn; 535 ftl_vfl_cxt[bank].usn = ++ftl_vfl_usn;
535 ftl_vfl_cxt[bank].nextcxtpage += 8; 536 ftl_vfl_cxt[bank].nextcxtpage += 8;
536 ftl_vfl_update_checksum(bank); 537 ftl_vfl_update_checksum(bank);
537 memset(&ftl_sparebuffer, 0xFF, 0x40); 538 memset(&ftl_sparebuffer[0], 0xFF, 0x40);
538 ftl_sparebuffer.meta.usn = ftl_vfl_cxt[bank].updatecount; 539 ftl_sparebuffer[0].meta.usn = ftl_vfl_cxt[bank].updatecount;
539 ftl_sparebuffer.meta.field_8 = 0; 540 ftl_sparebuffer[0].meta.field_8 = 0;
540 ftl_sparebuffer.meta.type = 0x80; 541 ftl_sparebuffer[0].meta.type = 0x80;
541 for (i = 1; i <= 8; i++) 542 for (i = 1; i <= 8; i++)
542 { 543 {
543 uint32_t index = ftl_vfl_cxt[bank].activecxtblock; 544 uint32_t index = ftl_vfl_cxt[bank].activecxtblock;
544 uint32_t block = ftl_vfl_cxt[bank].vflcxtblocks[index]; 545 uint32_t block = ftl_vfl_cxt[bank].vflcxtblocks[index];
545 uint32_t page = block * (*ftl_nand_type).pagesperblock; 546 uint32_t page = block * (*ftl_nand_type).pagesperblock;
546 page += ftl_vfl_cxt[bank].nextcxtpage - i; 547 page += ftl_vfl_cxt[bank].nextcxtpage - i;
547 nand_write_page(bank, page, &ftl_vfl_cxt[bank], &ftl_sparebuffer, 1); 548 nand_write_page(bank, page, &ftl_vfl_cxt[bank], &ftl_sparebuffer[0], 1);
548 } 549 }
549 uint32_t good = 0; 550 uint32_t good = 0;
550 for (i = 0; i < 8; i++) 551 for (i = 1; i <= 8; i++)
551 { 552 {
552 uint32_t index = ftl_vfl_cxt[bank].activecxtblock; 553 uint32_t index = ftl_vfl_cxt[bank].activecxtblock;
553 uint32_t block = ftl_vfl_cxt[bank].vflcxtblocks[index]; 554 uint32_t block = ftl_vfl_cxt[bank].vflcxtblocks[index];
554 uint32_t page = block * (*ftl_nand_type).pagesperblock; 555 uint32_t page = block * (*ftl_nand_type).pagesperblock;
555 page += ftl_vfl_cxt[bank].nextcxtpage - i; 556 page += ftl_vfl_cxt[bank].nextcxtpage - i;
556 if ((nand_read_page(bank, page, ftl_buffer, 557 if ((nand_read_page(bank, page, ftl_buffer,
557 &ftl_sparebuffer, 1, 0) & 0x11F) != 0) 558 &ftl_sparebuffer[0], 1, 0) & 0x11F) != 0)
558 continue; 559 continue;
559 if (memcmp(ftl_buffer, &ftl_vfl_cxt[bank], 0x7AC) != 0) 560 if (memcmp(ftl_buffer, &ftl_vfl_cxt[bank], 0x7AC) != 0)
560 continue; 561 continue;
561 if (ftl_sparebuffer.meta.usn != ftl_vfl_cxt[bank].updatecount) 562 if (ftl_sparebuffer[0].meta.usn != ftl_vfl_cxt[bank].updatecount)
562 continue; 563 continue;
563 if (ftl_sparebuffer.meta.field_8 == 0 564 if (ftl_sparebuffer[0].meta.field_8 == 0
564 && ftl_sparebuffer.meta.type == 0x80) good++; 565 && ftl_sparebuffer[0].meta.type == 0x80) good++;
565 } 566 }
566 return good > 3 ? 0 : 1; 567 return good > 3 ? 0 : 1;
567} 568}
@@ -847,6 +848,72 @@ uint32_t ftl_vfl_read(uint32_t vpage, void* buffer, void* sparebuffer,
847} 848}
848 849
849 850
851/* Multi-bank version of ftl_vfl_read, will read ftl_banks pages in parallel */
852uint32_t ftl_vfl_read_fast(uint32_t vpage, void* buffer, void* sparebuffer,
853 uint32_t checkempty, uint32_t remaponfail)
854{
855 uint32_t i, rc = 0;
856 uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks;
857 uint32_t syshyperblocks = (*ftl_nand_type).blocks
858 - (*ftl_nand_type).userblocks - 0x17;
859 uint32_t abspage = vpage + ppb * syshyperblocks;
860 if (abspage + ftl_banks - 1 >= (*ftl_nand_type).blocks * ppb || abspage < ppb)
861 panicf("FTL: Trying to read out-of-bounds vPage %u", (unsigned)vpage);
862 //return 4;
863
864 uint32_t bank = abspage % ftl_banks;
865 uint32_t block = abspage / ((*ftl_nand_type).pagesperblock * ftl_banks);
866 uint32_t page = (abspage / ftl_banks) % (*ftl_nand_type).pagesperblock;
867 if (bank)
868 {
869 for (i = 0; i < ftl_banks; i++)
870 {
871 void* databuf = (void*)0;
872 void* sparebuf = (void*)0;
873 if (buffer) databuf = (void*)((uint32_t)buffer + 0x800 * i);
874 if (sparebuffer) sparebuf = (void*)((uint32_t)sparebuffer + 0x40 * i);
875 uint32_t ret = ftl_vfl_read(vpage + i, databuf, sparebuf, checkempty, remaponfail);
876 if (ret & 1) rc |= 1 << (i << 2);
877 if (ret & 2) rc |= 2 << (i << 2);
878 if (ret & 0x10) rc |= 4 << (i << 2);
879 if (ret & 0x100) rc |= 8 << (i << 2);
880 }
881 return rc;
882 }
883 uint32_t physblock = ftl_vfl_get_physical_block(bank, block);
884 uint32_t physpage = physblock * (*ftl_nand_type).pagesperblock + page;
885
886 rc = nand_read_page_fast(physpage, buffer, sparebuffer, 1, checkempty);
887 if (!(rc & 0xdddd)) return rc;
888
889 for (i = 0; i < ftl_banks; i++)
890 {
891 if ((rc >> (i << 2)) & 0x2) continue;
892 if ((rc >> (i << 2)) & 0xf)
893 {
894 rc &= ~(0xf << (i << 2));
895 nand_reset(i);
896 uint32_t ret = nand_read_page(i, physpage,
897 (void*)((uint32_t)buffer + 0x800 * i),
898 (void*)((uint32_t)sparebuffer + 0x40 * i),
899 1, checkempty);
900#ifdef FTL_READONLY
901 (void)remaponfail;
902#else
903 if (remaponfail == 1 && (ret & 0x11D) != 0 && (ret & 2) == 0)
904 ftl_vfl_schedule_block_for_remap(i, block);
905#endif
906 if (ret & 1) rc |= 1 << (i << 2);
907 if (ret & 2) rc |= 2 << (i << 2);
908 if (ret & 0x10) rc |= 4 << (i << 2);
909 if (ret & 0x100) rc |= 8 << (i << 2);
910 }
911 }
912
913 return rc;
914}
915
916
850#ifndef FTL_READONLY 917#ifndef FTL_READONLY
851/* Writes the specified vPage, dealing with all kinds of trouble */ 918/* Writes the specified vPage, dealing with all kinds of trouble */
852uint32_t ftl_vfl_write(uint32_t vpage, void* buffer, void* sparebuffer) 919uint32_t ftl_vfl_write(uint32_t vpage, void* buffer, void* sparebuffer)
@@ -870,7 +937,7 @@ uint32_t ftl_vfl_write(uint32_t vpage, void* buffer, void* sparebuffer)
870 return 0; 937 return 0;
871 938
872 if ((nand_read_page(bank, physpage, ftl_buffer, 939 if ((nand_read_page(bank, physpage, ftl_buffer,
873 &ftl_sparebuffer, 1, 1) & 0x11F) == 0) 940 &ftl_sparebuffer[0], 1, 1) & 0x11F) == 0)
874 return 0; 941 return 0;
875 942
876 panicf("FTL: write error on vPage %u, bank %u, pPage %u", 943 panicf("FTL: write error on vPage %u, bank %u, pPage %u",
@@ -881,6 +948,57 @@ uint32_t ftl_vfl_write(uint32_t vpage, void* buffer, void* sparebuffer)
881#endif 948#endif
882 949
883 950
951#ifndef FTL_READONLY
952/* Multi-bank version of ftl_vfl_write, will write ftl_banks pages in parallel */
953uint32_t ftl_vfl_write_fast(uint32_t vpage, void* buffer, void* sparebuffer)
954{
955 uint32_t i, rc = 0;
956 uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks;
957 uint32_t syshyperblocks = (*ftl_nand_type).blocks
958 - (*ftl_nand_type).userblocks - 0x17;
959 uint32_t abspage = vpage + ppb * syshyperblocks;
960 if (abspage + ftl_banks - 1 >= (*ftl_nand_type).blocks * ppb || abspage < ppb)
961 panicf("FTL: Trying to write out-of-bounds vPage %u",
962 (unsigned)vpage);
963 //return 4;
964
965 uint32_t bank = abspage % ftl_banks;
966 uint32_t block = abspage / ((*ftl_nand_type).pagesperblock * ftl_banks);
967 uint32_t page = (abspage / ftl_banks) % (*ftl_nand_type).pagesperblock;
968 if (bank)
969 {
970 for (i = 0; i < ftl_banks; i++)
971 {
972 void* databuf = (void*)0;
973 void* sparebuf = (void*)0;
974 if (buffer) databuf = (void*)((uint32_t)buffer + 0x800 * i);
975 if (sparebuffer) sparebuf = (void*)((uint32_t)sparebuffer + 0x40 * i);
976 rc |= ftl_vfl_write(vpage + i, databuf, sparebuf) << i;
977 }
978 return rc;
979 }
980 uint32_t physblock = ftl_vfl_get_physical_block(bank, block);
981 uint32_t physpage = physblock * (*ftl_nand_type).pagesperblock + page;
982
983 rc = nand_write_page_fast(physpage, buffer, sparebuffer, 1);
984 if (!rc) return 0;
985
986 for (i = 0; i < ftl_banks; i++)
987 if (rc & (1 << i))
988 {
989 if (!(nand_read_page(i, physpage, ftl_buffer,
990 &ftl_sparebuffer[i], 1, 1) & 0x11F))
991 rc &= ~(1 << i);
992
993 panicf("FTL: write error on vPage %u, bank %u, pPage %u",
994 (unsigned)(vpage + i), (unsigned)i, (unsigned)physpage);
995 ftl_vfl_log_trouble(i, block);
996 }
997 return rc;
998}
999#endif
1000
1001
884/* Mounts the VFL on all banks */ 1002/* Mounts the VFL on all banks */
885uint32_t ftl_vfl_open(void) 1003uint32_t ftl_vfl_open(void)
886{ 1004{
@@ -913,7 +1031,7 @@ uint32_t ftl_vfl_open(void)
913 if (ftl_is_good_block(bbt, j) != 0) 1031 if (ftl_is_good_block(bbt, j) != 0)
914#endif 1032#endif
915 if (ftl_vfl_read_page(i, j, 0, ftl_buffer, 1033 if (ftl_vfl_read_page(i, j, 0, ftl_buffer,
916 &ftl_sparebuffer) == 0) 1034 &ftl_sparebuffer[0]) == 0)
917 { 1035 {
918 struct ftl_vfl_cxt_type* cxt; 1036 struct ftl_vfl_cxt_type* cxt;
919 cxt = (struct ftl_vfl_cxt_type*)ftl_buffer; 1037 cxt = (struct ftl_vfl_cxt_type*)ftl_buffer;
@@ -924,11 +1042,11 @@ uint32_t ftl_vfl_open(void)
924 if (vflcxtblock[k] != 0xFFFF) 1042 if (vflcxtblock[k] != 0xFFFF)
925 if (ftl_vfl_read_page(i, vflcxtblock[k], 0, 1043 if (ftl_vfl_read_page(i, vflcxtblock[k], 0,
926 ftl_buffer, 1044 ftl_buffer,
927 &ftl_sparebuffer) == 0) 1045 &ftl_sparebuffer[0]) == 0)
928 if (ftl_sparebuffer.meta.usn > 0 1046 if (ftl_sparebuffer[0].meta.usn > 0
929 && ftl_sparebuffer.meta.usn <= minusn) 1047 && ftl_sparebuffer[0].meta.usn <= minusn)
930 { 1048 {
931 minusn = ftl_sparebuffer.meta.usn; 1049 minusn = ftl_sparebuffer[0].meta.usn;
932 vflcxtidx = k; 1050 vflcxtidx = k;
933 } 1051 }
934 if (vflcxtidx == 4) //return 1; 1052 if (vflcxtidx == 4) //return 1;
@@ -940,13 +1058,13 @@ uint32_t ftl_vfl_open(void)
940 { 1058 {
941 if (ftl_vfl_read_page(i, vflcxtblock[vflcxtidx], 1059 if (ftl_vfl_read_page(i, vflcxtblock[vflcxtidx],
942 k, ftl_buffer, 1060 k, ftl_buffer,
943 &ftl_sparebuffer) != 0) 1061 &ftl_sparebuffer[0]) != 0)
944 break; 1062 break;
945 last = k; 1063 last = k;
946 } 1064 }
947 if (ftl_vfl_read_page(i, vflcxtblock[vflcxtidx], 1065 if (ftl_vfl_read_page(i, vflcxtblock[vflcxtidx],
948 last, ftl_buffer, 1066 last, ftl_buffer,
949 &ftl_sparebuffer) != 0) 1067 &ftl_sparebuffer[0]) != 0)
950 panicf("FTL: Re-reading VFL CXT block " 1068 panicf("FTL: Re-reading VFL CXT block "
951 "on bank %u failed!?", (unsigned)i); 1069 "on bank %u failed!?", (unsigned)i);
952 //return 1; 1070 //return 1;
@@ -981,12 +1099,12 @@ uint32_t ftl_open(void)
981 for (i = 0; i < 3; i++) 1099 for (i = 0; i < 3; i++)
982 { 1100 {
983 ret = ftl_vfl_read(ppb * (*cxt).ftlctrlblocks[i], 1101 ret = ftl_vfl_read(ppb * (*cxt).ftlctrlblocks[i],
984 ftl_buffer, &ftl_sparebuffer, 1, 0); 1102 ftl_buffer, &ftl_sparebuffer[0], 1, 0);
985 if ((ret &= 0x11F) != 0) continue; 1103 if ((ret &= 0x11F) != 0) continue;
986 if (ftl_sparebuffer.meta.type - 0x43 > 4) continue; 1104 if (ftl_sparebuffer[0].meta.type - 0x43 > 4) continue;
987 if (ftlcxtblock != 0xffffffff && ftl_sparebuffer.meta.usn >= minusn) 1105 if (ftlcxtblock != 0xffffffff && ftl_sparebuffer[0].meta.usn >= minusn)
988 continue; 1106 continue;
989 minusn = ftl_sparebuffer.meta.usn; 1107 minusn = ftl_sparebuffer[0].meta.usn;
990 ftlcxtblock = (*cxt).ftlctrlblocks[i]; 1108 ftlcxtblock = (*cxt).ftlctrlblocks[i];
991 } 1109 }
992 1110
@@ -997,9 +1115,9 @@ uint32_t ftl_open(void)
997 for (i = (*ftl_nand_type).pagesperblock * ftl_banks - 1; i > 0; i--) 1115 for (i = (*ftl_nand_type).pagesperblock * ftl_banks - 1; i > 0; i--)
998 { 1116 {
999 ret = ftl_vfl_read(ppb * ftlcxtblock + i, 1117 ret = ftl_vfl_read(ppb * ftlcxtblock + i,
1000 ftl_buffer, &ftl_sparebuffer, 1, 0); 1118 ftl_buffer, &ftl_sparebuffer[0], 1, 0);
1001 if ((ret & 0x11F) != 0) continue; 1119 if ((ret & 0x11F) != 0) continue;
1002 else if (ftl_sparebuffer.meta.type == 0x43) 1120 else if (ftl_sparebuffer[0].meta.type == 0x43)
1003 { 1121 {
1004 memcpy(&ftl_cxt, ftl_buffer, 0x28C); 1122 memcpy(&ftl_cxt, ftl_buffer, 0x28C);
1005 ftlcxtfound = 1; 1123 ftlcxtfound = 1;
@@ -1024,7 +1142,7 @@ uint32_t ftl_open(void)
1024 for (i = 0; i < pagestoread; i++) 1142 for (i = 0; i < pagestoread; i++)
1025 { 1143 {
1026 if ((ftl_vfl_read(ftl_cxt.ftl_map_pages[i], 1144 if ((ftl_vfl_read(ftl_cxt.ftl_map_pages[i],
1027 ftl_buffer, &ftl_sparebuffer, 1, 1) & 0x11F) != 0) 1145 ftl_buffer, &ftl_sparebuffer[0], 1, 1) & 0x11F) != 0)
1028 panicf("FTL: Failed to read block map page %u", (unsigned)i); 1146 panicf("FTL: Failed to read block map page %u", (unsigned)i);
1029 //return 1; 1147 //return 1;
1030 1148
@@ -1042,7 +1160,7 @@ uint32_t ftl_open(void)
1042 for (i = 0; i < pagestoread; i++) 1160 for (i = 0; i < pagestoread; i++)
1043 { 1161 {
1044 if ((ftl_vfl_read(ftl_cxt.ftl_erasectr_pages[i], 1162 if ((ftl_vfl_read(ftl_cxt.ftl_erasectr_pages[i],
1045 ftl_buffer, &ftl_sparebuffer, 1, 1) & 0x11F) != 0) 1163 ftl_buffer, &ftl_sparebuffer[0], 1, 1) & 0x11F) != 0)
1046 panicf("FTL: Failed to read erase counter page %u", (unsigned)i); 1164 panicf("FTL: Failed to read erase counter page %u", (unsigned)i);
1047 //return 1; 1165 //return 1;
1048 1166
@@ -1086,7 +1204,7 @@ struct ftl_log_type* ftl_get_log_entry(uint32_t block)
1086/* Exposed function: Read highlevel sectors */ 1204/* Exposed function: Read highlevel sectors */
1087uint32_t ftl_read(uint32_t sector, uint32_t count, void* buffer) 1205uint32_t ftl_read(uint32_t sector, uint32_t count, void* buffer)
1088{ 1206{
1089 uint32_t i; 1207 uint32_t i, j;
1090 uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; 1208 uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks;
1091 uint32_t error = 0; 1209 uint32_t error = 0;
1092 1210
@@ -1112,13 +1230,31 @@ uint32_t ftl_read(uint32_t sector, uint32_t count, void* buffer)
1112 + (*logentry).pageoffsets[page]; 1230 + (*logentry).pageoffsets[page];
1113#endif 1231#endif
1114 1232
1115 uint32_t ret = ftl_vfl_read(abspage, &((uint8_t*)buffer)[i << 11], 1233 if (count >= i + ftl_banks && !(page & (ftl_banks - 1))
1116 &ftl_sparebuffer, 1, 1); 1234 && logentry == (struct ftl_log_type*)0)
1117 if ((ret & 2) != 0) memset(&((uint8_t*)buffer)[i << 11], 0, 0x800);
1118 else if ((ret & 0x11D) != 0 || ftl_sparebuffer.user.eccmark != 0xFF)
1119 { 1235 {
1120 error = 1; 1236 uint32_t ret = ftl_vfl_read_fast(abspage, &((uint8_t*)buffer)[i << 11],
1121 memset(&((uint8_t*)buffer)[i << 11], 0, 0x800); 1237 &ftl_sparebuffer[0], 1, 1);
1238 for (j = 0; j < ftl_banks; j++)
1239 if (ret & (2 << (j << 2)))
1240 memset(&((uint8_t*)buffer)[(i + j) << 11], 0, 0x800);
1241 else if ((ret & (0xd << (j << 2))) || ftl_sparebuffer[j].user.eccmark != 0xFF)
1242 {
1243 error = 1;
1244 memset(&((uint8_t*)buffer)[(i + j) << 11], 0, 0x800);
1245 }
1246 i += ftl_banks - 1;
1247 }
1248 else
1249 {
1250 uint32_t ret = ftl_vfl_read(abspage, &((uint8_t*)buffer)[i << 11],
1251 &ftl_sparebuffer[0], 1, 1);
1252 if (ret & 2) memset(&((uint8_t*)buffer)[i << 11], 0, 0x800);
1253 else if ((ret & 0x11D) != 0 || ftl_sparebuffer[0].user.eccmark != 0xFF)
1254 {
1255 error = 1;
1256 memset(&((uint8_t*)buffer)[i << 11], 0, 0x800);
1257 }
1122 } 1258 }
1123 } 1259 }
1124 1260
@@ -1137,6 +1273,8 @@ uint32_t ftl_erase_block_internal(uint32_t block)
1137 block = block + (*ftl_nand_type).blocks 1273 block = block + (*ftl_nand_type).blocks
1138 - (*ftl_nand_type).userblocks - 0x17; 1274 - (*ftl_nand_type).userblocks - 0x17;
1139 if (block == 0 || block >= (*ftl_nand_type).blocks) return 1; 1275 if (block == 0 || block >= (*ftl_nand_type).blocks) return 1;
1276 uint32_t pblock[4];
1277 uint32_t differs = 0;
1140 for (i = 0; i < ftl_banks; i++) 1278 for (i = 0; i < ftl_banks; i++)
1141 { 1279 {
1142 if (ftl_vfl_check_remap_scheduled(i, block) == 1) 1280 if (ftl_vfl_check_remap_scheduled(i, block) == 1)
@@ -1145,29 +1283,38 @@ uint32_t ftl_erase_block_internal(uint32_t block)
1145 ftl_vfl_mark_remap_done(i, block); 1283 ftl_vfl_mark_remap_done(i, block);
1146 } 1284 }
1147 ftl_vfl_log_success(i, block); 1285 ftl_vfl_log_success(i, block);
1148 uint32_t pblock = ftl_vfl_get_physical_block(i, block); 1286 pblock[i] = ftl_vfl_get_physical_block(i, block);
1149 uint32_t rc; 1287 if (pblock[i] != pblock[0]) differs = 1;
1150 for (j = 0; j < 3; j++) 1288 }
1151 { 1289 uint32_t res = 0xf;
1152 rc = nand_block_erase(i, pblock * (*ftl_nand_type).pagesperblock); 1290 if (!differs)
1153 if (rc == 0) break; 1291 res = nand_block_erase_fast(pblock[0] * (*ftl_nand_type).pagesperblock);
1154 } 1292 if (!res) return 0;
1155 if (rc != 0) 1293 for (i = 0; i < ftl_banks; i++)
1294 if (res & (1 << i))
1156 { 1295 {
1157 panicf("FTL: Block erase failed on bank %u block %u", 1296 uint32_t rc;
1158 (unsigned)i, (unsigned)block); 1297 for (j = 0; j < 3; j++)
1159 if (pblock != block)
1160 { 1298 {
1161 uint32_t spareindex = pblock - ftl_vfl_cxt[i].firstspare; 1299 rc = nand_block_erase(i, pblock[i] * (*ftl_nand_type).pagesperblock);
1162 ftl_vfl_cxt[i].remaptable[spareindex] = 0xFFFF; 1300 if (rc == 0) break;
1301 }
1302 if (rc != 0)
1303 {
1304 panicf("FTL: Block erase failed on bank %u block %u",
1305 (unsigned)i, (unsigned)block);
1306 if (pblock[i] != block)
1307 {
1308 uint32_t spareindex = pblock[i] - ftl_vfl_cxt[i].firstspare;
1309 ftl_vfl_cxt[i].remaptable[spareindex] = 0xFFFF;
1310 }
1311 ftl_vfl_cxt[i].field_18++;
1312 if (ftl_vfl_remap_block(i, block) == 0) return 1;
1313 if (ftl_vfl_commit_cxt(i) != 0) return 1;
1314 memset(&ftl_sparebuffer[i], 0, 0x40);
1315 nand_write_page(i, pblock[i], &ftl_vfl_cxt[0], &ftl_sparebuffer[i], 1);
1163 } 1316 }
1164 ftl_vfl_cxt[i].field_18++;
1165 if (ftl_vfl_remap_block(i, block) == 0) return 1;
1166 if (ftl_vfl_commit_cxt(i) != 0) return 1;
1167 memset(&ftl_sparebuffer, 0, 0x40);
1168 nand_write_page(i, pblock, &ftl_vfl_cxt[0], &ftl_sparebuffer, 1);
1169 } 1317 }
1170 }
1171 return 0; 1318 return 0;
1172} 1319}
1173#endif 1320#endif
@@ -1251,20 +1398,20 @@ uint32_t ftl_store_ctrl_block_list(void)
1251 because it is too dirty or needs to be moved. */ 1398 because it is too dirty or needs to be moved. */
1252uint32_t ftl_save_erasectr_page(uint32_t index) 1399uint32_t ftl_save_erasectr_page(uint32_t index)
1253{ 1400{
1254 memset(&ftl_sparebuffer, 0xFF, 0x40); 1401 memset(&ftl_sparebuffer[0], 0xFF, 0x40);
1255 ftl_sparebuffer.meta.usn = ftl_cxt.usn; 1402 ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
1256 ftl_sparebuffer.meta.idx = index; 1403 ftl_sparebuffer[0].meta.idx = index;
1257 ftl_sparebuffer.meta.type = 0x46; 1404 ftl_sparebuffer[0].meta.type = 0x46;
1258 if (ftl_vfl_write(ftl_cxt.ftlctrlpage, &ftl_erasectr[index << 10], 1405 if (ftl_vfl_write(ftl_cxt.ftlctrlpage, &ftl_erasectr[index << 10],
1259 &ftl_sparebuffer) != 0) 1406 &ftl_sparebuffer[0]) != 0)
1260 return 1; 1407 return 1;
1261 if ((ftl_vfl_read(ftl_cxt.ftlctrlpage, ftl_buffer, 1408 if ((ftl_vfl_read(ftl_cxt.ftlctrlpage, ftl_buffer,
1262 &ftl_sparebuffer, 1, 1) & 0x11F) != 0) 1409 &ftl_sparebuffer[0], 1, 1) & 0x11F) != 0)
1263 return 1; 1410 return 1;
1264 if (memcmp(ftl_buffer, &ftl_erasectr[index << 10], 0x800) != 0) return 1; 1411 if (memcmp(ftl_buffer, &ftl_erasectr[index << 10], 0x800) != 0) return 1;
1265 if (ftl_sparebuffer.meta.type != 0x46) return 1; 1412 if (ftl_sparebuffer[0].meta.type != 0x46) return 1;
1266 if (ftl_sparebuffer.meta.idx != index) return 1; 1413 if (ftl_sparebuffer[0].meta.idx != index) return 1;
1267 if (ftl_sparebuffer.meta.usn != ftl_cxt.usn) return 1; 1414 if (ftl_sparebuffer[0].meta.usn != ftl_cxt.usn) return 1;
1268 ftl_cxt.ftl_erasectr_pages[index] = ftl_cxt.ftlctrlpage; 1415 ftl_cxt.ftl_erasectr_pages[index] = ftl_cxt.ftlctrlpage;
1269 ftl_erasectr_dirt[index] = 0; 1416 ftl_erasectr_dirt[index] = 0;
1270 return 0; 1417 return 0;
@@ -1317,17 +1464,17 @@ uint32_t ftl_copy_page(uint32_t source, uint32_t destination,
1317 uint32_t lpn, uint32_t type) 1464 uint32_t lpn, uint32_t type)
1318{ 1465{
1319 uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; 1466 uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks;
1320 uint32_t rc = ftl_vfl_read(source, ftl_copybuffer, 1467 uint32_t rc = ftl_vfl_read(source, ftl_copybuffer[0],
1321 &ftl_sparebuffer, 1, 1) & 0x11F; 1468 &ftl_copyspare[0], 1, 1) & 0x11F;
1322 memset(&ftl_sparebuffer, 0xFF, 0x40); 1469 memset(&ftl_copyspare[0], 0xFF, 0x40);
1323 ftl_sparebuffer.user.lpn = lpn; 1470 ftl_copyspare[0].user.lpn = lpn;
1324 ftl_sparebuffer.user.usn = ++ftl_cxt.nextblockusn; 1471 ftl_copyspare[0].user.usn = ++ftl_cxt.nextblockusn;
1325 ftl_sparebuffer.user.type = 0x40; 1472 ftl_copyspare[0].user.type = 0x40;
1326 if ((rc & 2) != 0) memset(ftl_copybuffer, 0, 0x800); 1473 if ((rc & 2) != 0) memset(ftl_copybuffer[0], 0, 0x800);
1327 else if (rc != 0) ftl_sparebuffer.user.eccmark = 0x55; 1474 else if (rc != 0) ftl_copyspare[0].user.eccmark = 0x55;
1328 if (type == 1 && destination % ppb == ppb - 1) 1475 if (type == 1 && destination % ppb == ppb - 1)
1329 ftl_sparebuffer.user.type = 0x41; 1476 ftl_copyspare[0].user.type = 0x41;
1330 return ftl_vfl_write(destination, ftl_copybuffer, &ftl_sparebuffer); 1477 return ftl_vfl_write(destination, ftl_copybuffer[0], &ftl_copyspare[0]);
1331} 1478}
1332#endif 1479#endif
1333 1480
@@ -1336,21 +1483,28 @@ uint32_t ftl_copy_page(uint32_t source, uint32_t destination,
1336/* Copies a pBlock to a vBlock */ 1483/* Copies a pBlock to a vBlock */
1337uint32_t ftl_copy_block(uint32_t source, uint32_t destination) 1484uint32_t ftl_copy_block(uint32_t source, uint32_t destination)
1338{ 1485{
1339 uint32_t i; 1486 uint32_t i, j;
1340 uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; 1487 uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks;
1341 uint32_t error = 0; 1488 uint32_t error = 0;
1342 ftl_cxt.nextblockusn++; 1489 ftl_cxt.nextblockusn++;
1343 for (i = 0; i < ppb; i++) 1490 for (i = 0; i < (*ftl_nand_type).pagesperblock; i ++)
1344 { 1491 {
1345 uint32_t rc = ftl_read(source * ppb + i, 1, ftl_copybuffer); 1492 uint32_t rc = ftl_read(source * ppb + i * ftl_banks, ftl_banks, ftl_copybuffer[0]);
1346 memset(&ftl_sparebuffer, 0xFF, 0x40); 1493 memset(&ftl_copyspare[0], 0xFF, 0x100);
1347 ftl_sparebuffer.user.lpn = source * ppb + i; 1494 for (j = 0; j < ftl_banks; j++)
1348 ftl_sparebuffer.user.usn = ftl_cxt.nextblockusn; 1495 {
1349 ftl_sparebuffer.user.type = 0x40; 1496 ftl_copyspare[j].user.lpn = source * ppb + i * ftl_banks + j;
1350 if (rc != 0) ftl_sparebuffer.user.eccmark = 0x55; 1497 ftl_copyspare[j].user.usn = ftl_cxt.nextblockusn;
1351 if (i == ppb - 1) ftl_sparebuffer.user.type = 0x41; 1498 ftl_copyspare[j].user.type = 0x40;
1352 if (ftl_vfl_write(destination * ppb + i, 1499 if (rc)
1353 ftl_copybuffer, &ftl_sparebuffer) != 0) 1500 {
1501 if (ftl_read(source * ppb + i * ftl_banks + j, 1, ftl_copybuffer[j]))
1502 ftl_copyspare[j].user.eccmark = 0x55;
1503 }
1504 if (i + j == ppb - 1) ftl_copyspare[j].user.type = 0x41;
1505 }
1506 if (ftl_vfl_write_fast(destination * ppb + i * ftl_banks,
1507 ftl_copybuffer[0], &ftl_copyspare[0]))
1354 { 1508 {
1355 error = 1; 1509 error = 1;
1356 break; 1510 break;
@@ -1471,6 +1625,7 @@ uint32_t ftl_commit_scattered(struct ftl_log_type* entry)
1471 If this fails for whichever reason, it will be committed the usual way. */ 1625 If this fails for whichever reason, it will be committed the usual way. */
1472uint32_t ftl_commit_sequential(struct ftl_log_type* entry) 1626uint32_t ftl_commit_sequential(struct ftl_log_type* entry)
1473{ 1627{
1628 uint32_t i;
1474 uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; 1629 uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks;
1475 1630
1476 if ((*entry).issequential != 1 1631 if ((*entry).issequential != 1
@@ -1484,8 +1639,29 @@ uint32_t ftl_commit_sequential(struct ftl_log_type* entry)
1484 + (*entry).pagesused; 1639 + (*entry).pagesused;
1485 uint32_t oldpage = ftl_map[(*entry).logicalvblock] * ppb 1640 uint32_t oldpage = ftl_map[(*entry).logicalvblock] * ppb
1486 + (*entry).pagesused; 1641 + (*entry).pagesused;
1487 if ((*entry).pageoffsets[(*entry).pagesused] != 0xFFFF 1642 if ((*entry).pageoffsets[(*entry).pagesused] != 0xFFFF)
1488 || ftl_copy_page(oldpage, newpage, lpn, 1) != 0) 1643 return ftl_commit_scattered(entry);
1644 if (!((*entry).pagesused & (ftl_banks - 1)))
1645 {
1646 uint32_t rc = ftl_vfl_read_fast(oldpage, ftl_copybuffer[0],
1647 &ftl_copyspare[0], 1, 1);
1648 memset(&ftl_copyspare[0], 0xFF, 0x100);
1649 for (i = 0; i < ftl_banks; i++)
1650 {
1651 ftl_copyspare[i].user.lpn = lpn + i;
1652 ftl_copyspare[i].user.usn = ++ftl_cxt.nextblockusn;
1653 ftl_copyspare[i].user.type = 0x40;
1654 if (rc & (2 << (i << 2))) memset(ftl_copybuffer[i], 0, 0x800);
1655 else if (rc & (0xd << (i << 2)))
1656 ftl_copyspare[i].user.eccmark = 0x55;
1657 if ((*entry).pagesused + i == ppb - 1)
1658 ftl_copyspare[i].user.type = 0x41;
1659 }
1660 if (ftl_vfl_write_fast(newpage, ftl_copybuffer[0], &ftl_copyspare[0]))
1661 return ftl_commit_scattered(entry);
1662 (*entry).pagesused += ftl_banks - 1;
1663 }
1664 else if (ftl_copy_page(oldpage, newpage, lpn, 1))
1489 return ftl_commit_scattered(entry); 1665 return ftl_commit_scattered(entry);
1490 } 1666 }
1491 ftl_release_pool_block(ftl_map[(*entry).logicalvblock]); 1667 ftl_release_pool_block(ftl_map[(*entry).logicalvblock]);
@@ -1606,21 +1782,21 @@ uint32_t ftl_commit_cxt(void)
1606 for (i = 0; i < mappages; i++) 1782 for (i = 0; i < mappages; i++)
1607 { 1783 {
1608 if (ftl_next_ctrl_pool_page() != 0) return 1; 1784 if (ftl_next_ctrl_pool_page() != 0) return 1;
1609 memset(&ftl_sparebuffer, 0xFF, 0x40); 1785 memset(&ftl_sparebuffer[0], 0xFF, 0x40);
1610 ftl_sparebuffer.meta.usn = ftl_cxt.usn; 1786 ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
1611 ftl_sparebuffer.meta.idx = i; 1787 ftl_sparebuffer[0].meta.idx = i;
1612 ftl_sparebuffer.meta.type = 0x44; 1788 ftl_sparebuffer[0].meta.type = 0x44;
1613 if (ftl_vfl_write(ftl_cxt.ftlctrlpage, &ftl_map[i << 10], 1789 if (ftl_vfl_write(ftl_cxt.ftlctrlpage, &ftl_map[i << 10],
1614 &ftl_sparebuffer) != 0) 1790 &ftl_sparebuffer[0]) != 0)
1615 return 1; 1791 return 1;
1616 ftl_cxt.ftl_map_pages[i] = ftl_cxt.ftlctrlpage; 1792 ftl_cxt.ftl_map_pages[i] = ftl_cxt.ftlctrlpage;
1617 } 1793 }
1618 if (ftl_next_ctrl_pool_page() != 0) return 1; 1794 if (ftl_next_ctrl_pool_page() != 0) return 1;
1619 ftl_cxt.clean_flag = 1; 1795 ftl_cxt.clean_flag = 1;
1620 memset(&ftl_sparebuffer, 0xFF, 0x40); 1796 memset(&ftl_sparebuffer[0], 0xFF, 0x40);
1621 ftl_sparebuffer.meta.usn = ftl_cxt.usn; 1797 ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
1622 ftl_sparebuffer.meta.type = 0x43; 1798 ftl_sparebuffer[0].meta.type = 0x43;
1623 if (ftl_vfl_write(ftl_cxt.ftlctrlpage, &ftl_cxt, &ftl_sparebuffer) != 0) 1799 if (ftl_vfl_write(ftl_cxt.ftlctrlpage, &ftl_cxt, &ftl_sparebuffer[0]) != 0)
1624 return 1; 1800 return 1;
1625 return 0; 1801 return 0;
1626} 1802}
@@ -1674,7 +1850,7 @@ uint32_t ftl_swap_blocks(void)
1674/* Exposed function: Write highlevel sectors */ 1850/* Exposed function: Write highlevel sectors */
1675uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer) 1851uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer)
1676{ 1852{
1677 uint32_t i, j; 1853 uint32_t i, j, k;
1678 uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; 1854 uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks;
1679 1855
1680 if (sector + count > (*ftl_nand_type).userblocks * ppb) 1856 if (sector + count > (*ftl_nand_type).userblocks * ppb)
@@ -1694,11 +1870,11 @@ uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer)
1694 return 1; 1870 return 1;
1695 } 1871 }
1696 memset(ftl_buffer, 0xFF, 0x800); 1872 memset(ftl_buffer, 0xFF, 0x800);
1697 memset(&ftl_sparebuffer, 0xFF, 0x40); 1873 memset(&ftl_sparebuffer[0], 0xFF, 0x40);
1698 ftl_sparebuffer.meta.usn = ftl_cxt.usn; 1874 ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
1699 ftl_sparebuffer.meta.type = 0x47; 1875 ftl_sparebuffer[0].meta.type = 0x47;
1700 if (ftl_vfl_write(ftl_cxt.ftlctrlpage, ftl_buffer, 1876 if (ftl_vfl_write(ftl_cxt.ftlctrlpage, ftl_buffer,
1701 &ftl_sparebuffer) == 0) 1877 &ftl_sparebuffer[0]) == 0)
1702 break; 1878 break;
1703 } 1879 }
1704 if (i == 3) 1880 if (i == 3)
@@ -1735,16 +1911,27 @@ uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer)
1735 } 1911 }
1736 } 1912 }
1737 ftl_cxt.nextblockusn++; 1913 ftl_cxt.nextblockusn++;
1738 for (j = 0; j < ppb; j++) 1914 for (j = 0; j < ppb; j += ftl_banks)
1739 { 1915 {
1740 memset(&ftl_sparebuffer, 0xFF, 0x40); 1916 memset(&ftl_sparebuffer[0], 0xFF, 0x100);
1741 ftl_sparebuffer.user.lpn = sector + i + j; 1917 for (k = 0; k < ftl_banks; k++)
1742 ftl_sparebuffer.user.usn = ftl_cxt.nextblockusn; 1918 {
1743 ftl_sparebuffer.user.type = 0x40; 1919 ftl_sparebuffer[k].user.lpn = sector + i + j + k;
1744 if (j == ppb - 1) ftl_sparebuffer.user.type = 0x41; 1920 ftl_sparebuffer[k].user.usn = ftl_cxt.nextblockusn;
1745 while (ftl_vfl_write(vblock * ppb + j, 1921 ftl_sparebuffer[k].user.type = 0x40;
1746 &((uint8_t*)buffer)[(i + j) << 11], 1922 if (j == ppb - 1) ftl_sparebuffer[k].user.type = 0x41;
1747 &ftl_sparebuffer) != 0); 1923 }
1924 uint32_t rc = ftl_vfl_write_fast(vblock * ppb + j,
1925 &((uint8_t*)buffer)[(i + j) << 11],
1926 &ftl_sparebuffer[0]);
1927 if (rc)
1928 for (k = 0; k < ftl_banks; k++)
1929 if (rc & (1 << k))
1930 {
1931 while (ftl_vfl_write(vblock * ppb + j + k,
1932 &((uint8_t*)buffer)[(i + j + k) << 11],
1933 &ftl_sparebuffer[k]));
1934 }
1748 } 1935 }
1749 ftl_release_pool_block(ftl_map[block]); 1936 ftl_release_pool_block(ftl_map[block]);
1750 ftl_map[block] = vblock; 1937 ftl_map[block] = vblock;
@@ -1762,20 +1949,57 @@ uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer)
1762 return 1; 1949 return 1;
1763 } 1950 }
1764 } 1951 }
1765 memset(&ftl_sparebuffer, 0xFF, 0x40); 1952 if ((unsigned)((*logentry).pagesused + ftl_banks) <= ppb
1766 ftl_sparebuffer.user.lpn = sector + i; 1953 && i + ftl_banks <= count
1767 ftl_sparebuffer.user.usn = ++ftl_cxt.nextblockusn; 1954 && !((*logentry).pagesused & (ftl_banks - 1))
1768 ftl_sparebuffer.user.type = 0x40; 1955 && page + ftl_banks <= ppb)
1769 uint32_t abspage = (*logentry).scatteredvblock * ppb
1770 + (*logentry).pagesused++;
1771 if (ftl_vfl_write(abspage, &((uint8_t*)buffer)[i << 11],
1772 &ftl_sparebuffer) == 0)
1773 { 1956 {
1774 if ((*logentry).pageoffsets[page] == 0xFFFF) 1957 memset(&ftl_sparebuffer[0], 0xFF, 0x100);
1775 (*logentry).pagescurrent++; 1958 for (j = 0; j < ftl_banks; j++)
1776 (*logentry).pageoffsets[page] = (*logentry).pagesused - 1; 1959 {
1777 ftl_check_still_sequential(logentry, page); 1960 ftl_sparebuffer[j].user.lpn = sector + i + j;
1778 i++; 1961 ftl_sparebuffer[j].user.usn = ++ftl_cxt.nextblockusn;
1962 ftl_sparebuffer[j].user.type = 0x40;
1963 if ((*logentry).pagesused + j == ppb - 1 && (*logentry).issequential)
1964 ftl_sparebuffer[j].user.type = 0x41;
1965 }
1966 uint32_t abspage = (*logentry).scatteredvblock * ppb
1967 + (*logentry).pagesused;
1968 (*logentry).pagesused += ftl_banks;
1969 if (ftl_vfl_write_fast(abspage, &((uint8_t*)buffer)[i << 11],
1970 &ftl_sparebuffer[0]) == 0)
1971 {
1972 for (j = 0; j < ftl_banks; j++)
1973 {
1974 if ((*logentry).pageoffsets[page + j] == 0xFFFF)
1975 (*logentry).pagescurrent++;
1976 (*logentry).pageoffsets[page + j] = (*logentry).pagesused - ftl_banks + j;
1977 if ((*logentry).pagesused - ftl_banks + j + 1 != (*logentry).pagescurrent
1978 || (*logentry).pageoffsets[page + j] != page + j)
1979 (*logentry).issequential = 0;
1980 }
1981 i += ftl_banks;
1982 }
1983 }
1984 else
1985 {
1986 memset(&ftl_sparebuffer[0], 0xFF, 0x40);
1987 ftl_sparebuffer[0].user.lpn = sector + i;
1988 ftl_sparebuffer[0].user.usn = ++ftl_cxt.nextblockusn;
1989 ftl_sparebuffer[0].user.type = 0x40;
1990 if ((*logentry).pagesused == ppb - 1 && (*logentry).issequential)
1991 ftl_sparebuffer[0].user.type = 0x41;
1992 uint32_t abspage = (*logentry).scatteredvblock * ppb
1993 + (*logentry).pagesused++;
1994 if (ftl_vfl_write(abspage, &((uint8_t*)buffer)[i << 11],
1995 &ftl_sparebuffer[0]) == 0)
1996 {
1997 if ((*logentry).pageoffsets[page] == 0xFFFF)
1998 (*logentry).pagescurrent++;
1999 (*logentry).pageoffsets[page] = (*logentry).pagesused - 1;
2000 ftl_check_still_sequential(logentry, page);
2001 i++;
2002 }
1779 } 2003 }
1780 } 2004 }
1781 } 2005 }
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
100static uint8_t nand_data[0x800] __attribute__((aligned(16))); 100static uint8_t nand_data[0x800] __attribute__((aligned(16)));
101static uint8_t nand_ctrl[0x200] __attribute__((aligned(16))); 101static uint8_t nand_ctrl[0x200] __attribute__((aligned(16)));
102static uint8_t nand_spare[0x40] __attribute__((aligned(16))); 102static uint8_t nand_spare[4][0x40] __attribute__((aligned(16)));
103static uint8_t nand_ecc[0x30] __attribute__((aligned(16))); 103static uint8_t nand_ecc[0x30] __attribute__((aligned(16)));
104 104
105 105
106uint32_t nand_unlock(uint32_t rc) 106uint32_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
491uint32_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
577uint32_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
653uint32_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
490const struct nand_device_info_type* nand_get_device_type(uint32_t bank) 688const 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)
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/nand-target.h b/firmware/target/arm/s5l8700/ipodnano2g/nand-target.h
index dee690e5e6..000373fff1 100644
--- a/firmware/target/arm/s5l8700/ipodnano2g/nand-target.h
+++ b/firmware/target/arm/s5l8700/ipodnano2g/nand-target.h
@@ -46,6 +46,13 @@ uint32_t nand_write_page(uint32_t bank, uint32_t page, void* databuffer,
46 void* sparebuffer, uint32_t doecc); 46 void* sparebuffer, uint32_t doecc);
47uint32_t nand_block_erase(uint32_t bank, uint32_t page); 47uint32_t nand_block_erase(uint32_t bank, uint32_t page);
48 48
49uint32_t nand_read_page_fast(uint32_t page, void* databuffer,
50 void* sparebuffer, uint32_t doecc,
51 uint32_t checkempty);
52uint32_t nand_write_page_fast(uint32_t page, void* databuffer,
53 void* sparebuffer, uint32_t doecc);
54uint32_t nand_block_erase_fast(uint32_t page);
55
49const struct nand_device_info_type* nand_get_device_type(uint32_t bank); 56const struct nand_device_info_type* nand_get_device_type(uint32_t bank);
50uint32_t nand_reset(uint32_t bank); 57uint32_t nand_reset(uint32_t bank);
51uint32_t nand_device_init(void); 58uint32_t nand_device_init(void);