mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-09 21:25:19 -05:00
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
This commit is contained in:
parent
40638bf2c7
commit
64ac121e2c
4 changed files with 129 additions and 112 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -367,7 +367,7 @@ struct ftl_vfl_cxt_type ftl_vfl_cxt[4];
|
|||
/* FTL context */
|
||||
struct ftl_cxt_type ftl_cxt;
|
||||
|
||||
/* Temporary data buffer for internal use by the FTL */
|
||||
/* 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 */
|
||||
|
|
@ -398,8 +398,18 @@ struct ftl_trouble_type ftl_troublelog[5];
|
|||
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;
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue