From 06c95d6819416e1814b7040505af3b1471bbfb40 Mon Sep 17 00:00:00 2001 From: theseven Date: Sun, 8 Nov 2009 14:55:30 +0000 Subject: [PATCH] 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 --- firmware/target/arm/s5l8700/ata-nand-s5l8700.c | 36 +---- .../target/arm/s5l8700/ipodnano2g/ftl-nano2g.c | 163 +++++++++++---------- .../target/arm/s5l8700/ipodnano2g/nand-nano2g.c | 40 ++++- .../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 850700141..ad87d9ea7 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 2c11ab534..0ce268ac3 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 ba10e4f9f..73673cdd6 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 a1559e936..51b215a24 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); -- 2.11.4.GIT