summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sparmann <theseven@rockbox.org>2009-11-08 14:55:30 +0000
committerMichael Sparmann <theseven@rockbox.org>2009-11-08 14:55:30 +0000
commit64ac121e2c36427490b4ae791a779006101bfbf4 (patch)
treefbdedfe5194831c877f09022fbc6b9c8d68401f2
parent40638bf2c73623bd00a4d669d3d0cd2eb01ff587 (diff)
downloadrockbox-64ac121e2c36427490b4ae791a779006101bfbf4.tar.gz
rockbox-64ac121e2c36427490b4ae791a779006101bfbf4.zip
Squash another bunch of iPod Nano 2G NAND bugs by moving the idle powerdown code down into the lowlevel driver. Move even more things from the FTL to the bss instead of the stack to prevent USB stkovs. Also fix some evil whitespace.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23570 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/target/arm/s5l8700/ata-nand-s5l8700.c36
-rw-r--r--firmware/target/arm/s5l8700/ipodnano2g/ftl-nano2g.c163
-rw-r--r--firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c40
-rw-r--r--firmware/target/arm/s5l8700/ipodnano2g/nand-target.h2
4 files changed, 129 insertions, 112 deletions
diff --git a/firmware/target/arm/s5l8700/ata-nand-s5l8700.c b/firmware/target/arm/s5l8700/ata-nand-s5l8700.c
index 8507001415..ad87d9ea73 100644
--- a/firmware/target/arm/s5l8700/ata-nand-s5l8700.c
+++ b/firmware/target/arm/s5l8700/ata-nand-s5l8700.c
@@ -30,30 +30,20 @@
30#include "ftl-target.h" 30#include "ftl-target.h"
31#include "nand-target.h" 31#include "nand-target.h"
32 32
33/* for compatibility */
34long last_disk_activity = -1;
35
36/** static, private data **/ 33/** static, private data **/
37static bool initialized = false; 34static bool initialized = false;
38 35
39static long nand_stack[20];
40
41/* API Functions */ 36/* API Functions */
42
43int nand_read_sectors(IF_MD2(int drive,) unsigned long start, int incount, 37int nand_read_sectors(IF_MD2(int drive,) unsigned long start, int incount,
44 void* inbuf) 38 void* inbuf)
45{ 39{
46 int rc = ftl_read(start, incount, inbuf); 40 return ftl_read(start, incount, inbuf);
47 last_disk_activity = current_tick;
48 return rc;
49} 41}
50 42
51int nand_write_sectors(IF_MD2(int drive,) unsigned long start, int count, 43int nand_write_sectors(IF_MD2(int drive,) unsigned long start, int count,
52 const void* outbuf) 44 const void* outbuf)
53{ 45{
54 int rc = ftl_write(start, count, outbuf); 46 return ftl_write(start, count, outbuf);
55 last_disk_activity = current_tick;
56 return rc;
57} 47}
58 48
59void nand_spindown(int seconds) 49void nand_spindown(int seconds)
@@ -73,7 +63,7 @@ void nand_sleepnow(void)
73 63
74void nand_spin(void) 64void nand_spin(void)
75{ 65{
76 last_disk_activity = current_tick; 66 nand_set_active();
77} 67}
78 68
79void nand_enable(bool on) 69void nand_enable(bool on)
@@ -93,40 +83,22 @@ void nand_get_info(IF_MD2(int drive,) struct storage_info *info)
93 83
94long nand_last_disk_activity(void) 84long nand_last_disk_activity(void)
95{ 85{
96 return last_disk_activity; 86 return nand_last_activity();
97} 87}
98 88
99#ifdef HAVE_STORAGE_FLUSH 89#ifdef HAVE_STORAGE_FLUSH
100int nand_flush(void) 90int nand_flush(void)
101{ 91{
102 last_disk_activity = current_tick;
103 int rc = ftl_sync(); 92 int rc = ftl_sync();
104 if (rc != 0) panicf("Failed to unmount flash: %X", rc); 93 if (rc != 0) panicf("Failed to unmount flash: %X", rc);
105 return rc; 94 return rc;
106} 95}
107#endif 96#endif
108 97
109static void nand_thread(void)
110{
111 while (1)
112 {
113 if (TIME_AFTER(current_tick, last_disk_activity + HZ / 5))
114 nand_power_down();
115 sleep(HZ / 10);
116 }
117}
118
119int nand_init(void) 98int nand_init(void)
120{ 99{
121 if (ftl_init()) return 1; 100 if (ftl_init()) return 1;
122 101
123 last_disk_activity = current_tick;
124
125 create_thread(nand_thread, nand_stack,
126 sizeof(nand_stack), 0, "nand"
127 IF_PRIO(, PRIORITY_USER_INTERFACE)
128 IF_COP(, CPU));
129
130 initialized = true; 102 initialized = true;
131 return 0; 103 return 0;
132} 104}
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/ftl-nano2g.c b/firmware/target/arm/s5l8700/ipodnano2g/ftl-nano2g.c
index 2c11ab5340..0ce268ac30 100644
--- a/firmware/target/arm/s5l8700/ipodnano2g/ftl-nano2g.c
+++ b/firmware/target/arm/s5l8700/ipodnano2g/ftl-nano2g.c
@@ -83,7 +83,7 @@ struct ftl_log_type
83 83
84 /* Pages that are still up to date in this block, i.e. need to be 84 /* Pages that are still up to date in this block, i.e. need to be
85 moved when this vBlock is deallocated. */ 85 moved when this vBlock is deallocated. */
86 uint16_t pagescurrent; 86 uint16_t pagescurrent;
87 87
88 /* A flag whether all pages are still sequential in this block. 88 /* A flag whether all pages are still sequential in this block.
89 Initialized to 1 on allocation, zeroed as soon as anything is 89 Initialized to 1 on allocation, zeroed as soon as anything is
@@ -112,9 +112,9 @@ struct ftl_cxt_type
112 112
113 /* Count of currently free pages in the block pool */ 113 /* Count of currently free pages in the block pool */
114 uint16_t freecount; 114 uint16_t freecount;
115 115
116 /* Index to the first free block in the blockpool ring buffer */ 116 /* Index to the first free block in the blockpool ring buffer */
117 uint16_t nextfreeidx; 117 uint16_t nextfreeidx;
118 118
119 /* This is a counter that is used to better distribute block 119 /* This is a counter that is used to better distribute block
120 wear. It is incremented on every block erase, and if it 120 wear. It is incremented on every block erase, and if it
@@ -129,7 +129,7 @@ struct ftl_cxt_type
129 uint16_t blockpool[0x14]; 129 uint16_t blockpool[0x14];
130 130
131 /* Alignment to 32 bits */ 131 /* Alignment to 32 bits */
132 uint16_t field_36; 132 uint16_t field_36;
133 133
134 /* vPages where the block map is stored */ 134 /* vPages where the block map is stored */
135 uint32_t ftl_map_pages[8]; 135 uint32_t ftl_map_pages[8];
@@ -138,23 +138,23 @@ struct ftl_cxt_type
138 uint8_t field_58[0x28]; 138 uint8_t field_58[0x28];
139 139
140 /* vPages where the erase counters are stored */ 140 /* vPages where the erase counters are stored */
141 uint32_t ftl_erasectr_pages[8]; 141 uint32_t ftl_erasectr_pages[8];
142 142
143 /* Seems to be padding */ 143 /* Seems to be padding */
144 uint8_t field_A0[0x70]; 144 uint8_t field_A0[0x70];
145 145
146 /* Pointer to ftl_map used by Whimory, not used by us */ 146 /* Pointer to ftl_map used by Whimory, not used by us */
147 uint32_t ftl_map_ptr; 147 uint32_t ftl_map_ptr;
148 148
149 /* Pointer to ftl_erasectr used by Whimory, not used by us */ 149 /* Pointer to ftl_erasectr used by Whimory, not used by us */
150 uint32_t ftl_erasectr_ptr; 150 uint32_t ftl_erasectr_ptr;
151 151
152 /* Pointer to ftl_log used by Whimory, not used by us */ 152 /* Pointer to ftl_log used by Whimory, not used by us */
153 uint32_t ftl_log_ptr; 153 uint32_t ftl_log_ptr;
154 154
155 /* Flag used to indicate that some erase counter pages should be committed 155 /* Flag used to indicate that some erase counter pages should be committed
156 as they were changed more than 100 times since the last commit. */ 156 as they were changed more than 100 times since the last commit. */
157 uint32_t erasedirty; 157 uint32_t erasedirty;
158 158
159 /* Seems to be unused */ 159 /* Seems to be unused */
160 uint16_t field_120; 160 uint16_t field_120;
@@ -163,7 +163,7 @@ struct ftl_cxt_type
163 counter pages. This is also a ring buffer, and the oldest 163 counter pages. This is also a ring buffer, and the oldest
164 page gets swapped with the least used page from the block 164 page gets swapped with the least used page from the block
165 pool ring buffer when a new one is allocated. */ 165 pool ring buffer when a new one is allocated. */
166 uint16_t ftlctrlblocks[3]; 166 uint16_t ftlctrlblocks[3];
167 167
168 /* The last used vPage number from ftlctrlblocks */ 168 /* The last used vPage number from ftlctrlblocks */
169 uint32_t ftlctrlpage; 169 uint32_t ftlctrlpage;
@@ -173,7 +173,7 @@ struct ftl_cxt_type
173 uint32_t clean_flag; 173 uint32_t clean_flag;
174 174
175 /* Seems to be unused, but gets loaded from flash by Whimory. */ 175 /* Seems to be unused, but gets loaded from flash by Whimory. */
176 uint8_t field_130[0x15C]; 176 uint8_t field_130[0x15C];
177 177
178} __attribute__((packed)) FTLCxtType; 178} __attribute__((packed)) FTLCxtType;
179 179
@@ -185,7 +185,7 @@ typedef struct ftl_vfl_cxt_type
185 185
186 /* Cross-bank update sequence number, incremented on every VFL 186 /* Cross-bank update sequence number, incremented on every VFL
187 context commit on any bank. */ 187 context commit on any bank. */
188 uint32_t usn; 188 uint32_t usn;
189 189
190 /* See ftl_cxt.ftlctrlblocks. This is stored to the VFL contexts 190 /* See ftl_cxt.ftlctrlblocks. This is stored to the VFL contexts
191 in order to be able to find the most recent FTL context copy 191 in order to be able to find the most recent FTL context copy
@@ -194,14 +194,14 @@ typedef struct ftl_vfl_cxt_type
194 uint16_t ftlctrlblocks[3]; 194 uint16_t ftlctrlblocks[3];
195 195
196 /* Alignment to 32 bits */ 196 /* Alignment to 32 bits */
197 uint8_t field_A[2]; 197 uint8_t field_A[2];
198 198
199 /* Decrementing update counter for VFL context commits per bank */ 199 /* Decrementing update counter for VFL context commits per bank */
200 uint32_t updatecount; 200 uint32_t updatecount;
201 201
202 /* Number of the currently active VFL context block, it's an index 202 /* Number of the currently active VFL context block, it's an index
203 into vflcxtblocks. */ 203 into vflcxtblocks. */
204 uint16_t activecxtblock; 204 uint16_t activecxtblock;
205 205
206 /* Number of the first free page in the active FTL context block */ 206 /* Number of the first free page in the active FTL context block */
207 uint16_t nextcxtpage; 207 uint16_t nextcxtpage;
@@ -217,31 +217,31 @@ typedef struct ftl_vfl_cxt_type
217 uint16_t spareused; 217 uint16_t spareused;
218 218
219 /* pBlock number of the first spare block */ 219 /* pBlock number of the first spare block */
220 uint16_t firstspare; 220 uint16_t firstspare;
221 221
222 /* Total number of spare blocks */ 222 /* Total number of spare blocks */
223 uint16_t sparecount; 223 uint16_t sparecount;
224 224
225 /* Block remap table. Contains the vBlock number the n-th spare 225 /* Block remap table. Contains the vBlock number the n-th spare
226 block is used as a replacement for. 0 = unused, 0xFFFF = bad. */ 226 block is used as a replacement for. 0 = unused, 0xFFFF = bad. */
227 uint16_t remaptable[0x334]; 227 uint16_t remaptable[0x334];
228 228
229 /* Bad block table. Each bit represents 8 blocks. 1 = OK, 0 = Bad. 229 /* Bad block table. Each bit represents 8 blocks. 1 = OK, 0 = Bad.
230 If the entry is zero, you should look at the remap table to see 230 If the entry is zero, you should look at the remap table to see
231 if the block is remapped, and if yes, where the replacement is. */ 231 if the block is remapped, and if yes, where the replacement is. */
232 uint8_t bbt[0x11A]; 232 uint8_t bbt[0x11A];
233 233
234 /* pBlock numbers used to store the VFL context. This is a ring 234 /* pBlock numbers used to store the VFL context. This is a ring
235 buffer. On a VFL context write, always 8 pages are written, 235 buffer. On a VFL context write, always 8 pages are written,
236 and it passes if at least 4 of them can be read back. */ 236 and it passes if at least 4 of them can be read back. */
237 uint16_t vflcxtblocks[4]; 237 uint16_t vflcxtblocks[4];
238 238
239 /* Blocks scheduled for remapping are stored at the end of the 239 /* Blocks scheduled for remapping are stored at the end of the
240 remap table. This is the first index used for them. */ 240 remap table. This is the first index used for them. */
241 uint16_t scheduledstart; 241 uint16_t scheduledstart;
242 242
243 /* Probably padding */ 243 /* Probably padding */
244 uint8_t field_7AC[0x4C]; 244 uint8_t field_7AC[0x4C];
245 245
246 /* First checksum (addition) */ 246 /* First checksum (addition) */
247 uint32_t checksum1; 247 uint32_t checksum1;
@@ -265,17 +265,17 @@ union ftl_spare_data_type
265 265
266 /* The update sequence number of that page, 266 /* The update sequence number of that page,
267 copied from ftl_cxt.nextblockusn on write */ 267 copied from ftl_cxt.nextblockusn on write */
268 uint32_t usn; 268 uint32_t usn;
269 269
270 /* Seems to be unused */ 270 /* Seems to be unused */
271 uint8_t field_8; 271 uint8_t field_8;
272 272
273 /* Type field, 0x40 (data page) or 0x41 (last data page of block) */ 273 /* Type field, 0x40 (data page) or 0x41 (last data page of block) */
274 uint8_t type; 274 uint8_t type;
275 275
276 /* ECC mark, usually 0xFF. If an error occurred while reading the 276 /* ECC mark, usually 0xFF. If an error occurred while reading the
277 page during a copying operation earlier, this will be 0x55. */ 277 page during a copying operation earlier, this will be 0x55. */
278 uint8_t eccmark; 278 uint8_t eccmark;
279 279
280 /* Seems to be unused */ 280 /* Seems to be unused */
281 uint8_t field_B; 281 uint8_t field_B;
@@ -297,10 +297,10 @@ union ftl_spare_data_type
297 297
298 /* Index of the thing inside the page, 298 /* Index of the thing inside the page,
299 for example number / index of the map or erase counter page */ 299 for example number / index of the map or erase counter page */
300 uint16_t idx; 300 uint16_t idx;
301 301
302 /* Seems to be unused */ 302 /* Seems to be unused */
303 uint8_t field_6; 303 uint8_t field_6;
304 304
305 /* Seems to be unused */ 305 /* Seems to be unused */
306 uint8_t field_7; 306 uint8_t field_7;
@@ -318,7 +318,7 @@ union ftl_spare_data_type
318 318
319 /* ECC mark, usually 0xFF. If an error occurred while reading the 319 /* ECC mark, usually 0xFF. If an error occurred while reading the
320 page during a copying operation earlier, this will be 0x55. */ 320 page during a copying operation earlier, this will be 0x55. */
321 uint8_t eccmark; 321 uint8_t eccmark;
322 322
323 /* Seems to be unused */ 323 /* Seems to be unused */
324 uint8_t field_B; 324 uint8_t field_B;
@@ -339,14 +339,14 @@ struct ftl_trouble_type
339{ 339{
340 340
341 /* vBlock number of the block giving trouble */ 341 /* vBlock number of the block giving trouble */
342 uint16_t block; 342 uint16_t block;
343 343
344 /* Bank of the block giving trouble */ 344 /* Bank of the block giving trouble */
345 uint8_t bank; 345 uint8_t bank;
346 346
347 /* Error counter, incremented by 3 on error, decremented by 1 on erase, 347 /* Error counter, incremented by 3 on error, decremented by 1 on erase,
348 remaping will be done when it reaches 6. */ 348 remaping will be done when it reaches 6. */
349 uint8_t errors; 349 uint8_t errors;
350 350
351} __attribute__((packed)); 351} __attribute__((packed));
352 352
@@ -359,47 +359,57 @@ const struct nand_device_info_type* ftl_nand_type;
359uint32_t ftl_banks; 359uint32_t ftl_banks;
360 360
361/* Block map, used vor pBlock to vBlock mapping */ 361/* Block map, used vor pBlock to vBlock mapping */
362uint16_t ftl_map[0x2000]; 362uint16_t ftl_map[0x2000];
363 363
364/* VFL context for each bank */ 364/* VFL context for each bank */
365struct ftl_vfl_cxt_type ftl_vfl_cxt[4]; 365struct ftl_vfl_cxt_type ftl_vfl_cxt[4];
366 366
367/* FTL context */ 367/* FTL context */
368struct ftl_cxt_type ftl_cxt; 368struct ftl_cxt_type ftl_cxt;
369 369
370/* Temporary data buffer for internal use by the FTL */ 370/* Temporary data buffers for internal use by the FTL */
371uint8_t ftl_buffer[0x800] __attribute__((aligned(16))); 371uint8_t ftl_buffer[0x800] __attribute__((aligned(16)));
372 372
373/* Temporary spare byte buffer for internal use by the FTL */ 373/* Temporary spare byte buffer for internal use by the FTL */
374union ftl_spare_data_type ftl_sparebuffer __attribute__((aligned(16))); 374union ftl_spare_data_type ftl_sparebuffer __attribute__((aligned(16)));
375 375
376 376
377#ifndef FTL_READONLY 377#ifndef FTL_READONLY
378 378
379/* Lowlevel BBT for each bank */ 379/* Lowlevel BBT for each bank */
380uint8_t ftl_bbt[4][0x410]; 380uint8_t ftl_bbt[4][0x410];
381 381
382/* Erase countes for the vBlocks */ 382/* Erase countes for the vBlocks */
383uint16_t ftl_erasectr[0x2000]; 383uint16_t ftl_erasectr[0x2000];
384 384
385/* Used by ftl_log */ 385/* Used by ftl_log */
386uint16_t ftl_offsets[0x11][0x200]; 386uint16_t ftl_offsets[0x11][0x200];
387 387
388/* Structs keeping record of scattered page blocks */ 388/* Structs keeping record of scattered page blocks */
389struct ftl_log_type ftl_log[0x11]; 389struct ftl_log_type ftl_log[0x11];
390 390
391/* Global cross-bank update sequence number of the VFL context */ 391/* Global cross-bank update sequence number of the VFL context */
392uint32_t ftl_vfl_usn; 392uint32_t ftl_vfl_usn;
393 393
394/* Keeps track (temporarily) of troublesome blocks */ 394/* Keeps track (temporarily) of troublesome blocks */
395struct ftl_trouble_type ftl_troublelog[5]; 395struct ftl_trouble_type ftl_troublelog[5];
396 396
397/* Counts erase counter page changes, after 100 of them the affected 397/* Counts erase counter page changes, after 100 of them the affected
398 page will be committed to the flash. */ 398 page will be committed to the flash. */
399uint8_t ftl_erasectr_dirt[8]; 399uint8_t ftl_erasectr_dirt[8];
400 400
401/* Buffer needed for copying pages around while moving or committing blocks.
402 This can't be shared with ftl_buffer, because this one could be overwritten
403 during the copying operation in order to e.g. commit a CXT. */
404uint8_t ftl_copybuffer[0x800] __attribute__((aligned(16)));
405
406/* Needed to store the old scattered page offsets in order to be able to roll
407 back if something fails while compacting a scattered page block. */
408uint16_t ftl_offsets_backup[0x200] __attribute__((aligned(16)));
409
401#endif 410#endif
402 411
412
403static struct mutex ftl_mtx; 413static struct mutex ftl_mtx;
404 414
405 415
@@ -413,28 +423,28 @@ uint32_t ftl_find_devinfo(uint32_t bank)
413 - ((*ftl_nand_type).blocks / 10); 423 - ((*ftl_nand_type).blocks / 10);
414 uint32_t block, page, pagenum; 424 uint32_t block, page, pagenum;
415 for (block = (*ftl_nand_type).blocks - 1; block >= lowestBlock; block--) 425 for (block = (*ftl_nand_type).blocks - 1; block >= lowestBlock; block--)
416 { 426 {
417 page = (*ftl_nand_type).pagesperblock - 8; 427 page = (*ftl_nand_type).pagesperblock - 8;
418 for (; page < (*ftl_nand_type).pagesperblock; page++) 428 for (; page < (*ftl_nand_type).pagesperblock; page++)
419 { 429 {
420 pagenum = block * (*ftl_nand_type).pagesperblock + page; 430 pagenum = block * (*ftl_nand_type).pagesperblock + page;
421 if ((nand_read_page(bank, pagenum, ftl_buffer, 431 if ((nand_read_page(bank, pagenum, ftl_buffer,
422 &ftl_sparebuffer, 1, 0) & 0x11F) != 0) 432 &ftl_sparebuffer, 1, 0) & 0x11F) != 0)
423 continue; 433 continue;
424 if (memcmp(ftl_buffer, "DEVICEINFOSIGN\0", 0x10) == 0) 434 if (memcmp(ftl_buffer, "DEVICEINFOSIGN\0", 0x10) == 0)
425 return pagenum; 435 return pagenum;
426 } 436 }
427 } 437 }
428 return 0; 438 return 0;
429} 439}
430 440
431 441
432/* Checks if all banks have proper device info pages */ 442/* Checks if all banks have proper device info pages */
433uint32_t ftl_has_devinfo(void) 443uint32_t ftl_has_devinfo(void)
434{ 444{
435 uint32_t i; 445 uint32_t i;
436 for (i = 0; i < ftl_banks; i++) if (ftl_find_devinfo(i) == 0) return 0; 446 for (i = 0; i < ftl_banks; i++) if (ftl_find_devinfo(i) == 0) return 0;
437 return 1; 447 return 1;
438} 448}
439 449
440 450
@@ -442,33 +452,33 @@ uint32_t ftl_has_devinfo(void)
442 This is based on some cryptic disassembly and not fully understood yet. */ 452 This is based on some cryptic disassembly and not fully understood yet. */
443uint32_t ftl_load_bbt(uint32_t bank, uint8_t* bbt) 453uint32_t ftl_load_bbt(uint32_t bank, uint8_t* bbt)
444{ 454{
445 uint32_t i, j; 455 uint32_t i, j;
446 uint32_t pagebase, page = ftl_find_devinfo(bank), page2; 456 uint32_t pagebase, page = ftl_find_devinfo(bank), page2;
447 uint32_t unk1, unk2, unk3; 457 uint32_t unk1, unk2, unk3;
448 if (page == 0) return 1; 458 if (page == 0) return 1;
449 pagebase = page & ~((*ftl_nand_type).pagesperblock - 1); 459 pagebase = page & ~((*ftl_nand_type).pagesperblock - 1);
450 if ((nand_read_page(bank, page, ftl_buffer, 460 if ((nand_read_page(bank, page, ftl_buffer,
451 (uint32_t*)0, 1, 0) & 0x11F) != 0) return 1; 461 (uint32_t*)0, 1, 0) & 0x11F) != 0) return 1;
452 if (memcmp(&ftl_buffer[0x18], "BBT", 4) != 0) return 1; 462 if (memcmp(&ftl_buffer[0x18], "BBT", 4) != 0) return 1;
453 unk1 = ((uint16_t*)ftl_buffer)[0x10]; 463 unk1 = ((uint16_t*)ftl_buffer)[0x10];
454 unk2 = ((uint16_t*)ftl_buffer)[0x11]; 464 unk2 = ((uint16_t*)ftl_buffer)[0x11];
455 unk3 = ((uint16_t*)ftl_buffer)[((uint32_t*)ftl_buffer)[4] * 0xC + 10] 465 unk3 = ((uint16_t*)ftl_buffer)[((uint32_t*)ftl_buffer)[4] * 0xC + 10]
456 + ((uint16_t*)ftl_buffer)[((uint32_t*)ftl_buffer)[4] * 0xC + 11]; 466 + ((uint16_t*)ftl_buffer)[((uint32_t*)ftl_buffer)[4] * 0xC + 11];
457 for (i = 0; i < unk1; i++) 467 for (i = 0; i < unk1; i++)
458 { 468 {
459 for (j = 0; ; j++) 469 for (j = 0; ; j++)
460 { 470 {
461 page2 = unk2 + i + unk3 * j; 471 page2 = unk2 + i + unk3 * j;
462 if (page2 >= (uint32_t)((*ftl_nand_type).pagesperblock - 8)) 472 if (page2 >= (uint32_t)((*ftl_nand_type).pagesperblock - 8))
463 break; 473 break;
464 if ((nand_read_page(bank, pagebase + page2, ftl_buffer, 474 if ((nand_read_page(bank, pagebase + page2, ftl_buffer,
465 (void*)0, 1, 0) & 0x11F) == 0) 475 (void*)0, 1, 0) & 0x11F) == 0)
466 { 476 {
467 memcpy(bbt, ftl_buffer, 0x410); 477 memcpy(bbt, ftl_buffer, 0x410);
468 return 0; 478 return 0;
469 } 479 }
470 } 480 }
471 } 481 }
472 return 1; 482 return 1;
473} 483}
474 484
@@ -929,7 +939,7 @@ uint32_t ftl_vfl_open(void)
929 { 939 {
930 if (ftl_vfl_read_page(i, vflcxtblock[vflcxtidx], 940 if (ftl_vfl_read_page(i, vflcxtblock[vflcxtidx],
931 k, ftl_buffer, 941 k, ftl_buffer,
932 &ftl_sparebuffer) != 0) 942 &ftl_sparebuffer) != 0)
933 break; 943 break;
934 last = k; 944 last = k;
935 } 945 }
@@ -1306,19 +1316,18 @@ uint32_t ftl_next_ctrl_pool_page(void)
1306uint32_t ftl_copy_page(uint32_t source, uint32_t destination, 1316uint32_t ftl_copy_page(uint32_t source, uint32_t destination,
1307 uint32_t lpn, uint32_t type) 1317 uint32_t lpn, uint32_t type)
1308{ 1318{
1309 uint8_t buffer[0x800];
1310 uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; 1319 uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks;
1311 uint32_t rc = ftl_vfl_read(source, buffer, 1320 uint32_t rc = ftl_vfl_read(source, ftl_copybuffer,
1312 &ftl_sparebuffer, 1, 1) & 0x11F; 1321 &ftl_sparebuffer, 1, 1) & 0x11F;
1313 memset(&ftl_sparebuffer, 0xFF, 0x40); 1322 memset(&ftl_sparebuffer, 0xFF, 0x40);
1314 ftl_sparebuffer.user.lpn = lpn; 1323 ftl_sparebuffer.user.lpn = lpn;
1315 ftl_sparebuffer.user.usn = ++ftl_cxt.nextblockusn; 1324 ftl_sparebuffer.user.usn = ++ftl_cxt.nextblockusn;
1316 ftl_sparebuffer.user.type = 0x40; 1325 ftl_sparebuffer.user.type = 0x40;
1317 if ((rc & 2) != 0) memset(buffer, 0, 0x800); 1326 if ((rc & 2) != 0) memset(ftl_copybuffer, 0, 0x800);
1318 else if (rc != 0) ftl_sparebuffer.user.eccmark = 0x55; 1327 else if (rc != 0) ftl_sparebuffer.user.eccmark = 0x55;
1319 if (type == 1 && destination % ppb == ppb - 1) 1328 if (type == 1 && destination % ppb == ppb - 1)
1320 ftl_sparebuffer.user.type = 0x41; 1329 ftl_sparebuffer.user.type = 0x41;
1321 return ftl_vfl_write(destination, buffer, &ftl_sparebuffer); 1330 return ftl_vfl_write(destination, ftl_copybuffer, &ftl_sparebuffer);
1322} 1331}
1323#endif 1332#endif
1324 1333
@@ -1330,11 +1339,10 @@ uint32_t ftl_copy_block(uint32_t source, uint32_t destination)
1330 uint32_t i; 1339 uint32_t i;
1331 uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; 1340 uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks;
1332 uint32_t error = 0; 1341 uint32_t error = 0;
1333 uint8_t buffer[0x800];
1334 ftl_cxt.nextblockusn++; 1342 ftl_cxt.nextblockusn++;
1335 for (i = 0; i < ppb; i++) 1343 for (i = 0; i < ppb; i++)
1336 { 1344 {
1337 uint32_t rc = ftl_read(source * ppb + i, 1, buffer); 1345 uint32_t rc = ftl_read(source * ppb + i, 1, ftl_copybuffer);
1338 memset(&ftl_sparebuffer, 0xFF, 0x40); 1346 memset(&ftl_sparebuffer, 0xFF, 0x40);
1339 ftl_sparebuffer.user.lpn = source * ppb + i; 1347 ftl_sparebuffer.user.lpn = source * ppb + i;
1340 ftl_sparebuffer.user.usn = ftl_cxt.nextblockusn; 1348 ftl_sparebuffer.user.usn = ftl_cxt.nextblockusn;
@@ -1342,7 +1350,7 @@ uint32_t ftl_copy_block(uint32_t source, uint32_t destination)
1342 if (rc != 0) ftl_sparebuffer.user.eccmark = 0x55; 1350 if (rc != 0) ftl_sparebuffer.user.eccmark = 0x55;
1343 if (i == ppb - 1) ftl_sparebuffer.user.type = 0x41; 1351 if (i == ppb - 1) ftl_sparebuffer.user.type = 0x41;
1344 if (ftl_vfl_write(destination * ppb + i, 1352 if (ftl_vfl_write(destination * ppb + i,
1345 buffer, &ftl_sparebuffer) != 0) 1353 ftl_copybuffer, &ftl_sparebuffer) != 0)
1346 { 1354 {
1347 error = 1; 1355 error = 1;
1348 break; 1356 break;
@@ -1383,7 +1391,6 @@ uint32_t ftl_compact_scattered(struct ftl_log_type* entry)
1383 uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; 1391 uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks;
1384 uint32_t error; 1392 uint32_t error;
1385 struct ftl_log_type backup; 1393 struct ftl_log_type backup;
1386 uint16_t backup_pageoffsets[0x200];
1387 if ((*entry).pagescurrent == 0) 1394 if ((*entry).pagescurrent == 0)
1388 { 1395 {
1389 ftl_release_pool_block((*entry).scatteredvblock); 1396 ftl_release_pool_block((*entry).scatteredvblock);
@@ -1391,7 +1398,7 @@ uint32_t ftl_compact_scattered(struct ftl_log_type* entry)
1391 return 0; 1398 return 0;
1392 } 1399 }
1393 backup = *entry; 1400 backup = *entry;
1394 memcpy(backup_pageoffsets, (*entry).pageoffsets, 0x400); 1401 memcpy(ftl_offsets_backup, (*entry).pageoffsets, 0x400);
1395 for (i = 0; i < 4; i++) 1402 for (i = 0; i < 4; i++)
1396 { 1403 {
1397 uint32_t block = ftl_allocate_pool_block(); 1404 uint32_t block = ftl_allocate_pool_block();
@@ -1425,7 +1432,7 @@ uint32_t ftl_compact_scattered(struct ftl_log_type* entry)
1425 break; 1432 break;
1426 } 1433 }
1427 *entry = backup; 1434 *entry = backup;
1428 memcpy((*entry).pageoffsets, backup_pageoffsets, 0x400); 1435 memcpy((*entry).pageoffsets, ftl_offsets_backup, 0x400);
1429 } 1436 }
1430 return error; 1437 return error;
1431} 1438}
@@ -1850,7 +1857,7 @@ uint32_t ftl_init(void)
1850{ 1857{
1851 mutex_init(&ftl_mtx); 1858 mutex_init(&ftl_mtx);
1852 uint32_t i; 1859 uint32_t i;
1853 uint32_t result = 0; 1860 uint32_t result = 0;
1854 uint32_t foundsignature, founddevinfo, blockwiped, repaired, skip; 1861 uint32_t foundsignature, founddevinfo, blockwiped, repaired, skip;
1855 if (nand_device_init() != 0) //return 1; 1862 if (nand_device_init() != 0) //return 1;
1856 panicf("FTL: Lowlevel NAND driver init failed!"); 1863 panicf("FTL: Lowlevel NAND driver init failed!");
@@ -1874,7 +1881,7 @@ uint32_t ftl_init(void)
1874 else if ((result & 2) != 2) blockwiped = 0; 1881 else if ((result & 2) != 2) blockwiped = 0;
1875 } 1882 }
1876 1883
1877 founddevinfo = ftl_has_devinfo(); 1884 founddevinfo = ftl_has_devinfo();
1878 1885
1879 repaired = 0; 1886 repaired = 0;
1880 skip = 0; 1887 skip = 0;
@@ -1904,7 +1911,7 @@ uint32_t ftl_init(void)
1904 (However there is curently no point in this, as iLoader would already 1911 (However there is curently no point in this, as iLoader would already
1905 fail if this would be the case.) 1912 fail if this would be the case.)
1906 1913
1907 nand_block_erase(0, 0); 1914 nand_block_erase(0, 0);
1908*/ 1915*/
1909 1916
1910 1917
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c b/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c
index ba10e4f9f2..73673cdd67 100644
--- a/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c
+++ b/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c
@@ -88,6 +88,8 @@ uint8_t nand_tunk2[4];
88uint8_t nand_tunk3[4]; 88uint8_t nand_tunk3[4];
89uint32_t nand_type[4]; 89uint32_t nand_type[4];
90int nand_powered = 0; 90int nand_powered = 0;
91long nand_last_activity_value = -1;
92static long nand_stack[20];
91 93
92static struct mutex nand_mtx; 94static struct mutex nand_mtx;
93static struct wakeup nand_wakeup; 95static struct wakeup nand_wakeup;
@@ -186,7 +188,6 @@ uint32_t nand_reset(uint32_t bank)
186 if (nand_send_cmd(NAND_CMD_RESET)) return 1; 188 if (nand_send_cmd(NAND_CMD_RESET)) return 1;
187 if (nand_wait_chip_ready(bank)) return 1; 189 if (nand_wait_chip_ready(bank)) return 1;
188 FMCTRL1 = FMCTRL1_CLEARRFIFO | FMCTRL1_CLEARWFIFO; 190 FMCTRL1 = FMCTRL1_CLEARRFIFO | FMCTRL1_CLEARWFIFO;
189 sleep(HZ / 100); /* Some chips seem to need this */
190 return 0; 191 return 0;
191} 192}
192 193
@@ -301,10 +302,21 @@ uint32_t nand_get_chip_type(uint32_t bank)
301 return nand_unlock(result); 302 return nand_unlock(result);
302} 303}
303 304
305void nand_set_active(void)
306{
307 nand_last_activity_value = current_tick;
308}
309
310long nand_last_activity(void)
311{
312 return nand_last_activity_value;
313}
314
304void nand_power_up(void) 315void nand_power_up(void)
305{ 316{
306 uint32_t i; 317 uint32_t i;
307 mutex_lock(&nand_mtx); 318 mutex_lock(&nand_mtx);
319 nand_last_activity_value = current_tick;
308 PWRCONEXT &= ~0x40; 320 PWRCONEXT &= ~0x40;
309 PWRCON &= ~0x100000; 321 PWRCON &= ~0x100000;
310 PCON2 = 0x33333333; 322 PCON2 = 0x33333333;
@@ -318,13 +330,16 @@ void nand_power_up(void)
318 pmu_ldo_set_voltage(4, 0x15); 330 pmu_ldo_set_voltage(4, 0x15);
319 pmu_ldo_power_on(4); 331 pmu_ldo_power_on(4);
320 sleep(HZ / 20); 332 sleep(HZ / 20);
333 nand_last_activity_value = current_tick;
321 for (i = 0; i < 4; i++) nand_reset(i); 334 for (i = 0; i < 4; i++) nand_reset(i);
322 nand_powered = 1; 335 nand_powered = 1;
336 nand_last_activity_value = current_tick;
323 mutex_unlock(&nand_mtx); 337 mutex_unlock(&nand_mtx);
324} 338}
325 339
326void nand_power_down(void) 340void nand_power_down(void)
327{ 341{
342 if (!nand_powered) return;
328 mutex_lock(&nand_mtx); 343 mutex_lock(&nand_mtx);
329 pmu_ldo_power_off(4); 344 pmu_ldo_power_off(4);
330 PCON2 = 0x11111111; 345 PCON2 = 0x11111111;
@@ -352,6 +367,7 @@ uint32_t nand_read_page(uint32_t bank, uint32_t page, void* databuffer,
352 if (sparebuffer && !((uint32_t)sparebuffer & 0xf)) 367 if (sparebuffer && !((uint32_t)sparebuffer & 0xf))
353 spare = (uint8_t*)sparebuffer; 368 spare = (uint8_t*)sparebuffer;
354 mutex_lock(&nand_mtx); 369 mutex_lock(&nand_mtx);
370 nand_last_activity_value = current_tick;
355 led(true); 371 led(true);
356 if (!nand_powered) nand_power_up(); 372 if (!nand_powered) nand_power_up();
357 uint32_t rc, eccresult; 373 uint32_t rc, eccresult;
@@ -409,6 +425,7 @@ uint32_t nand_write_page(uint32_t bank, uint32_t page, void* databuffer,
409 if (sparebuffer && !((uint32_t)sparebuffer & 0xf)) 425 if (sparebuffer && !((uint32_t)sparebuffer & 0xf))
410 spare = (uint8_t*)sparebuffer; 426 spare = (uint8_t*)sparebuffer;
411 mutex_lock(&nand_mtx); 427 mutex_lock(&nand_mtx);
428 nand_last_activity_value = current_tick;
412 led(true); 429 led(true);
413 if (!nand_powered) nand_power_up(); 430 if (!nand_powered) nand_power_up();
414 if (sparebuffer) 431 if (sparebuffer)
@@ -443,6 +460,7 @@ uint32_t nand_write_page(uint32_t bank, uint32_t page, void* databuffer,
443uint32_t nand_block_erase(uint32_t bank, uint32_t page) 460uint32_t nand_block_erase(uint32_t bank, uint32_t page)
444{ 461{
445 mutex_lock(&nand_mtx); 462 mutex_lock(&nand_mtx);
463 nand_last_activity_value = current_tick;
446 led(true); 464 led(true);
447 if (!nand_powered) nand_power_up(); 465 if (!nand_powered) nand_power_up();
448 nand_set_fmctrl0(bank, 0); 466 nand_set_fmctrl0(bank, 0);
@@ -463,6 +481,17 @@ const struct nand_device_info_type* nand_get_device_type(uint32_t bank)
463 return &nand_deviceinfotable[nand_type[bank]]; 481 return &nand_deviceinfotable[nand_type[bank]];
464} 482}
465 483
484static void nand_thread(void)
485{
486 while (1)
487 {
488 if (TIME_AFTER(current_tick, nand_last_activity_value + HZ / 5)
489 && nand_powered)
490 nand_power_down();
491 sleep(HZ / 10);
492 }
493}
494
466uint32_t nand_device_init(void) 495uint32_t nand_device_init(void)
467{ 496{
468 mutex_init(&nand_mtx); 497 mutex_init(&nand_mtx);
@@ -472,7 +501,7 @@ uint32_t nand_device_init(void)
472 501
473 uint32_t type; 502 uint32_t type;
474 uint32_t i, j; 503 uint32_t i, j;
475 if (!nand_powered) nand_power_up(); 504 nand_power_up();
476 for (i = 0; i < 4; i++) 505 for (i = 0; i < 4; i++)
477 { 506 {
478 nand_tunk1[i] = 7; 507 nand_tunk1[i] = 7;
@@ -497,5 +526,12 @@ uint32_t nand_device_init(void)
497 nand_tunk3[i] = nand_deviceinfotable[nand_type[i]].tunk3; 526 nand_tunk3[i] = nand_deviceinfotable[nand_type[i]].tunk3;
498 } 527 }
499 if (nand_type[0] == 0xFFFFFFFF) return 1; 528 if (nand_type[0] == 0xFFFFFFFF) return 1;
529
530 nand_last_activity_value = current_tick;
531 create_thread(nand_thread, nand_stack,
532 sizeof(nand_stack), 0, "nand"
533 IF_PRIO(, PRIORITY_USER_INTERFACE)
534 IF_COP(, CPU));
535
500 return 0; 536 return 0;
501} 537}
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/nand-target.h b/firmware/target/arm/s5l8700/ipodnano2g/nand-target.h
index a1559e936c..51b215a248 100644
--- a/firmware/target/arm/s5l8700/ipodnano2g/nand-target.h
+++ b/firmware/target/arm/s5l8700/ipodnano2g/nand-target.h
@@ -49,6 +49,8 @@ uint32_t nand_block_erase(uint32_t bank, uint32_t page);
49const struct nand_device_info_type* nand_get_device_type(uint32_t bank); 49const struct nand_device_info_type* nand_get_device_type(uint32_t bank);
50uint32_t nand_reset(uint32_t bank); 50uint32_t nand_reset(uint32_t bank);
51uint32_t nand_device_init(void); 51uint32_t nand_device_init(void);
52void nand_set_active(void);
53long nand_last_activity(void);
52void nand_power_up(void); 54void nand_power_up(void);
53void nand_power_down(void); 55void nand_power_down(void);
54 56