diff options
Diffstat (limited to 'firmware/target')
-rw-r--r-- | firmware/target/arm/s5l8700/ata-nand-s5l8700.c | 36 | ||||
-rw-r--r-- | firmware/target/arm/s5l8700/ipodnano2g/ftl-nano2g.c | 163 | ||||
-rw-r--r-- | firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c | 40 | ||||
-rw-r--r-- | firmware/target/arm/s5l8700/ipodnano2g/nand-target.h | 2 |
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 */ | ||
34 | long last_disk_activity = -1; | ||
35 | |||
36 | /** static, private data **/ | 33 | /** static, private data **/ |
37 | static bool initialized = false; | 34 | static bool initialized = false; |
38 | 35 | ||
39 | static long nand_stack[20]; | ||
40 | |||
41 | /* API Functions */ | 36 | /* API Functions */ |
42 | |||
43 | int nand_read_sectors(IF_MD2(int drive,) unsigned long start, int incount, | 37 | int 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 | ||
51 | int nand_write_sectors(IF_MD2(int drive,) unsigned long start, int count, | 43 | int 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 | ||
59 | void nand_spindown(int seconds) | 49 | void nand_spindown(int seconds) |
@@ -73,7 +63,7 @@ void nand_sleepnow(void) | |||
73 | 63 | ||
74 | void nand_spin(void) | 64 | void nand_spin(void) |
75 | { | 65 | { |
76 | last_disk_activity = current_tick; | 66 | nand_set_active(); |
77 | } | 67 | } |
78 | 68 | ||
79 | void nand_enable(bool on) | 69 | void nand_enable(bool on) |
@@ -93,40 +83,22 @@ void nand_get_info(IF_MD2(int drive,) struct storage_info *info) | |||
93 | 83 | ||
94 | long nand_last_disk_activity(void) | 84 | long 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 |
100 | int nand_flush(void) | 90 | int 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 | ||
109 | static 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 | |||
119 | int nand_init(void) | 98 | int 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; | |||
359 | uint32_t ftl_banks; | 359 | uint32_t ftl_banks; |
360 | 360 | ||
361 | /* Block map, used vor pBlock to vBlock mapping */ | 361 | /* Block map, used vor pBlock to vBlock mapping */ |
362 | uint16_t ftl_map[0x2000]; | 362 | uint16_t ftl_map[0x2000]; |
363 | 363 | ||
364 | /* VFL context for each bank */ | 364 | /* VFL context for each bank */ |
365 | struct ftl_vfl_cxt_type ftl_vfl_cxt[4]; | 365 | struct ftl_vfl_cxt_type ftl_vfl_cxt[4]; |
366 | 366 | ||
367 | /* FTL context */ | 367 | /* FTL context */ |
368 | struct ftl_cxt_type ftl_cxt; | 368 | struct 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 */ |
371 | uint8_t ftl_buffer[0x800] __attribute__((aligned(16))); | 371 | uint8_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 */ |
374 | union ftl_spare_data_type ftl_sparebuffer __attribute__((aligned(16))); | 374 | union 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 */ |
380 | uint8_t ftl_bbt[4][0x410]; | 380 | uint8_t ftl_bbt[4][0x410]; |
381 | 381 | ||
382 | /* Erase countes for the vBlocks */ | 382 | /* Erase countes for the vBlocks */ |
383 | uint16_t ftl_erasectr[0x2000]; | 383 | uint16_t ftl_erasectr[0x2000]; |
384 | 384 | ||
385 | /* Used by ftl_log */ | 385 | /* Used by ftl_log */ |
386 | uint16_t ftl_offsets[0x11][0x200]; | 386 | uint16_t ftl_offsets[0x11][0x200]; |
387 | 387 | ||
388 | /* Structs keeping record of scattered page blocks */ | 388 | /* Structs keeping record of scattered page blocks */ |
389 | struct ftl_log_type ftl_log[0x11]; | 389 | struct 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 */ |
392 | uint32_t ftl_vfl_usn; | 392 | uint32_t ftl_vfl_usn; |
393 | 393 | ||
394 | /* Keeps track (temporarily) of troublesome blocks */ | 394 | /* Keeps track (temporarily) of troublesome blocks */ |
395 | struct ftl_trouble_type ftl_troublelog[5]; | 395 | struct 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. */ |
399 | uint8_t ftl_erasectr_dirt[8]; | 399 | uint8_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. */ | ||
404 | uint8_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. */ | ||
408 | uint16_t ftl_offsets_backup[0x200] __attribute__((aligned(16))); | ||
409 | |||
401 | #endif | 410 | #endif |
402 | 411 | ||
412 | |||
403 | static struct mutex ftl_mtx; | 413 | static 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 */ |
433 | uint32_t ftl_has_devinfo(void) | 443 | uint32_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. */ |
443 | uint32_t ftl_load_bbt(uint32_t bank, uint8_t* bbt) | 453 | uint32_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) | |||
1306 | uint32_t ftl_copy_page(uint32_t source, uint32_t destination, | 1316 | uint32_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]; | |||
88 | uint8_t nand_tunk3[4]; | 88 | uint8_t nand_tunk3[4]; |
89 | uint32_t nand_type[4]; | 89 | uint32_t nand_type[4]; |
90 | int nand_powered = 0; | 90 | int nand_powered = 0; |
91 | long nand_last_activity_value = -1; | ||
92 | static long nand_stack[20]; | ||
91 | 93 | ||
92 | static struct mutex nand_mtx; | 94 | static struct mutex nand_mtx; |
93 | static struct wakeup nand_wakeup; | 95 | static 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 | ||
305 | void nand_set_active(void) | ||
306 | { | ||
307 | nand_last_activity_value = current_tick; | ||
308 | } | ||
309 | |||
310 | long nand_last_activity(void) | ||
311 | { | ||
312 | return nand_last_activity_value; | ||
313 | } | ||
314 | |||
304 | void nand_power_up(void) | 315 | void 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 | ||
326 | void nand_power_down(void) | 340 | void 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, | |||
443 | uint32_t nand_block_erase(uint32_t bank, uint32_t page) | 460 | uint32_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 | ||
484 | static 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 | |||
466 | uint32_t nand_device_init(void) | 495 | uint32_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); | |||
49 | const struct nand_device_info_type* nand_get_device_type(uint32_t bank); | 49 | const struct nand_device_info_type* nand_get_device_type(uint32_t bank); |
50 | uint32_t nand_reset(uint32_t bank); | 50 | uint32_t nand_reset(uint32_t bank); |
51 | uint32_t nand_device_init(void); | 51 | uint32_t nand_device_init(void); |
52 | void nand_set_active(void); | ||
53 | long nand_last_activity(void); | ||
52 | void nand_power_up(void); | 54 | void nand_power_up(void); |
53 | void nand_power_down(void); | 55 | void nand_power_down(void); |
54 | 56 | ||