xref: /nrf52832-nimble/rt-thread/components/dfs/filesystems/uffs/uffs_nandif.c (revision 104654410c56c573564690304ae786df310c91fc)
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