1 /*
2 * RT-Thread Device Interface for uffs
3 */
4
5 #include <rtthread.h>
6 #include <rtdevice.h>
7 #include "dfs_uffs.h"
8
nand_init_flash(uffs_Device * dev)9 static int nand_init_flash(uffs_Device *dev)
10 {
11 return UFFS_FLASH_NO_ERR;
12 }
13
nand_release_flash(uffs_Device * dev)14 static int nand_release_flash(uffs_Device *dev)
15 {
16 return UFFS_FLASH_NO_ERR;
17 }
nand_erase_block(uffs_Device * dev,unsigned block)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)
nand_check_block(uffs_Device * dev,unsigned block)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
nand_mark_badblock(uffs_Device * dev,unsigned block)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)
nand_read_page(uffs_Device * dev,u32 block,u32 page,u8 * data,int data_len,u8 * ecc,rt_uint8_t * spare,int spare_len)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
nand_write_page(uffs_Device * dev,u32 block,u32 page,const u8 * data,int data_len,const u8 * spare,int spare_len)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
uffs_setup_storage(struct uffs_StorageAttrSt * attr,struct rt_mtd_nand_device * nand)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
WritePageWithLayout(uffs_Device * dev,u32 block,u32 page,const u8 * data,int data_len,const u8 * ecc,const uffs_TagStore * ts)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
ReadPageWithLayout(uffs_Device * dev,u32 block,u32 page,u8 * data,int data_len,u8 * ecc,uffs_TagStore * ts,u8 * ecc_store)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
uffs_setup_storage(struct uffs_StorageAttrSt * attr,struct rt_mtd_nand_device * nand)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