diff options
author | Michael Sparmann <theseven@rockbox.org> | 2010-03-13 21:41:14 +0000 |
---|---|---|
committer | Michael Sparmann <theseven@rockbox.org> | 2010-03-13 21:41:14 +0000 |
commit | cb41b2f2457015a3594eb63e917c5742564fc801 (patch) | |
tree | 96b40dafcbd1e82ad2c880b051f4a33ac51b1d53 /firmware | |
parent | af77b1842ced33af99318f5cb24cd24718c78639 (diff) |
Nano2G NAND parallel read support
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25153 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c b/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c index 07eb344040..7e455f044c 100644 --- a/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c +++ b/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c @@ -499,6 +499,138 @@ uint32_t nand_block_erase(uint32_t bank, uint32_t page) return nand_unlock(0); } +uint32_t nand_read_page_fast(uint32_t page, void* databuffer, + void* sparebuffer, uint32_t doecc, + uint32_t checkempty) +{ + uint32_t i, rc = 0; + if (((uint32_t)databuffer & 0xf) || ((uint32_t)sparebuffer & 0xf) + || !databuffer || !sparebuffer || !doecc) + { + for (i = 0; i < 4; i++) + { + if (nand_type[i] == 0xFFFFFFFF) continue; + void* databuf = (void*)0; + void* sparebuf = (void*)0; + if (databuffer) databuf = (void*)((uint32_t)databuffer + 0x800 * i); + if (sparebuffer) sparebuf = (void*)((uint32_t)sparebuffer + 0x40 * i); + uint32_t ret = nand_read_page(i, page, databuf, sparebuf, doecc, checkempty); + if (ret & 1) rc |= 1 << (i << 2); + if (ret & 2) rc |= 2 << (i << 2); + if (ret & 0x10) rc |= 4 << (i << 2); + if (ret & 0x100) rc |= 8 << (i << 2); + } + return rc; + } + mutex_lock(&nand_mtx); + nand_last_activity_value = current_tick; + led(true); + if (!nand_powered) nand_power_up(); + for (i = 0; i < 4; i++) + { + if (nand_type[i] == 0xFFFFFFFF) continue; + nand_set_fmctrl0(i, FMCTRL0_ENABLEDMA); + if (nand_send_cmd(NAND_CMD_READ)) + { + rc |= 1 << (i << 2); + continue; + } + if (nand_send_address(page, databuffer ? 0 : 0x800)) + { + rc |= 1 << (i << 2); + continue; + } + if (nand_send_cmd(NAND_CMD_READ2)) + { + rc |= 1 << (i << 2); + continue; + } + } + uint8_t status[4]; + for (i = 0; i < 4; i++) status[i] = (nand_type[i] == 0xFFFFFFFF); + if (!status[0]) + if (nand_wait_status_ready(0)) + status[0] = 1; + if (!status[0]) + if (nand_transfer_data(0, 0, databuffer, 0x800)) + status[0] = 1; + if (!status[0]) + if (nand_transfer_data(0, 0, sparebuffer, 0x40)) + status[0] = 1; + for (i = 1; i < 4; i++) + { + if (!status[i]) + if (nand_wait_status_ready(i)) + status[i] = 1; + if (!status[i]) + nand_transfer_data_start(i, 0, (void*)((uint32_t)databuffer + + 0x800 * i), 0x800); + if (!status[i - 1]) + { + memcpy(nand_ecc, (void*)((uint32_t)sparebuffer + 0x40 * (i - 1) + 0xC), 0x28); + ecc_start(3, (void*)((uint32_t)databuffer + + 0x800 * (i - 1)), nand_ecc, ECCCTRL_STARTDECODING); + } + if (!status[i]) + if (nand_transfer_data_collect(0)) + status[i] = 1; + if (!status[i]) + nand_transfer_data_start(i, 0, (void*)((uint32_t)sparebuffer + + 0x40 * i), 0x40); + if (!status[i - 1]) + if (ecc_collect() & 1) + status[i - 1] = 4; + if (!status[i - 1]) + { + memset(nand_ctrl, 0xFF, 0x200); + memcpy(nand_ctrl, (void*)((uint32_t)sparebuffer + 0x40 * (i - 1)), 0xC); + memcpy(nand_ecc, (void*)((uint32_t)sparebuffer + 0x40 * (i - 1) + 0x34), 0xC); + ecc_start(0, nand_ctrl, nand_ecc, ECCCTRL_STARTDECODING); + } + if (!status[i]) + if (nand_transfer_data_collect(0)) + status[i] = 1; + if (!status[i - 1]) + { + if (ecc_collect() & 1) + { + status[i - 1] |= 8; + memset((void*)((uint32_t)sparebuffer + 0x40 * (i - 1)), 0xFF, 0xC); + } + else memcpy((void*)((uint32_t)sparebuffer + 0x40 * (i - 1)), nand_ctrl, 0xC); + if (checkempty) + status[i - 1] |= nand_check_empty((void*)((uint32_t)sparebuffer + + 0x40 * (i - 1))) << 1; + } + } + if (!status[i - 1]) + { + memcpy(nand_ecc,(void*)((uint32_t)sparebuffer + 0x40 * (i - 1) + 0xC), 0x28); + if (ecc_decode(3, (void*)((uint32_t)databuffer + + 0x800 * (i - 1)), nand_ecc) & 1) + status[i - 1] = 4; + } + if (!status[i - 1]) + { + memset(nand_ctrl, 0xFF, 0x200); + memcpy(nand_ctrl, (void*)((uint32_t)sparebuffer + 0x40 * (i - 1)), 0xC); + memcpy(nand_ecc, (void*)((uint32_t)sparebuffer + 0x40 * (i - 1) + 0x34), 0xC); + if (ecc_decode(0, nand_ctrl, nand_ecc) & 1) + { + status[i - 1] |= 8; + memset((void*)((uint32_t)sparebuffer + 0x40 * (i - 1)), 0xFF, 0xC); + } + else memcpy((void*)((uint32_t)sparebuffer + 0x40 * (i - 1)), nand_ctrl, 0xC); + if (checkempty) + status[i - 1] |= nand_check_empty((void*)((uint32_t)sparebuffer + + 0x40 * (i - 1))) << 1; + } + for (i = 0; i < 4; i++) + if (nand_type[i] != 0xFFFFFFFF) + rc |= status[i] << (i << 2); + return nand_unlock(rc); +} + const struct nand_device_info_type* nand_get_device_type(uint32_t bank) { if (nand_type[bank] == 0xFFFFFFFF) |