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