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