diff options
Diffstat (limited to 'firmware')
-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 @@ #include "ftl-target.h" #include "nand-target.h" -/* for compatibility */ -long last_disk_activity = -1; - /** static, private data **/ static bool initialized = false; -static long nand_stack[20]; - /* API Functions */ - int nand_read_sectors(IF_MD2(int drive,) unsigned long start, int incount, void* inbuf) { - int rc = ftl_read(start, incount, inbuf); - last_disk_activity = current_tick; - return rc; + return ftl_read(start, incount, inbuf); } int nand_write_sectors(IF_MD2(int drive,) unsigned long start, int count, const void* outbuf) { - int rc = ftl_write(start, count, outbuf); - last_disk_activity = current_tick; - return rc; + return ftl_write(start, count, outbuf); } void nand_spindown(int seconds) @@ -73,7 +63,7 @@ void nand_sleepnow(void) void nand_spin(void) { - last_disk_activity = current_tick; + nand_set_active(); } void nand_enable(bool on) @@ -93,40 +83,22 @@ void nand_get_info(IF_MD2(int drive,) struct storage_info *info) long nand_last_disk_activity(void) { - return last_disk_activity; + return nand_last_activity(); } #ifdef HAVE_STORAGE_FLUSH int nand_flush(void) { - last_disk_activity = current_tick; int rc = ftl_sync(); if (rc != 0) panicf("Failed to unmount flash: %X", rc); return rc; } #endif -static void nand_thread(void) -{ - while (1) - { - if (TIME_AFTER(current_tick, last_disk_activity + HZ / 5)) - nand_power_down(); - sleep(HZ / 10); - } -} - int nand_init(void) { if (ftl_init()) return 1; - last_disk_activity = current_tick; - - create_thread(nand_thread, nand_stack, - sizeof(nand_stack), 0, "nand" - IF_PRIO(, PRIORITY_USER_INTERFACE) - IF_COP(, CPU)); - initialized = true; return 0; } 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 /* Pages that are still up to date in this block, i.e. need to be moved when this vBlock is deallocated. */ - uint16_t pagescurrent; + uint16_t pagescurrent; /* A flag whether all pages are still sequential in this block. Initialized to 1 on allocation, zeroed as soon as anything is @@ -112,9 +112,9 @@ struct ftl_cxt_type /* Count of currently free pages in the block pool */ uint16_t freecount; - + /* Index to the first free block in the blockpool ring buffer */ - uint16_t nextfreeidx; + uint16_t nextfreeidx; /* This is a counter that is used to better distribute block wear. It is incremented on every block erase, and if it @@ -129,7 +129,7 @@ struct ftl_cxt_type uint16_t blockpool[0x14]; /* Alignment to 32 bits */ - uint16_t field_36; + uint16_t field_36; /* vPages where the block map is stored */ uint32_t ftl_map_pages[8]; @@ -138,23 +138,23 @@ struct ftl_cxt_type uint8_t field_58[0x28]; /* vPages where the erase counters are stored */ - uint32_t ftl_erasectr_pages[8]; + uint32_t ftl_erasectr_pages[8]; /* Seems to be padding */ - uint8_t field_A0[0x70]; + uint8_t field_A0[0x70]; /* Pointer to ftl_map used by Whimory, not used by us */ - uint32_t ftl_map_ptr; + uint32_t ftl_map_ptr; /* Pointer to ftl_erasectr used by Whimory, not used by us */ - uint32_t ftl_erasectr_ptr; + uint32_t ftl_erasectr_ptr; /* Pointer to ftl_log used by Whimory, not used by us */ uint32_t ftl_log_ptr; /* Flag used to indicate that some erase counter pages should be committed as they were changed more than 100 times since the last commit. */ - uint32_t erasedirty; + uint32_t erasedirty; /* Seems to be unused */ uint16_t field_120; @@ -163,7 +163,7 @@ struct ftl_cxt_type counter pages. This is also a ring buffer, and the oldest page gets swapped with the least used page from the block pool ring buffer when a new one is allocated. */ - uint16_t ftlctrlblocks[3]; + uint16_t ftlctrlblocks[3]; /* The last used vPage number from ftlctrlblocks */ uint32_t ftlctrlpage; @@ -173,7 +173,7 @@ struct ftl_cxt_type uint32_t clean_flag; /* Seems to be unused, but gets loaded from flash by Whimory. */ - uint8_t field_130[0x15C]; + uint8_t field_130[0x15C]; } __attribute__((packed)) FTLCxtType; @@ -185,7 +185,7 @@ typedef struct ftl_vfl_cxt_type /* Cross-bank update sequence number, incremented on every VFL context commit on any bank. */ - uint32_t usn; + uint32_t usn; /* See ftl_cxt.ftlctrlblocks. This is stored to the VFL contexts in order to be able to find the most recent FTL context copy @@ -194,14 +194,14 @@ typedef struct ftl_vfl_cxt_type uint16_t ftlctrlblocks[3]; /* Alignment to 32 bits */ - uint8_t field_A[2]; + uint8_t field_A[2]; /* Decrementing update counter for VFL context commits per bank */ uint32_t updatecount; /* Number of the currently active VFL context block, it's an index into vflcxtblocks. */ - uint16_t activecxtblock; + uint16_t activecxtblock; /* Number of the first free page in the active FTL context block */ uint16_t nextcxtpage; @@ -217,31 +217,31 @@ typedef struct ftl_vfl_cxt_type uint16_t spareused; /* pBlock number of the first spare block */ - uint16_t firstspare; + uint16_t firstspare; /* Total number of spare blocks */ - uint16_t sparecount; + uint16_t sparecount; /* Block remap table. Contains the vBlock number the n-th spare block is used as a replacement for. 0 = unused, 0xFFFF = bad. */ - uint16_t remaptable[0x334]; + uint16_t remaptable[0x334]; /* Bad block table. Each bit represents 8 blocks. 1 = OK, 0 = Bad. If the entry is zero, you should look at the remap table to see if the block is remapped, and if yes, where the replacement is. */ - uint8_t bbt[0x11A]; + uint8_t bbt[0x11A]; /* pBlock numbers used to store the VFL context. This is a ring buffer. On a VFL context write, always 8 pages are written, and it passes if at least 4 of them can be read back. */ - uint16_t vflcxtblocks[4]; + uint16_t vflcxtblocks[4]; /* Blocks scheduled for remapping are stored at the end of the remap table. This is the first index used for them. */ uint16_t scheduledstart; /* Probably padding */ - uint8_t field_7AC[0x4C]; + uint8_t field_7AC[0x4C]; /* First checksum (addition) */ uint32_t checksum1; @@ -265,17 +265,17 @@ union ftl_spare_data_type /* The update sequence number of that page, copied from ftl_cxt.nextblockusn on write */ - uint32_t usn; + uint32_t usn; /* Seems to be unused */ - uint8_t field_8; + uint8_t field_8; /* Type field, 0x40 (data page) or 0x41 (last data page of block) */ - uint8_t type; + uint8_t type; /* ECC mark, usually 0xFF. If an error occurred while reading the page during a copying operation earlier, this will be 0x55. */ - uint8_t eccmark; + uint8_t eccmark; /* Seems to be unused */ uint8_t field_B; @@ -297,10 +297,10 @@ union ftl_spare_data_type /* Index of the thing inside the page, for example number / index of the map or erase counter page */ - uint16_t idx; + uint16_t idx; /* Seems to be unused */ - uint8_t field_6; + uint8_t field_6; /* Seems to be unused */ uint8_t field_7; @@ -318,7 +318,7 @@ union ftl_spare_data_type /* ECC mark, usually 0xFF. If an error occurred while reading the page during a copying operation earlier, this will be 0x55. */ - uint8_t eccmark; + uint8_t eccmark; /* Seems to be unused */ uint8_t field_B; @@ -339,14 +339,14 @@ struct ftl_trouble_type { /* vBlock number of the block giving trouble */ - uint16_t block; + uint16_t block; /* Bank of the block giving trouble */ - uint8_t bank; + uint8_t bank; /* Error counter, incremented by 3 on error, decremented by 1 on erase, remaping will be done when it reaches 6. */ - uint8_t errors; + uint8_t errors; } __attribute__((packed)); @@ -359,47 +359,57 @@ const struct nand_device_info_type* ftl_nand_type; uint32_t ftl_banks; /* Block map, used vor pBlock to vBlock mapping */ -uint16_t ftl_map[0x2000]; +uint16_t ftl_map[0x2000]; /* VFL context for each bank */ -struct ftl_vfl_cxt_type ftl_vfl_cxt[4]; +struct ftl_vfl_cxt_type ftl_vfl_cxt[4]; /* FTL context */ -struct ftl_cxt_type ftl_cxt; +struct ftl_cxt_type ftl_cxt; -/* Temporary data buffer for internal use by the FTL */ -uint8_t ftl_buffer[0x800] __attribute__((aligned(16))); +/* Temporary data buffers for internal use by the FTL */ +uint8_t ftl_buffer[0x800] __attribute__((aligned(16))); /* Temporary spare byte buffer for internal use by the FTL */ -union ftl_spare_data_type ftl_sparebuffer __attribute__((aligned(16))); +union ftl_spare_data_type ftl_sparebuffer __attribute__((aligned(16))); #ifndef FTL_READONLY /* Lowlevel BBT for each bank */ -uint8_t ftl_bbt[4][0x410]; +uint8_t ftl_bbt[4][0x410]; /* Erase countes for the vBlocks */ -uint16_t ftl_erasectr[0x2000]; +uint16_t ftl_erasectr[0x2000]; /* Used by ftl_log */ -uint16_t ftl_offsets[0x11][0x200]; +uint16_t ftl_offsets[0x11][0x200]; /* Structs keeping record of scattered page blocks */ struct ftl_log_type ftl_log[0x11]; /* Global cross-bank update sequence number of the VFL context */ -uint32_t ftl_vfl_usn; +uint32_t ftl_vfl_usn; /* Keeps track (temporarily) of troublesome blocks */ -struct ftl_trouble_type ftl_troublelog[5]; +struct ftl_trouble_type ftl_troublelog[5]; /* Counts erase counter page changes, after 100 of them the affected page will be committed to the flash. */ uint8_t ftl_erasectr_dirt[8]; +/* Buffer needed for copying pages around while moving or committing blocks. + This can't be shared with ftl_buffer, because this one could be overwritten + during the copying operation in order to e.g. commit a CXT. */ +uint8_t ftl_copybuffer[0x800] __attribute__((aligned(16))); + +/* Needed to store the old scattered page offsets in order to be able to roll + back if something fails while compacting a scattered page block. */ +uint16_t ftl_offsets_backup[0x200] __attribute__((aligned(16))); + #endif + static struct mutex ftl_mtx; @@ -413,28 +423,28 @@ uint32_t ftl_find_devinfo(uint32_t bank) - ((*ftl_nand_type).blocks / 10); uint32_t block, page, pagenum; for (block = (*ftl_nand_type).blocks - 1; block >= lowestBlock; block--) - { + { page = (*ftl_nand_type).pagesperblock - 8; for (; page < (*ftl_nand_type).pagesperblock; page++) - { - pagenum = block * (*ftl_nand_type).pagesperblock + page; + { + pagenum = block * (*ftl_nand_type).pagesperblock + page; if ((nand_read_page(bank, pagenum, ftl_buffer, &ftl_sparebuffer, 1, 0) & 0x11F) != 0) continue; - if (memcmp(ftl_buffer, "DEVICEINFOSIGN\0", 0x10) == 0) + if (memcmp(ftl_buffer, "DEVICEINFOSIGN\0", 0x10) == 0) return pagenum; - } - } - return 0; + } + } + return 0; } /* Checks if all banks have proper device info pages */ uint32_t ftl_has_devinfo(void) { - uint32_t i; - for (i = 0; i < ftl_banks; i++) if (ftl_find_devinfo(i) == 0) return 0; - return 1; + uint32_t i; + for (i = 0; i < ftl_banks; i++) if (ftl_find_devinfo(i) == 0) return 0; + return 1; } @@ -442,33 +452,33 @@ uint32_t ftl_has_devinfo(void) This is based on some cryptic disassembly and not fully understood yet. */ uint32_t ftl_load_bbt(uint32_t bank, uint8_t* bbt) { - uint32_t i, j; - uint32_t pagebase, page = ftl_find_devinfo(bank), page2; + uint32_t i, j; + uint32_t pagebase, page = ftl_find_devinfo(bank), page2; uint32_t unk1, unk2, unk3; - if (page == 0) return 1; + if (page == 0) return 1; pagebase = page & ~((*ftl_nand_type).pagesperblock - 1); if ((nand_read_page(bank, page, ftl_buffer, (uint32_t*)0, 1, 0) & 0x11F) != 0) return 1; - if (memcmp(&ftl_buffer[0x18], "BBT", 4) != 0) return 1; + if (memcmp(&ftl_buffer[0x18], "BBT", 4) != 0) return 1; unk1 = ((uint16_t*)ftl_buffer)[0x10]; unk2 = ((uint16_t*)ftl_buffer)[0x11]; unk3 = ((uint16_t*)ftl_buffer)[((uint32_t*)ftl_buffer)[4] * 0xC + 10] + ((uint16_t*)ftl_buffer)[((uint32_t*)ftl_buffer)[4] * 0xC + 11]; - for (i = 0; i < unk1; i++) - { - for (j = 0; ; j++) - { - page2 = unk2 + i + unk3 * j; - if (page2 >= (uint32_t)((*ftl_nand_type).pagesperblock - 8)) + for (i = 0; i < unk1; i++) + { + for (j = 0; ; j++) + { + page2 = unk2 + i + unk3 * j; + if (page2 >= (uint32_t)((*ftl_nand_type).pagesperblock - 8)) break; - if ((nand_read_page(bank, pagebase + page2, ftl_buffer, + if ((nand_read_page(bank, pagebase + page2, ftl_buffer, (void*)0, 1, 0) & 0x11F) == 0) { memcpy(bbt, ftl_buffer, 0x410); return 0; } - } - } + } + } return 1; } @@ -929,7 +939,7 @@ uint32_t ftl_vfl_open(void) { if (ftl_vfl_read_page(i, vflcxtblock[vflcxtidx], k, ftl_buffer, - &ftl_sparebuffer) != 0) + &ftl_sparebuffer) != 0) break; last = k; } @@ -1306,19 +1316,18 @@ uint32_t ftl_next_ctrl_pool_page(void) uint32_t ftl_copy_page(uint32_t source, uint32_t destination, uint32_t lpn, uint32_t type) { - uint8_t buffer[0x800]; uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; - uint32_t rc = ftl_vfl_read(source, buffer, + uint32_t rc = ftl_vfl_read(source, ftl_copybuffer, &ftl_sparebuffer, 1, 1) & 0x11F; memset(&ftl_sparebuffer, 0xFF, 0x40); ftl_sparebuffer.user.lpn = lpn; ftl_sparebuffer.user.usn = ++ftl_cxt.nextblockusn; ftl_sparebuffer.user.type = 0x40; - if ((rc & 2) != 0) memset(buffer, 0, 0x800); + if ((rc & 2) != 0) memset(ftl_copybuffer, 0, 0x800); else if (rc != 0) ftl_sparebuffer.user.eccmark = 0x55; if (type == 1 && destination % ppb == ppb - 1) ftl_sparebuffer.user.type = 0x41; - return ftl_vfl_write(destination, buffer, &ftl_sparebuffer); + return ftl_vfl_write(destination, ftl_copybuffer, &ftl_sparebuffer); } #endif @@ -1330,11 +1339,10 @@ uint32_t ftl_copy_block(uint32_t source, uint32_t destination) uint32_t i; uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; uint32_t error = 0; - uint8_t buffer[0x800]; ftl_cxt.nextblockusn++; for (i = 0; i < ppb; i++) { - uint32_t rc = ftl_read(source * ppb + i, 1, buffer); + uint32_t rc = ftl_read(source * ppb + i, 1, ftl_copybuffer); memset(&ftl_sparebuffer, 0xFF, 0x40); ftl_sparebuffer.user.lpn = source * ppb + i; ftl_sparebuffer.user.usn = ftl_cxt.nextblockusn; @@ -1342,7 +1350,7 @@ uint32_t ftl_copy_block(uint32_t source, uint32_t destination) if (rc != 0) ftl_sparebuffer.user.eccmark = 0x55; if (i == ppb - 1) ftl_sparebuffer.user.type = 0x41; if (ftl_vfl_write(destination * ppb + i, - buffer, &ftl_sparebuffer) != 0) + ftl_copybuffer, &ftl_sparebuffer) != 0) { error = 1; break; @@ -1383,7 +1391,6 @@ uint32_t ftl_compact_scattered(struct ftl_log_type* entry) uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; uint32_t error; struct ftl_log_type backup; - uint16_t backup_pageoffsets[0x200]; if ((*entry).pagescurrent == 0) { ftl_release_pool_block((*entry).scatteredvblock); @@ -1391,7 +1398,7 @@ uint32_t ftl_compact_scattered(struct ftl_log_type* entry) return 0; } backup = *entry; - memcpy(backup_pageoffsets, (*entry).pageoffsets, 0x400); + memcpy(ftl_offsets_backup, (*entry).pageoffsets, 0x400); for (i = 0; i < 4; i++) { uint32_t block = ftl_allocate_pool_block(); @@ -1425,7 +1432,7 @@ uint32_t ftl_compact_scattered(struct ftl_log_type* entry) break; } *entry = backup; - memcpy((*entry).pageoffsets, backup_pageoffsets, 0x400); + memcpy((*entry).pageoffsets, ftl_offsets_backup, 0x400); } return error; } @@ -1850,7 +1857,7 @@ uint32_t ftl_init(void) { mutex_init(&ftl_mtx); uint32_t i; - uint32_t result = 0; + uint32_t result = 0; uint32_t foundsignature, founddevinfo, blockwiped, repaired, skip; if (nand_device_init() != 0) //return 1; panicf("FTL: Lowlevel NAND driver init failed!"); @@ -1874,7 +1881,7 @@ uint32_t ftl_init(void) else if ((result & 2) != 2) blockwiped = 0; } - founddevinfo = ftl_has_devinfo(); + founddevinfo = ftl_has_devinfo(); repaired = 0; skip = 0; @@ -1904,7 +1911,7 @@ uint32_t ftl_init(void) (However there is curently no point in this, as iLoader would already fail if this would be the case.) - nand_block_erase(0, 0); + nand_block_erase(0, 0); */ 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]; uint8_t nand_tunk3[4]; uint32_t nand_type[4]; int nand_powered = 0; +long nand_last_activity_value = -1; +static long nand_stack[20]; static struct mutex nand_mtx; static struct wakeup nand_wakeup; @@ -186,7 +188,6 @@ uint32_t nand_reset(uint32_t bank) if (nand_send_cmd(NAND_CMD_RESET)) return 1; if (nand_wait_chip_ready(bank)) return 1; FMCTRL1 = FMCTRL1_CLEARRFIFO | FMCTRL1_CLEARWFIFO; - sleep(HZ / 100); /* Some chips seem to need this */ return 0; } @@ -301,10 +302,21 @@ uint32_t nand_get_chip_type(uint32_t bank) return nand_unlock(result); } +void nand_set_active(void) +{ + nand_last_activity_value = current_tick; +} + +long nand_last_activity(void) +{ + return nand_last_activity_value; +} + void nand_power_up(void) { uint32_t i; mutex_lock(&nand_mtx); + nand_last_activity_value = current_tick; PWRCONEXT &= ~0x40; PWRCON &= ~0x100000; PCON2 = 0x33333333; @@ -318,13 +330,16 @@ void nand_power_up(void) pmu_ldo_set_voltage(4, 0x15); pmu_ldo_power_on(4); sleep(HZ / 20); + nand_last_activity_value = current_tick; for (i = 0; i < 4; i++) nand_reset(i); nand_powered = 1; + nand_last_activity_value = current_tick; mutex_unlock(&nand_mtx); } void nand_power_down(void) { + if (!nand_powered) return; mutex_lock(&nand_mtx); pmu_ldo_power_off(4); PCON2 = 0x11111111; @@ -352,6 +367,7 @@ uint32_t nand_read_page(uint32_t bank, uint32_t page, void* databuffer, if (sparebuffer && !((uint32_t)sparebuffer & 0xf)) spare = (uint8_t*)sparebuffer; mutex_lock(&nand_mtx); + nand_last_activity_value = current_tick; led(true); if (!nand_powered) nand_power_up(); uint32_t rc, eccresult; @@ -409,6 +425,7 @@ uint32_t nand_write_page(uint32_t bank, uint32_t page, void* databuffer, if (sparebuffer && !((uint32_t)sparebuffer & 0xf)) spare = (uint8_t*)sparebuffer; mutex_lock(&nand_mtx); + nand_last_activity_value = current_tick; led(true); if (!nand_powered) nand_power_up(); if (sparebuffer) @@ -443,6 +460,7 @@ uint32_t nand_write_page(uint32_t bank, uint32_t page, void* databuffer, uint32_t nand_block_erase(uint32_t bank, uint32_t page) { mutex_lock(&nand_mtx); + nand_last_activity_value = current_tick; led(true); if (!nand_powered) nand_power_up(); nand_set_fmctrl0(bank, 0); @@ -463,6 +481,17 @@ const struct nand_device_info_type* nand_get_device_type(uint32_t bank) return &nand_deviceinfotable[nand_type[bank]]; } +static void nand_thread(void) +{ + while (1) + { + if (TIME_AFTER(current_tick, nand_last_activity_value + HZ / 5) + && nand_powered) + nand_power_down(); + sleep(HZ / 10); + } +} + uint32_t nand_device_init(void) { mutex_init(&nand_mtx); @@ -472,7 +501,7 @@ uint32_t nand_device_init(void) uint32_t type; uint32_t i, j; - if (!nand_powered) nand_power_up(); + nand_power_up(); for (i = 0; i < 4; i++) { nand_tunk1[i] = 7; @@ -497,5 +526,12 @@ uint32_t nand_device_init(void) nand_tunk3[i] = nand_deviceinfotable[nand_type[i]].tunk3; } if (nand_type[0] == 0xFFFFFFFF) return 1; + + nand_last_activity_value = current_tick; + create_thread(nand_thread, nand_stack, + sizeof(nand_stack), 0, "nand" + IF_PRIO(, PRIORITY_USER_INTERFACE) + IF_COP(, CPU)); + return 0; } 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); const struct nand_device_info_type* nand_get_device_type(uint32_t bank); uint32_t nand_reset(uint32_t bank); uint32_t nand_device_init(void); +void nand_set_active(void); +long nand_last_activity(void); void nand_power_up(void); void nand_power_down(void); |