uffs_nandif.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /*
  2. * RT-Thread Device Interface for uffs
  3. */
  4. #include <rtthread.h>
  5. #include <rtdevice.h>
  6. #include "dfs_uffs.h"
  7. static int nand_init_flash(uffs_Device *dev)
  8. {
  9. return UFFS_FLASH_NO_ERR;
  10. }
  11. static int nand_release_flash(uffs_Device *dev)
  12. {
  13. return UFFS_FLASH_NO_ERR;
  14. }
  15. static int nand_erase_block(uffs_Device *dev, unsigned block)
  16. {
  17. int res;
  18. res = rt_mtd_nand_erase_block(RT_MTD_NAND_DEVICE(dev->_private), block);
  19. return res == RT_EOK ? UFFS_FLASH_NO_ERR : UFFS_FLASH_IO_ERR;
  20. }
  21. #if defined(RT_UFFS_USE_CHECK_MARK_FUNCITON)
  22. static int nand_check_block(uffs_Device *dev, unsigned block)
  23. {
  24. int res;
  25. res = rt_mtd_nand_check_block(RT_MTD_NAND_DEVICE(dev->_private), block);
  26. return res == RT_EOK ? UFFS_FLASH_NO_ERR : UFFS_FLASH_BAD_BLK;
  27. }
  28. static int nand_mark_badblock(uffs_Device *dev, unsigned block)
  29. {
  30. int res;
  31. res = rt_mtd_nand_mark_badblock(RT_MTD_NAND_DEVICE(dev->_private), block);
  32. return res == RT_EOK ? UFFS_FLASH_NO_ERR : UFFS_FLASH_IO_ERR;
  33. }
  34. #endif
  35. #if (RT_CONFIG_UFFS_ECC_MODE == UFFS_ECC_NONE) || (RT_CONFIG_UFFS_ECC_MODE == UFFS_ECC_SOFT)
  36. static int nand_read_page(uffs_Device *dev,
  37. u32 block,
  38. u32 page,
  39. u8 *data,
  40. int data_len,
  41. u8 *ecc,
  42. rt_uint8_t *spare,
  43. int spare_len)
  44. {
  45. int res;
  46. page = block * dev->attr->pages_per_block + page;
  47. if (data == NULL && spare == NULL)
  48. {
  49. #if defined(RT_UFFS_USE_CHECK_MARK_FUNCITON)
  50. RT_ASSERT(0); //should not be here
  51. #else
  52. /* check block status: bad or good */
  53. rt_uint8_t spare[UFFS_MAX_SPARE_SIZE];
  54. rt_memset(spare, 0, UFFS_MAX_SPARE_SIZE);
  55. rt_mtd_nand_read(RT_MTD_NAND_DEVICE(dev->_private),
  56. page, RT_NULL, 0,
  57. spare, dev->attr->spare_size);//dev->mem.spare_data_size
  58. res = spare[dev->attr->block_status_offs] == 0xFF ?
  59. UFFS_FLASH_NO_ERR : UFFS_FLASH_BAD_BLK;
  60. return res;
  61. #endif
  62. }
  63. rt_mtd_nand_read(RT_MTD_NAND_DEVICE(dev->_private),
  64. page, data, data_len, spare, spare_len);
  65. return UFFS_FLASH_NO_ERR;
  66. }
  67. static int nand_write_page(uffs_Device *dev,
  68. u32 block,
  69. u32 page,
  70. const u8 *data,
  71. int data_len,
  72. const u8 *spare,
  73. int spare_len)
  74. {
  75. int res;
  76. RT_ASSERT(UFFS_MAX_SPARE_SIZE >= dev->attr->spare_size);
  77. page = block * dev->attr->pages_per_block + page;
  78. if (data == NULL && spare == NULL)
  79. {
  80. #if defined(RT_UFFS_USE_CHECK_MARK_FUNCITON)
  81. RT_ASSERT(0); //should not be here
  82. #else
  83. /* mark bad block */
  84. rt_uint8_t spare[UFFS_MAX_SPARE_SIZE];
  85. rt_memset(spare, 0xFF, UFFS_MAX_SPARE_SIZE);
  86. spare[dev->attr->block_status_offs] = 0x00;
  87. res = rt_mtd_nand_write(RT_MTD_NAND_DEVICE(dev->_private),
  88. page, RT_NULL, 0,
  89. spare, dev->attr->spare_size);//dev->mem.spare_data_size
  90. if (res != RT_EOK)
  91. goto __error;
  92. #endif
  93. }
  94. res = rt_mtd_nand_write(RT_MTD_NAND_DEVICE(dev->_private),
  95. page, data, data_len, spare, spare_len);
  96. if (res != RT_EOK)
  97. goto __error;
  98. return UFFS_FLASH_NO_ERR;
  99. __error:
  100. return UFFS_FLASH_IO_ERR;
  101. }
  102. const uffs_FlashOps nand_ops =
  103. {
  104. nand_init_flash, /* InitFlash() */
  105. nand_release_flash, /* ReleaseFlash() */
  106. nand_read_page, /* ReadPage() */
  107. NULL, /* ReadPageWithLayout */
  108. nand_write_page, /* WritePage() */
  109. NULL, /* WirtePageWithLayout */
  110. #if defined(RT_UFFS_USE_CHECK_MARK_FUNCITON)
  111. nand_check_block,
  112. nand_mark_badblock,
  113. #else
  114. NULL, /* IsBadBlock(), let UFFS take care of it. */
  115. NULL, /* MarkBadBlock(), let UFFS take care of it. */
  116. #endif
  117. nand_erase_block, /* EraseBlock() */
  118. };
  119. void uffs_setup_storage(struct uffs_StorageAttrSt *attr,
  120. struct rt_mtd_nand_device *nand)
  121. {
  122. rt_memset(attr, 0, sizeof(struct uffs_StorageAttrSt));
  123. // attr->total_blocks = nand->end_block - nand->start_block + 1;/* no use */
  124. attr->page_data_size = nand->page_size; /* page data size */
  125. attr->pages_per_block = nand->pages_per_block; /* pages per block */
  126. attr->spare_size = nand->oob_size; /* page spare size */
  127. attr->ecc_opt = RT_CONFIG_UFFS_ECC_MODE; /* ecc option */
  128. attr->ecc_size = 0; /* ecc size is 0 , the uffs will calculate the ecc size*/
  129. attr->block_status_offs = attr->ecc_size; /* indicate block bad or good, offset in spare */
  130. attr->layout_opt = RT_CONFIG_UFFS_LAYOUT; /* let UFFS do the spare layout */
  131. }
  132. #elif RT_CONFIG_UFFS_ECC_MODE == UFFS_ECC_HW_AUTO
  133. static int WritePageWithLayout(uffs_Device *dev,
  134. u32 block,
  135. u32 page,
  136. const u8 *data,
  137. int data_len,
  138. const u8 *ecc, //NULL
  139. const uffs_TagStore *ts)
  140. {
  141. int res;
  142. int spare_len;
  143. rt_uint8_t spare[UFFS_MAX_SPARE_SIZE];
  144. RT_ASSERT(UFFS_MAX_SPARE_SIZE >= dev->attr->spare_size);
  145. page = block * dev->attr->pages_per_block + page;
  146. spare_len = dev->mem.spare_data_size;
  147. if (data == NULL && ts == NULL)
  148. {
  149. #if defined(RT_UFFS_USE_CHECK_MARK_FUNCITON)
  150. RT_ASSERT(0); //should not be here
  151. #else
  152. /* mark bad block */
  153. rt_memset(spare, 0xFF, UFFS_MAX_SPARE_SIZE);
  154. spare[dev->attr->block_status_offs] = 0x00;
  155. res = rt_mtd_nand_write(RT_MTD_NAND_DEVICE(dev->_private),
  156. page, RT_NULL, 0,
  157. spare, dev->attr->spare_size);//dev->mem.spare_data_size
  158. if (res != RT_EOK)
  159. goto __error;
  160. dev->st.io_write++;
  161. return UFFS_FLASH_NO_ERR;
  162. #endif
  163. }
  164. if (data != NULL && data_len != 0)
  165. {
  166. RT_ASSERT(data_len == dev->attr->page_data_size);
  167. dev->st.page_write_count++;
  168. dev->st.io_write += data_len;
  169. }
  170. if (ts != RT_NULL)
  171. {
  172. uffs_FlashMakeSpare(dev, ts, RT_NULL, (u8 *)spare);
  173. dev->st.spare_write_count++;
  174. dev->st.io_write += spare_len;
  175. }
  176. res = rt_mtd_nand_write(RT_MTD_NAND_DEVICE(dev->_private),
  177. page, data, data_len, spare, spare_len);
  178. if (res != RT_EOK)
  179. goto __error;
  180. return UFFS_FLASH_NO_ERR;
  181. __error:
  182. return UFFS_FLASH_IO_ERR;
  183. }
  184. static URET ReadPageWithLayout(uffs_Device *dev,
  185. u32 block,
  186. u32 page,
  187. u8 *data,
  188. int data_len,
  189. u8 *ecc, //NULL
  190. uffs_TagStore *ts,
  191. u8 *ecc_store) //NULL
  192. {
  193. int res = UFFS_FLASH_NO_ERR;
  194. int spare_len;
  195. rt_uint8_t spare[UFFS_MAX_SPARE_SIZE];
  196. RT_ASSERT(UFFS_MAX_SPARE_SIZE >= dev->attr->spare_size);
  197. page = block * dev->attr->pages_per_block + page;
  198. spare_len = dev->mem.spare_data_size;
  199. if (data == RT_NULL && ts == RT_NULL)
  200. {
  201. #if defined(RT_UFFS_USE_CHECK_MARK_FUNCITON)
  202. RT_ASSERT(0); //should not be here
  203. #else
  204. /* check block good or bad */
  205. rt_mtd_nand_read(RT_MTD_NAND_DEVICE(dev->_private),
  206. page, RT_NULL, 0,
  207. spare, dev->attr->spare_size);//dev->mem.spare_data_size
  208. dev->st.io_read++;
  209. res = spare[dev->attr->block_status_offs] == 0xFF ?
  210. UFFS_FLASH_NO_ERR : UFFS_FLASH_BAD_BLK;
  211. return res;
  212. #endif
  213. }
  214. if (data != RT_NULL)
  215. {
  216. dev->st.io_read += data_len;
  217. dev->st.page_read_count++;
  218. }
  219. res = rt_mtd_nand_read(RT_MTD_NAND_DEVICE(dev->_private),
  220. page, data, data_len, spare, spare_len);
  221. if (res == 0)
  222. res = UFFS_FLASH_NO_ERR;
  223. else if (res == -1)
  224. {
  225. //TODO ecc correct, add code to use hardware do ecc correct
  226. res = UFFS_FLASH_ECC_OK;
  227. }
  228. else
  229. res = UFFS_FLASH_ECC_FAIL;
  230. if (ts != RT_NULL)
  231. {
  232. // unload ts and ecc from spare, you can modify it if you like
  233. uffs_FlashUnloadSpare(dev, (const u8 *)spare, ts, RT_NULL);
  234. if ((spare[spare_len - 1] == 0xFF) && (res == UFFS_FLASH_NO_ERR))
  235. res = UFFS_FLASH_NOT_SEALED;
  236. dev->st.io_read += spare_len;
  237. dev->st.spare_read_count++;
  238. }
  239. return res;
  240. }
  241. const uffs_FlashOps nand_ops =
  242. {
  243. nand_init_flash, /* InitFlash() */
  244. nand_release_flash, /* ReleaseFlash() */
  245. NULL, /* ReadPage() */
  246. ReadPageWithLayout, /* ReadPageWithLayout */
  247. NULL, /* WritePage() */
  248. WritePageWithLayout,/* WirtePageWithLayout */
  249. #if defined(RT_UFFS_USE_CHECK_MARK_FUNCITON)
  250. nand_check_block,
  251. nand_mark_badblock,
  252. #else
  253. NULL, /* IsBadBlock(), let UFFS take care of it. */
  254. NULL, /* MarkBadBlock(), let UFFS take care of it. */
  255. #endif
  256. nand_erase_block, /* EraseBlock() */
  257. };
  258. static rt_uint8_t hw_flash_data_layout[UFFS_SPARE_LAYOUT_SIZE] =
  259. {
  260. 0x05, 0x08, 0xFF, 0x00
  261. };
  262. static rt_uint8_t hw_flash_ecc_layout[UFFS_SPARE_LAYOUT_SIZE] =
  263. {
  264. 0x00, 0x04, 0xFF, 0x00
  265. };
  266. void uffs_setup_storage(struct uffs_StorageAttrSt *attr,
  267. struct rt_mtd_nand_device *nand)
  268. {
  269. rt_memset(attr, 0, sizeof(struct uffs_StorageAttrSt));
  270. // attr->total_blocks = nand->end_block - nand->start_block + 1;/* no use */
  271. attr->page_data_size = nand->page_size; /* page data size */
  272. attr->pages_per_block = nand->pages_per_block; /* pages per block */
  273. attr->spare_size = nand->oob_size; /* page spare size */
  274. attr->ecc_opt = RT_CONFIG_UFFS_ECC_MODE; /* ecc option */
  275. attr->ecc_size = nand->oob_size-nand->oob_free; /* ecc size */
  276. attr->block_status_offs = attr->ecc_size; /* indicate block bad or good, offset in spare */
  277. attr->layout_opt = RT_CONFIG_UFFS_LAYOUT; /* let UFFS do the spare layout */
  278. /* calculate the ecc layout array */
  279. hw_flash_data_layout[0] = attr->ecc_size + 1; /* ecc size + 1byte block status */
  280. hw_flash_data_layout[1] = 0x08;
  281. hw_flash_data_layout[2] = 0xFF;
  282. hw_flash_data_layout[3] = 0x00;
  283. hw_flash_ecc_layout[0] = 0;
  284. hw_flash_ecc_layout[1] = attr->ecc_size;
  285. hw_flash_ecc_layout[2] = 0xFF;
  286. hw_flash_ecc_layout[3] = 0x00;
  287. /* initialize _uffs_data_layout and _uffs_ecc_layout */
  288. rt_memcpy(attr->_uffs_data_layout, hw_flash_data_layout, UFFS_SPARE_LAYOUT_SIZE);
  289. rt_memcpy(attr->_uffs_ecc_layout, hw_flash_ecc_layout, UFFS_SPARE_LAYOUT_SIZE);
  290. attr->data_layout = attr->_uffs_data_layout;
  291. attr->ecc_layout = attr->_uffs_ecc_layout;
  292. }
  293. #endif