diff options
author | Michael Sparmann <theseven@rockbox.org> | 2009-10-05 14:42:25 +0000 |
---|---|---|
committer | Michael Sparmann <theseven@rockbox.org> | 2009-10-05 14:42:25 +0000 |
commit | 79bf2da1ef6f8f16c44ba8fa6d71ea6870a19767 (patch) | |
tree | dc2d6425d7702e8d7a5b04e585dde625d428d6f5 /firmware/target/arm/s5l8700 | |
parent | 112bc15d65f133876654b45090618c3cd1da148c (diff) | |
download | rockbox-79bf2da1ef6f8f16c44ba8fa6d71ea6870a19767.tar.gz rockbox-79bf2da1ef6f8f16c44ba8fa6d71ea6870a19767.zip |
iPod Nano 2G NAND/ECC driver and FTL improvements (still polling)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@22958 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm/s5l8700')
-rw-r--r-- | firmware/target/arm/s5l8700/ipodnano2g/ftl-nano2g.c | 96 | ||||
-rw-r--r-- | firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c | 131 |
2 files changed, 176 insertions, 51 deletions
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/ftl-nano2g.c b/firmware/target/arm/s5l8700/ipodnano2g/ftl-nano2g.c index bbef9d2920..56c7554640 100644 --- a/firmware/target/arm/s5l8700/ipodnano2g/ftl-nano2g.c +++ b/firmware/target/arm/s5l8700/ipodnano2g/ftl-nano2g.c | |||
@@ -26,6 +26,35 @@ | |||
26 | #include <nand-target.h> | 26 | #include <nand-target.h> |
27 | #include <ftl-target.h> | 27 | #include <ftl-target.h> |
28 | #include <string.h> | 28 | #include <string.h> |
29 | #include "kernel.h" | ||
30 | #include "panic.h" | ||
31 | |||
32 | |||
33 | |||
34 | //#define FTL_FORCEMOUNT | ||
35 | |||
36 | |||
37 | |||
38 | #ifdef FTL_FORCEMOUNT | ||
39 | #ifndef FTL_READONLY | ||
40 | #define FTL_READONLY | ||
41 | #endif | ||
42 | #endif | ||
43 | |||
44 | |||
45 | #ifdef FTL_READONLY | ||
46 | uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer) | ||
47 | { | ||
48 | (void)sector; | ||
49 | (void)count; | ||
50 | (void)buffer; | ||
51 | return 1; | ||
52 | } | ||
53 | uint32_t ftl_sync(void) | ||
54 | { | ||
55 | return 0; | ||
56 | } | ||
57 | #endif | ||
29 | 58 | ||
30 | 59 | ||
31 | 60 | ||
@@ -371,6 +400,8 @@ uint8_t ftl_erasectr_dirt[8]; | |||
371 | 400 | ||
372 | #endif | 401 | #endif |
373 | 402 | ||
403 | static struct mutex ftl_mtx; | ||
404 | |||
374 | 405 | ||
375 | 406 | ||
376 | /* Finds a device info page for the specified bank and returns its number. | 407 | /* Finds a device info page for the specified bank and returns its number. |
@@ -653,6 +684,7 @@ void ftl_vfl_schedule_block_for_remap(uint32_t bank, uint32_t block) | |||
653 | { | 684 | { |
654 | if (ftl_vfl_check_remap_scheduled(bank, block) == 1) | 685 | if (ftl_vfl_check_remap_scheduled(bank, block) == 1) |
655 | return; | 686 | return; |
687 | panicf("FTL: Scheduling bank %d block %d for remap!", bank, block); | ||
656 | if (ftl_vfl_cxt[bank].scheduledstart == ftl_vfl_cxt[bank].spareused) | 688 | if (ftl_vfl_cxt[bank].scheduledstart == ftl_vfl_cxt[bank].spareused) |
657 | return; | 689 | return; |
658 | ftl_vfl_cxt[bank].remaptable[--ftl_vfl_cxt[bank].scheduledstart] = block; | 690 | ftl_vfl_cxt[bank].remaptable[--ftl_vfl_cxt[bank].scheduledstart] = block; |
@@ -738,6 +770,7 @@ uint32_t ftl_vfl_remap_block(uint32_t bank, uint32_t block) | |||
738 | { | 770 | { |
739 | uint32_t i; | 771 | uint32_t i; |
740 | uint32_t newblock = 0, newidx; | 772 | uint32_t newblock = 0, newidx; |
773 | panicf("FTL: Remapping bank %d block %d!", bank, block); | ||
741 | if (bank >= ftl_banks || block >= (*ftl_nand_type).blocks) return 0; | 774 | if (bank >= ftl_banks || block >= (*ftl_nand_type).blocks) return 0; |
742 | for (i = 0; i < ftl_vfl_cxt[bank].sparecount; i++) | 775 | for (i = 0; i < ftl_vfl_cxt[bank].sparecount; i++) |
743 | if (ftl_vfl_cxt[bank].remaptable[i] == 0) | 776 | if (ftl_vfl_cxt[bank].remaptable[i] == 0) |
@@ -949,7 +982,9 @@ uint32_t ftl_open(void) | |||
949 | else | 982 | else |
950 | { | 983 | { |
951 | /* This will trip if there was an unclean unmount before. */ | 984 | /* This will trip if there was an unclean unmount before. */ |
985 | #ifndef FTL_FORCEMOUNT | ||
952 | break; | 986 | break; |
987 | #endif | ||
953 | } | 988 | } |
954 | } | 989 | } |
955 | 990 | ||
@@ -1030,6 +1065,8 @@ uint32_t ftl_read(uint32_t sector, uint32_t count, void* buffer) | |||
1030 | 1065 | ||
1031 | if (count == 0) return 0; | 1066 | if (count == 0) return 0; |
1032 | 1067 | ||
1068 | mutex_lock(&ftl_mtx); | ||
1069 | |||
1033 | for (i = 0; i < count; i++) | 1070 | for (i = 0; i < count; i++) |
1034 | { | 1071 | { |
1035 | uint32_t block = (sector + i) / ppb; | 1072 | uint32_t block = (sector + i) / ppb; |
@@ -1054,6 +1091,9 @@ uint32_t ftl_read(uint32_t sector, uint32_t count, void* buffer) | |||
1054 | memset(&((uint8_t*)buffer)[i << 11], 0, 0x800); | 1091 | memset(&((uint8_t*)buffer)[i << 11], 0, 0x800); |
1055 | } | 1092 | } |
1056 | } | 1093 | } |
1094 | |||
1095 | mutex_unlock(&ftl_mtx); | ||
1096 | |||
1057 | return error; | 1097 | return error; |
1058 | } | 1098 | } |
1059 | 1099 | ||
@@ -1609,11 +1649,17 @@ uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer) | |||
1609 | 1649 | ||
1610 | if (count == 0) return 0; | 1650 | if (count == 0) return 0; |
1611 | 1651 | ||
1652 | mutex_lock(&ftl_mtx); | ||
1653 | |||
1612 | if (ftl_cxt.clean_flag == 1) | 1654 | if (ftl_cxt.clean_flag == 1) |
1613 | { | 1655 | { |
1614 | for (i = 0; i < 3; i++) | 1656 | for (i = 0; i < 3; i++) |
1615 | { | 1657 | { |
1616 | if (ftl_next_ctrl_pool_page() != 0) return 1; | 1658 | if (ftl_next_ctrl_pool_page() != 0) |
1659 | { | ||
1660 | mutex_unlock(&ftl_mtx); | ||
1661 | return 1; | ||
1662 | } | ||
1617 | memset(ftl_buffer, 0xFF, 0x800); | 1663 | memset(ftl_buffer, 0xFF, 0x800); |
1618 | memset(&ftl_sparebuffer, 0xFF, 0x40); | 1664 | memset(&ftl_sparebuffer, 0xFF, 0x40); |
1619 | ftl_sparebuffer.meta.usn = ftl_cxt.usn; | 1665 | ftl_sparebuffer.meta.usn = ftl_cxt.usn; |
@@ -1622,7 +1668,11 @@ uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer) | |||
1622 | &ftl_sparebuffer) == 0) | 1668 | &ftl_sparebuffer) == 0) |
1623 | break; | 1669 | break; |
1624 | } | 1670 | } |
1625 | if (i == 3) return 1; | 1671 | if (i == 3) |
1672 | { | ||
1673 | mutex_unlock(&ftl_mtx); | ||
1674 | return 1; | ||
1675 | } | ||
1626 | ftl_cxt.clean_flag = 0; | 1676 | ftl_cxt.clean_flag = 0; |
1627 | } | 1677 | } |
1628 | 1678 | ||
@@ -1632,7 +1682,11 @@ uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer) | |||
1632 | uint32_t page = (sector + i) % ppb; | 1682 | uint32_t page = (sector + i) % ppb; |
1633 | 1683 | ||
1634 | struct ftl_log_type* logentry = ftl_allocate_log_entry(block); | 1684 | struct ftl_log_type* logentry = ftl_allocate_log_entry(block); |
1635 | if (logentry == (struct ftl_log_type*)0) return 1; | 1685 | if (logentry == (struct ftl_log_type*)0) |
1686 | { | ||
1687 | mutex_unlock(&ftl_mtx); | ||
1688 | return 1; | ||
1689 | } | ||
1636 | if (page == 0 && count - i >= ppb) | 1690 | if (page == 0 && count - i >= ppb) |
1637 | { | 1691 | { |
1638 | uint32_t vblock = (*logentry).scatteredvblock; | 1692 | uint32_t vblock = (*logentry).scatteredvblock; |
@@ -1641,7 +1695,11 @@ uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer) | |||
1641 | { | 1695 | { |
1642 | ftl_release_pool_block(vblock); | 1696 | ftl_release_pool_block(vblock); |
1643 | vblock = ftl_allocate_pool_block(); | 1697 | vblock = ftl_allocate_pool_block(); |
1644 | if (vblock == 0) return 1; | 1698 | if (vblock == 0) |
1699 | { | ||
1700 | mutex_unlock(&ftl_mtx); | ||
1701 | return 1; | ||
1702 | } | ||
1645 | } | 1703 | } |
1646 | ftl_cxt.nextblockusn++; | 1704 | ftl_cxt.nextblockusn++; |
1647 | for (j = 0; j < ppb; j++) | 1705 | for (j = 0; j < ppb; j++) |
@@ -1665,7 +1723,11 @@ uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer) | |||
1665 | { | 1723 | { |
1666 | ftl_remove_scattered_block(logentry); | 1724 | ftl_remove_scattered_block(logentry); |
1667 | logentry = ftl_allocate_log_entry(block); | 1725 | logentry = ftl_allocate_log_entry(block); |
1668 | if (logentry == (struct ftl_log_type*)0) return 1; | 1726 | if (logentry == (struct ftl_log_type*)0) |
1727 | { | ||
1728 | mutex_unlock(&ftl_mtx); | ||
1729 | return 1; | ||
1730 | } | ||
1669 | } | 1731 | } |
1670 | memset(&ftl_sparebuffer, 0xFF, 0x40); | 1732 | memset(&ftl_sparebuffer, 0xFF, 0x40); |
1671 | ftl_sparebuffer.user.lpn = sector + i; | 1733 | ftl_sparebuffer.user.lpn = sector + i; |
@@ -1699,6 +1761,7 @@ uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer) | |||
1699 | ftl_save_erasectr_page(i); | 1761 | ftl_save_erasectr_page(i); |
1700 | } | 1762 | } |
1701 | } | 1763 | } |
1764 | mutex_unlock(&ftl_mtx); | ||
1702 | return 0; | 1765 | return 0; |
1703 | } | 1766 | } |
1704 | #endif | 1767 | #endif |
@@ -1745,6 +1808,7 @@ uint32_t ftl_sync(void) | |||
1745 | which will just do nothing if everything was already clean. */ | 1808 | which will just do nothing if everything was already clean. */ |
1746 | uint32_t ftl_init(void) | 1809 | uint32_t ftl_init(void) |
1747 | { | 1810 | { |
1811 | mutex_init(&ftl_mtx); | ||
1748 | uint32_t i; | 1812 | uint32_t i; |
1749 | uint32_t result = 0; | 1813 | uint32_t result = 0; |
1750 | uint32_t foundsignature, founddevinfo, blockwiped, repaired, skip; | 1814 | uint32_t foundsignature, founddevinfo, blockwiped, repaired, skip; |
@@ -1755,6 +1819,7 @@ uint32_t ftl_init(void) | |||
1755 | ftl_nand_type = nand_get_device_type(0); | 1819 | ftl_nand_type = nand_get_device_type(0); |
1756 | foundsignature = 0; | 1820 | foundsignature = 0; |
1757 | blockwiped = 1; | 1821 | blockwiped = 1; |
1822 | mutex_unlock(&ftl_mtx); | ||
1758 | for (i = 0; i < (*ftl_nand_type).pagesperblock; i++) | 1823 | for (i = 0; i < (*ftl_nand_type).pagesperblock; i++) |
1759 | { | 1824 | { |
1760 | result = nand_read_page(0, i, ftl_buffer, (uint32_t*)0, 1, 1); | 1825 | result = nand_read_page(0, i, ftl_buffer, (uint32_t*)0, 1, 1); |
@@ -1772,10 +1837,23 @@ uint32_t ftl_init(void) | |||
1772 | 1837 | ||
1773 | repaired = 0; | 1838 | repaired = 0; |
1774 | skip = 0; | 1839 | skip = 0; |
1775 | if (founddevinfo == 0) return 1; | 1840 | if (founddevinfo == 0) |
1776 | if (foundsignature != 0 && (result & 0x11F) != 0) return 1; | 1841 | { |
1842 | mutex_unlock(&ftl_mtx); | ||
1843 | return 1; | ||
1844 | } | ||
1845 | if (foundsignature != 0 && (result & 0x11F) != 0) | ||
1846 | { | ||
1847 | mutex_unlock(&ftl_mtx); | ||
1848 | return 1; | ||
1849 | } | ||
1777 | if (ftl_vfl_open() == 0) | 1850 | if (ftl_vfl_open() == 0) |
1778 | if (ftl_open() == 0) return 0; | 1851 | if (ftl_open() == 0) |
1852 | { | ||
1853 | mutex_unlock(&ftl_mtx); | ||
1854 | return 0; | ||
1855 | } | ||
1856 | |||
1779 | 1857 | ||
1780 | /* Something went terribly wrong. We may want to allow the user to erase | 1858 | /* Something went terribly wrong. We may want to allow the user to erase |
1781 | block zero in that condition, to make norboot reinitialize the FTL. | 1859 | block zero in that condition, to make norboot reinitialize the FTL. |
@@ -1785,5 +1863,7 @@ uint32_t ftl_init(void) | |||
1785 | nand_block_erase(0, 0); | 1863 | nand_block_erase(0, 0); |
1786 | */ | 1864 | */ |
1787 | 1865 | ||
1866 | |||
1867 | mutex_unlock(&ftl_mtx); | ||
1788 | return 1; | 1868 | return 1; |
1789 | } | 1869 | } |
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c b/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c index ba83ab6df2..91d8827b50 100644 --- a/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c +++ b/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include "config.h" | 23 | #include "config.h" |
24 | #include "system.h" | 24 | #include "system.h" |
25 | #include "kernel.h" | ||
25 | #include "cpu.h" | 26 | #include "cpu.h" |
26 | #include "inttypes.h" | 27 | #include "inttypes.h" |
27 | #include "nand-target.h" | 28 | #include "nand-target.h" |
@@ -84,6 +85,11 @@ uint8_t nand_tunk2[4]; | |||
84 | uint8_t nand_tunk3[4]; | 85 | uint8_t nand_tunk3[4]; |
85 | uint32_t nand_type[4]; | 86 | uint32_t nand_type[4]; |
86 | 87 | ||
88 | static struct mutex nand_mtx; | ||
89 | static struct wakeup nand_wakeup; | ||
90 | static struct mutex ecc_mtx; | ||
91 | static struct wakeup ecc_wakeup; | ||
92 | |||
87 | static uint8_t nand_aligned_data[0x800] __attribute__((aligned(32))); | 93 | static uint8_t nand_aligned_data[0x800] __attribute__((aligned(32))); |
88 | static uint8_t nand_aligned_ctrl[0x200] __attribute__((aligned(32))); | 94 | static uint8_t nand_aligned_ctrl[0x200] __attribute__((aligned(32))); |
89 | static uint8_t nand_aligned_spare[0x40] __attribute__((aligned(32))); | 95 | static uint8_t nand_aligned_spare[0x40] __attribute__((aligned(32))); |
@@ -98,35 +104,60 @@ static uint8_t nand_aligned_ecc[0x28] __attribute__((aligned(32))); | |||
98 | ((uint8_t*)(((uint32_t)nand_aligned_ecc) | 0x40000000)) | 104 | ((uint8_t*)(((uint32_t)nand_aligned_ecc) | 0x40000000)) |
99 | 105 | ||
100 | 106 | ||
107 | uint32_t nand_unlock(uint32_t rc) | ||
108 | { | ||
109 | mutex_unlock(&nand_mtx); | ||
110 | return rc; | ||
111 | } | ||
112 | |||
113 | uint32_t ecc_unlock(uint32_t rc) | ||
114 | { | ||
115 | mutex_unlock(&ecc_mtx); | ||
116 | return rc; | ||
117 | } | ||
118 | |||
119 | uint32_t nand_timeout(long timeout) | ||
120 | { | ||
121 | if (TIME_AFTER(current_tick, timeout)) return 1; | ||
122 | else | ||
123 | { | ||
124 | yield(); | ||
125 | return 0; | ||
126 | } | ||
127 | } | ||
128 | |||
101 | uint32_t nand_wait_rbbdone(void) | 129 | uint32_t nand_wait_rbbdone(void) |
102 | { | 130 | { |
103 | uint32_t timeout = 0x40000; | 131 | long timeout = current_tick + HZ / 1; |
104 | while ((FMCSTAT & FMCSTAT_RBBDONE) == 0) if (timeout-- == 0) return 1; | 132 | while ((FMCSTAT & FMCSTAT_RBBDONE) == 0) |
133 | if (nand_timeout(timeout)) return 1; | ||
105 | FMCSTAT = FMCSTAT_RBBDONE; | 134 | FMCSTAT = FMCSTAT_RBBDONE; |
106 | return 0; | 135 | return 0; |
107 | } | 136 | } |
108 | 137 | ||
109 | uint32_t nand_wait_cmddone(void) | 138 | uint32_t nand_wait_cmddone(void) |
110 | { | 139 | { |
111 | uint32_t timeout = 0x40000; | 140 | long timeout = current_tick + HZ / 1; |
112 | while ((FMCSTAT & FMCSTAT_CMDDONE) == 0) if (timeout-- == 0) return 1; | 141 | while ((FMCSTAT & FMCSTAT_CMDDONE) == 0) |
142 | if (nand_timeout(timeout)) return 1; | ||
113 | FMCSTAT = FMCSTAT_CMDDONE; | 143 | FMCSTAT = FMCSTAT_CMDDONE; |
114 | return 0; | 144 | return 0; |
115 | } | 145 | } |
116 | 146 | ||
117 | uint32_t nand_wait_addrdone(void) | 147 | uint32_t nand_wait_addrdone(void) |
118 | { | 148 | { |
119 | uint32_t timeout = 0x40000; | 149 | long timeout = current_tick + HZ / 1; |
120 | while ((FMCSTAT & FMCSTAT_ADDRDONE) == 0) if (timeout-- == 0) return 1; | 150 | while ((FMCSTAT & FMCSTAT_ADDRDONE) == 0) |
151 | if (nand_timeout(timeout)) return 1; | ||
121 | FMCSTAT = FMCSTAT_ADDRDONE; | 152 | FMCSTAT = FMCSTAT_ADDRDONE; |
122 | return 0; | 153 | return 0; |
123 | } | 154 | } |
124 | 155 | ||
125 | uint32_t nand_wait_chip_ready(uint32_t bank) | 156 | uint32_t nand_wait_chip_ready(uint32_t bank) |
126 | { | 157 | { |
127 | uint32_t timeout = 0x40000; | 158 | long timeout = current_tick + HZ / 1; |
128 | while ((FMCSTAT & (FMCSTAT_BANK0READY << bank)) == 0) | 159 | while ((FMCSTAT & (FMCSTAT_BANK0READY << bank)) == 0) |
129 | if (timeout-- == 0) return 1; | 160 | if (nand_timeout(timeout)) return 1; |
130 | FMCSTAT = (FMCSTAT_BANK0READY << bank); | 161 | FMCSTAT = (FMCSTAT_BANK0READY << bank); |
131 | return 0; | 162 | return 0; |
132 | } | 163 | } |
@@ -163,7 +194,7 @@ uint32_t nand_reset(uint32_t bank) | |||
163 | 194 | ||
164 | uint32_t nand_wait_status_ready(uint32_t bank) | 195 | uint32_t nand_wait_status_ready(uint32_t bank) |
165 | { | 196 | { |
166 | uint32_t timeout = 0x4000; | 197 | long timeout = current_tick + HZ / 1; |
167 | nand_set_fmctrl0(bank, 0); | 198 | nand_set_fmctrl0(bank, 0); |
168 | if ((FMCSTAT & (FMCSTAT_BANK0READY << bank)) != 0) | 199 | if ((FMCSTAT & (FMCSTAT_BANK0READY << bank)) != 0) |
169 | FMCSTAT = (FMCSTAT_BANK0READY << bank); | 200 | FMCSTAT = (FMCSTAT_BANK0READY << bank); |
@@ -171,7 +202,7 @@ uint32_t nand_wait_status_ready(uint32_t bank) | |||
171 | if (nand_send_cmd(NAND_CMD_GET_STATUS) != 0) return 1; | 202 | if (nand_send_cmd(NAND_CMD_GET_STATUS) != 0) return 1; |
172 | while (1) | 203 | while (1) |
173 | { | 204 | { |
174 | if (timeout-- == 0) return 1; | 205 | if (nand_timeout(timeout)) return 1; |
175 | FMDNUM = 0; | 206 | FMDNUM = 0; |
176 | FMCTRL1 = FMCTRL1_DOREADDATA; | 207 | FMCTRL1 = FMCTRL1_DOREADDATA; |
177 | if (nand_wait_addrdone() != 0) return 1; | 208 | if (nand_wait_addrdone() != 0) return 1; |
@@ -185,7 +216,7 @@ uint32_t nand_wait_status_ready(uint32_t bank) | |||
185 | uint32_t nand_transfer_data(uint32_t bank, uint32_t direction, | 216 | uint32_t nand_transfer_data(uint32_t bank, uint32_t direction, |
186 | void* buffer, uint32_t size) | 217 | void* buffer, uint32_t size) |
187 | { | 218 | { |
188 | uint32_t timeout = 0x40000; | 219 | long timeout = current_tick + HZ / 1; |
189 | nand_set_fmctrl0(bank, FMCTRL0_ENABLEDMA); | 220 | nand_set_fmctrl0(bank, FMCTRL0_ENABLEDMA); |
190 | FMDNUM = size - 1; | 221 | FMDNUM = size - 1; |
191 | FMCTRL1 = FMCTRL1_DOREADDATA << direction; | 222 | FMCTRL1 = FMCTRL1_DOREADDATA << direction; |
@@ -199,7 +230,7 @@ uint32_t nand_transfer_data(uint32_t bank, uint32_t direction, | |||
199 | DMATCNT3 = (size >> 4) - 1; | 230 | DMATCNT3 = (size >> 4) - 1; |
200 | DMACOM3 = 4; | 231 | DMACOM3 = 4; |
201 | while ((DMAALLST & DMAALLST_DMABUSY3) != 0) | 232 | while ((DMAALLST & DMAALLST_DMABUSY3) != 0) |
202 | if (timeout-- == 0) return 1; | 233 | if (nand_timeout(timeout)) return 1; |
203 | if (nand_wait_addrdone() != 0) return 1; | 234 | if (nand_wait_addrdone() != 0) return 1; |
204 | if (direction == 0) FMCTRL1 = FMCTRL1_CLEARRFIFO | FMCTRL1_CLEARWFIFO; | 235 | if (direction == 0) FMCTRL1 = FMCTRL1_CLEARRFIFO | FMCTRL1_CLEARWFIFO; |
205 | return 0; | 236 | return 0; |
@@ -207,32 +238,36 @@ uint32_t nand_transfer_data(uint32_t bank, uint32_t direction, | |||
207 | 238 | ||
208 | uint32_t ecc_decode(uint32_t size, void* databuffer, void* sparebuffer) | 239 | uint32_t ecc_decode(uint32_t size, void* databuffer, void* sparebuffer) |
209 | { | 240 | { |
210 | uint32_t timeout = 0x40000; | 241 | mutex_lock(&ecc_mtx); |
242 | long timeout = current_tick + HZ / 1; | ||
211 | ECC_INT_CLR = 1; | 243 | ECC_INT_CLR = 1; |
212 | SRCPND = INTMSK_ECC; | 244 | SRCPND = INTMSK_ECC; |
213 | ECC_UNK1 = size; | 245 | ECC_UNK1 = size; |
214 | ECC_DATA_PTR = (uint32_t)databuffer; | 246 | ECC_DATA_PTR = (uint32_t)databuffer; |
215 | ECC_SPARE_PTR = (uint32_t)sparebuffer; | 247 | ECC_SPARE_PTR = (uint32_t)sparebuffer; |
216 | ECC_CTRL = ECCCTRL_STARTDECODING; | 248 | ECC_CTRL = ECCCTRL_STARTDECODING; |
217 | while ((SRCPND & INTMSK_ECC) == 0) if (timeout-- == 0) return 1; | 249 | while ((SRCPND & INTMSK_ECC) == 0) |
250 | if (nand_timeout(timeout)) return ecc_unlock(1); | ||
218 | ECC_INT_CLR = 1; | 251 | ECC_INT_CLR = 1; |
219 | SRCPND = INTMSK_ECC; | 252 | SRCPND = INTMSK_ECC; |
220 | return ECC_RESULT; | 253 | return ecc_unlock(ECC_RESULT); |
221 | } | 254 | } |
222 | 255 | ||
223 | uint32_t ecc_encode(uint32_t size, void* databuffer, void* sparebuffer) | 256 | uint32_t ecc_encode(uint32_t size, void* databuffer, void* sparebuffer) |
224 | { | 257 | { |
225 | uint32_t timeout = 0x40000; | 258 | mutex_lock(&ecc_mtx); |
259 | long timeout = current_tick + HZ / 1; | ||
226 | ECC_INT_CLR = 1; | 260 | ECC_INT_CLR = 1; |
227 | SRCPND = INTMSK_ECC; | 261 | SRCPND = INTMSK_ECC; |
228 | ECC_UNK1 = size; | 262 | ECC_UNK1 = size; |
229 | ECC_DATA_PTR = (uint32_t)databuffer; | 263 | ECC_DATA_PTR = (uint32_t)databuffer; |
230 | ECC_SPARE_PTR = (uint32_t)sparebuffer; | 264 | ECC_SPARE_PTR = (uint32_t)sparebuffer; |
231 | ECC_CTRL = ECCCTRL_STARTENCODING; | 265 | ECC_CTRL = ECCCTRL_STARTENCODING; |
232 | while ((SRCPND & INTMSK_ECC) == 0) if (timeout-- == 0) return 1; | 266 | while ((SRCPND & INTMSK_ECC) == 0) |
267 | if (nand_timeout(timeout)) return ecc_unlock(1); | ||
233 | ECC_INT_CLR = 1; | 268 | ECC_INT_CLR = 1; |
234 | SRCPND = INTMSK_ECC; | 269 | SRCPND = INTMSK_ECC; |
235 | return 0; | 270 | return ecc_unlock(0); |
236 | } | 271 | } |
237 | 272 | ||
238 | uint32_t nand_check_empty(uint8_t* buffer) | 273 | uint32_t nand_check_empty(uint8_t* buffer) |
@@ -246,51 +281,53 @@ uint32_t nand_check_empty(uint8_t* buffer) | |||
246 | 281 | ||
247 | uint32_t nand_get_chip_type(uint32_t bank) | 282 | uint32_t nand_get_chip_type(uint32_t bank) |
248 | { | 283 | { |
284 | mutex_lock(&nand_mtx); | ||
249 | uint32_t result; | 285 | uint32_t result; |
250 | if (nand_reset(bank) != 0) return 0xFFFFFFFF; | 286 | if (nand_reset(bank) != 0) return nand_unlock(0xFFFFFFFF); |
251 | if (nand_send_cmd(0x90) != 0) return 0xFFFFFFFF; | 287 | if (nand_send_cmd(0x90) != 0) return nand_unlock(0xFFFFFFFF); |
252 | FMANUM = 0; | 288 | FMANUM = 0; |
253 | FMADDR0 = 0; | 289 | FMADDR0 = 0; |
254 | FMCTRL1 = FMCTRL1_DOTRANSADDR; | 290 | FMCTRL1 = FMCTRL1_DOTRANSADDR; |
255 | if (nand_wait_cmddone() != 0) return 0xFFFFFFFF; | 291 | if (nand_wait_cmddone() != 0) return nand_unlock(0xFFFFFFFF); |
256 | FMDNUM = 4; | 292 | FMDNUM = 4; |
257 | FMCTRL1 = FMCTRL1_DOREADDATA; | 293 | FMCTRL1 = FMCTRL1_DOREADDATA; |
258 | if (nand_wait_addrdone() != 0) return 0xFFFFFFFF; | 294 | if (nand_wait_addrdone() != 0) return nand_unlock(0xFFFFFFFF); |
259 | result = FMFIFO; | 295 | result = FMFIFO; |
260 | FMCTRL1 = FMCTRL1_CLEARRFIFO | FMCTRL1_CLEARWFIFO; | 296 | FMCTRL1 = FMCTRL1_CLEARRFIFO | FMCTRL1_CLEARWFIFO; |
261 | return result; | 297 | return nand_unlock(result); |
262 | } | 298 | } |
263 | 299 | ||
264 | uint32_t nand_read_page(uint32_t bank, uint32_t page, void* databuffer, | 300 | uint32_t nand_read_page(uint32_t bank, uint32_t page, void* databuffer, |
265 | void* sparebuffer, uint32_t doecc, | 301 | void* sparebuffer, uint32_t doecc, |
266 | uint32_t checkempty) | 302 | uint32_t checkempty) |
267 | { | 303 | { |
304 | mutex_lock(&nand_mtx); | ||
268 | uint32_t rc, eccresult; | 305 | uint32_t rc, eccresult; |
269 | nand_set_fmctrl0(bank, FMCTRL0_ENABLEDMA); | 306 | nand_set_fmctrl0(bank, FMCTRL0_ENABLEDMA); |
270 | if (nand_send_cmd(NAND_CMD_READ) != 0) return 1; | 307 | if (nand_send_cmd(NAND_CMD_READ) != 0) return nand_unlock(1); |
271 | if (nand_send_address(page, (databuffer == 0) ? 0x800 : 0) != 0) | 308 | if (nand_send_address(page, (databuffer == 0) ? 0x800 : 0) != 0) |
272 | return 1; | 309 | return nand_unlock(1); |
273 | if (nand_send_cmd(NAND_CMD_READ2) != 0) return 1; | 310 | if (nand_send_cmd(NAND_CMD_READ2) != 0) return nand_unlock(1); |
274 | if (nand_wait_status_ready(bank) != 0) return 1; | 311 | if (nand_wait_status_ready(bank) != 0) return nand_unlock(1); |
275 | if (databuffer != 0) | 312 | if (databuffer != 0) |
276 | if (nand_transfer_data(bank, 0, nand_uncached_data, 0x800) != 0) | 313 | if (nand_transfer_data(bank, 0, nand_uncached_data, 0x800) != 0) |
277 | return 1; | 314 | return nand_unlock(1); |
278 | if (doecc == 0) | 315 | if (doecc == 0) |
279 | { | 316 | { |
280 | memcpy(databuffer, nand_uncached_data, 0x800); | 317 | memcpy(databuffer, nand_uncached_data, 0x800); |
281 | if (sparebuffer != 0) | 318 | if (sparebuffer != 0) |
282 | { | 319 | { |
283 | if (nand_transfer_data(bank, 0, nand_uncached_spare, 0x40) != 0) | 320 | if (nand_transfer_data(bank, 0, nand_uncached_spare, 0x40) != 0) |
284 | return 1; | 321 | return nand_unlock(1); |
285 | memcpy(sparebuffer, nand_uncached_spare, 0x800); | 322 | memcpy(sparebuffer, nand_uncached_spare, 0x800); |
286 | if (checkempty != 0) | 323 | if (checkempty != 0) |
287 | return nand_check_empty((uint8_t*)sparebuffer) << 1; | 324 | return nand_check_empty((uint8_t*)sparebuffer) << 1; |
288 | } | 325 | } |
289 | return 0; | 326 | return nand_unlock(0); |
290 | } | 327 | } |
291 | rc = 0; | 328 | rc = 0; |
292 | if (nand_transfer_data(bank, 0, nand_uncached_spare, 0x40) != 0) | 329 | if (nand_transfer_data(bank, 0, nand_uncached_spare, 0x40) != 0) |
293 | return 1; | 330 | return nand_unlock(1); |
294 | memcpy(nand_uncached_ecc, &nand_uncached_spare[0xC], 0x28); | 331 | memcpy(nand_uncached_ecc, &nand_uncached_spare[0xC], 0x28); |
295 | rc |= (ecc_decode(3, nand_uncached_data, nand_uncached_ecc) & 0xF) << 4; | 332 | rc |= (ecc_decode(3, nand_uncached_data, nand_uncached_ecc) & 0xF) << 4; |
296 | if (databuffer != 0) memcpy(databuffer, nand_uncached_data, 0x800); | 333 | if (databuffer != 0) memcpy(databuffer, nand_uncached_data, 0x800); |
@@ -307,51 +344,54 @@ uint32_t nand_read_page(uint32_t bank, uint32_t page, void* databuffer, | |||
307 | } | 344 | } |
308 | if (checkempty != 0) rc |= nand_check_empty(nand_uncached_spare) << 1; | 345 | if (checkempty != 0) rc |= nand_check_empty(nand_uncached_spare) << 1; |
309 | 346 | ||
310 | return rc; | 347 | return nand_unlock(rc); |
311 | } | 348 | } |
312 | 349 | ||
313 | uint32_t nand_write_page(uint32_t bank, uint32_t page, void* databuffer, | 350 | uint32_t nand_write_page(uint32_t bank, uint32_t page, void* databuffer, |
314 | void* sparebuffer, uint32_t doecc) | 351 | void* sparebuffer, uint32_t doecc) |
315 | { | 352 | { |
353 | mutex_lock(&nand_mtx); | ||
316 | if (sparebuffer != 0) memcpy(nand_uncached_spare, sparebuffer, 0x40); | 354 | if (sparebuffer != 0) memcpy(nand_uncached_spare, sparebuffer, 0x40); |
317 | else memset(nand_uncached_spare, 0xFF, 0x40); | 355 | else memset(nand_uncached_spare, 0xFF, 0x40); |
318 | if (doecc != 0) | 356 | if (doecc != 0) |
319 | { | 357 | { |
320 | memcpy(nand_uncached_data, databuffer, 0x800); | 358 | memcpy(nand_uncached_data, databuffer, 0x800); |
321 | if (ecc_encode(3, nand_uncached_data, nand_uncached_ecc) != 0) | 359 | if (ecc_encode(3, nand_uncached_data, nand_uncached_ecc) != 0) |
322 | return 1; | 360 | return nand_unlock(1); |
323 | memcpy(&nand_uncached_spare[0xC], nand_uncached_ecc, 0x28); | 361 | memcpy(&nand_uncached_spare[0xC], nand_uncached_ecc, 0x28); |
324 | memset(nand_uncached_ctrl, 0xFF, 0x200); | 362 | memset(nand_uncached_ctrl, 0xFF, 0x200); |
325 | memcpy(nand_uncached_ctrl, nand_uncached_spare, 0xC); | 363 | memcpy(nand_uncached_ctrl, nand_uncached_spare, 0xC); |
326 | if (ecc_encode(0, nand_uncached_ctrl, nand_uncached_ecc) != 0) | 364 | if (ecc_encode(0, nand_uncached_ctrl, nand_uncached_ecc) != 0) |
327 | return 1; | 365 | return nand_unlock(1); |
328 | memcpy(&nand_uncached_spare[0x34], nand_uncached_ecc, 0xC); | 366 | memcpy(&nand_uncached_spare[0x34], nand_uncached_ecc, 0xC); |
329 | } | 367 | } |
330 | nand_set_fmctrl0(bank, FMCTRL0_ENABLEDMA); | 368 | nand_set_fmctrl0(bank, FMCTRL0_ENABLEDMA); |
331 | if (nand_send_cmd(NAND_CMD_PROGRAM) != 0) | 369 | if (nand_send_cmd(NAND_CMD_PROGRAM) != 0) |
332 | return 1; | 370 | return nand_unlock(1); |
333 | if (nand_send_address(page, (databuffer == 0) ? 0x800 : 0) != 0) | 371 | if (nand_send_address(page, (databuffer == 0) ? 0x800 : 0) != 0) |
334 | return 1; | 372 | return nand_unlock(1); |
335 | if (databuffer != 0) | 373 | if (databuffer != 0) |
336 | if (nand_transfer_data(bank, 1, nand_uncached_data, 0x800) != 0) | 374 | if (nand_transfer_data(bank, 1, nand_uncached_data, 0x800) != 0) |
337 | return 1; | 375 | return nand_unlock(1); |
338 | if (sparebuffer != 0 || doecc != 0) | 376 | if (sparebuffer != 0 || doecc != 0) |
339 | if (nand_transfer_data(bank, 1, nand_uncached_spare, 0x40) != 0) | 377 | if (nand_transfer_data(bank, 1, nand_uncached_spare, 0x40) != 0) |
340 | return 1; | 378 | return nand_unlock(1); |
341 | if (nand_send_cmd(NAND_CMD_PROGCNFRM) != 0) return 1; | 379 | if (nand_send_cmd(NAND_CMD_PROGCNFRM) != 0) return nand_unlock(1); |
342 | return nand_wait_status_ready(bank); | 380 | return nand_wait_status_ready(bank); |
343 | } | 381 | } |
344 | 382 | ||
345 | uint32_t nand_block_erase(uint32_t bank, uint32_t page) | 383 | uint32_t nand_block_erase(uint32_t bank, uint32_t page) |
346 | { | 384 | { |
385 | mutex_lock(&nand_mtx); | ||
347 | nand_set_fmctrl0(bank, 0); | 386 | nand_set_fmctrl0(bank, 0); |
348 | if (nand_send_cmd(NAND_CMD_BLOCKERASE) != 0) return 1; | 387 | if (nand_send_cmd(NAND_CMD_BLOCKERASE) != 0) return nand_unlock(1); |
349 | FMANUM = 2; | 388 | FMANUM = 2; |
350 | FMADDR0 = page; | 389 | FMADDR0 = page; |
351 | FMCTRL1 = FMCTRL1_DOTRANSADDR; | 390 | FMCTRL1 = FMCTRL1_DOTRANSADDR; |
352 | if (nand_wait_cmddone() != 0) return 1; | 391 | if (nand_wait_cmddone() != 0) return nand_unlock(1); |
353 | if (nand_send_cmd(NAND_CMD_ERASECNFRM) != 0) return 1; | 392 | if (nand_send_cmd(NAND_CMD_ERASECNFRM) != 0) return nand_unlock(1); |
354 | return nand_wait_status_ready(bank); | 393 | if (nand_wait_status_ready(bank) != 0) return nand_unlock(1); |
394 | return nand_unlock(0); | ||
355 | } | 395 | } |
356 | 396 | ||
357 | const struct nand_device_info_type* nand_get_device_type(uint32_t bank) | 397 | const struct nand_device_info_type* nand_get_device_type(uint32_t bank) |
@@ -363,6 +403,11 @@ const struct nand_device_info_type* nand_get_device_type(uint32_t bank) | |||
363 | 403 | ||
364 | uint32_t nand_device_init(void) | 404 | uint32_t nand_device_init(void) |
365 | { | 405 | { |
406 | mutex_init(&nand_mtx); | ||
407 | wakeup_init(&nand_wakeup); | ||
408 | mutex_init(&ecc_mtx); | ||
409 | wakeup_init(&ecc_wakeup); | ||
410 | |||
366 | uint32_t type; | 411 | uint32_t type; |
367 | uint32_t i, j; | 412 | uint32_t i, j; |
368 | PCON2 = 0x33333333; | 413 | PCON2 = 0x33333333; |