diff options
author | Michael Sparmann <theseven@rockbox.org> | 2009-11-08 14:55:30 +0000 |
---|---|---|
committer | Michael Sparmann <theseven@rockbox.org> | 2009-11-08 14:55:30 +0000 |
commit | 64ac121e2c36427490b4ae791a779006101bfbf4 (patch) | |
tree | fbdedfe5194831c877f09022fbc6b9c8d68401f2 | |
parent | 40638bf2c73623bd00a4d669d3d0cd2eb01ff587 (diff) | |
download | rockbox-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.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 | ||