| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 | /* * RT-Thread Device Interface for uffs */#include <rtthread.h>#include <rtdevice.h>#include "dfs_uffs.h"static int nand_init_flash(uffs_Device *dev){    return UFFS_FLASH_NO_ERR;}static int nand_release_flash(uffs_Device *dev){    return UFFS_FLASH_NO_ERR;}static int nand_erase_block(uffs_Device *dev, unsigned block){    int res;    res = rt_mtd_nand_erase_block(RT_MTD_NAND_DEVICE(dev->_private), block);    return res == RT_EOK ? UFFS_FLASH_NO_ERR : UFFS_FLASH_IO_ERR;}#if defined(RT_UFFS_USE_CHECK_MARK_FUNCITON)static int nand_check_block(uffs_Device *dev, unsigned block){    int res;    res = rt_mtd_nand_check_block(RT_MTD_NAND_DEVICE(dev->_private), block);    return res == RT_EOK ? UFFS_FLASH_NO_ERR : UFFS_FLASH_BAD_BLK;}static int nand_mark_badblock(uffs_Device *dev, unsigned block){    int res;    res = rt_mtd_nand_mark_badblock(RT_MTD_NAND_DEVICE(dev->_private), block);    return res == RT_EOK ? UFFS_FLASH_NO_ERR : UFFS_FLASH_IO_ERR;}#endif#if (RT_CONFIG_UFFS_ECC_MODE == UFFS_ECC_NONE) || (RT_CONFIG_UFFS_ECC_MODE == UFFS_ECC_SOFT)static int nand_read_page(uffs_Device *dev,                          u32          block,                          u32          page,                          u8          *data,                          int          data_len,                          u8          *ecc,                          rt_uint8_t  *spare,                          int          spare_len){    int res;    page = block * dev->attr->pages_per_block + page;    if (data == NULL && spare == NULL)    {#if defined(RT_UFFS_USE_CHECK_MARK_FUNCITON)        RT_ASSERT(0); //should not be here#else        /* check block status: bad or good */        rt_uint8_t spare[UFFS_MAX_SPARE_SIZE];        rt_memset(spare, 0, UFFS_MAX_SPARE_SIZE);        rt_mtd_nand_read(RT_MTD_NAND_DEVICE(dev->_private),                         page, RT_NULL, 0,                         spare, dev->attr->spare_size);//dev->mem.spare_data_size        res = spare[dev->attr->block_status_offs] == 0xFF ?                               UFFS_FLASH_NO_ERR : UFFS_FLASH_BAD_BLK;        return res;#endif    }    rt_mtd_nand_read(RT_MTD_NAND_DEVICE(dev->_private),                     page, data, data_len, spare, spare_len);    return UFFS_FLASH_NO_ERR;}static int nand_write_page(uffs_Device *dev,                           u32          block,                           u32          page,                           const u8    *data,                           int          data_len,                           const u8    *spare,                           int          spare_len){    int res;    RT_ASSERT(UFFS_MAX_SPARE_SIZE >= dev->attr->spare_size);    page = block * dev->attr->pages_per_block + page;    if (data == NULL && spare == NULL)    {#if defined(RT_UFFS_USE_CHECK_MARK_FUNCITON)        RT_ASSERT(0); //should not be here#else        /* mark bad block  */        rt_uint8_t spare[UFFS_MAX_SPARE_SIZE];        rt_memset(spare, 0xFF, UFFS_MAX_SPARE_SIZE);        spare[dev->attr->block_status_offs] =  0x00;        res = rt_mtd_nand_write(RT_MTD_NAND_DEVICE(dev->_private),                                page, RT_NULL, 0,                                spare, dev->attr->spare_size);//dev->mem.spare_data_size        if (res != RT_EOK)            goto __error;#endif    }    res = rt_mtd_nand_write(RT_MTD_NAND_DEVICE(dev->_private),                           page,  data, data_len, spare, spare_len);    if (res != RT_EOK)        goto __error;    return UFFS_FLASH_NO_ERR;__error:    return UFFS_FLASH_IO_ERR;}const uffs_FlashOps nand_ops ={    nand_init_flash,    /* InitFlash() */    nand_release_flash, /* ReleaseFlash() */    nand_read_page,     /* ReadPage() */    NULL,               /* ReadPageWithLayout */    nand_write_page,    /* WritePage() */    NULL,               /* WritePageWithLayout */#if defined(RT_UFFS_USE_CHECK_MARK_FUNCITON)    nand_check_block,    nand_mark_badblock,#else    NULL,               /* IsBadBlock(), let UFFS take care of it. */    NULL,               /* MarkBadBlock(), let UFFS take care of it. */#endif    nand_erase_block,   /* EraseBlock() */};void uffs_setup_storage(struct uffs_StorageAttrSt *attr,                        struct rt_mtd_nand_device *nand){    rt_memset(attr, 0, sizeof(struct uffs_StorageAttrSt));//  attr->total_blocks = nand->end_block - nand->start_block + 1;/* no use */    attr->page_data_size = nand->page_size;                /* page data size */    attr->pages_per_block = nand->pages_per_block;         /* pages per block */    attr->spare_size = nand->oob_size;                     /* page spare size */    attr->ecc_opt = RT_CONFIG_UFFS_ECC_MODE;               /* ecc option */    attr->ecc_size = 0;                                    /* ecc size is 0 , the uffs will calculate the ecc size*/    attr->block_status_offs = attr->ecc_size;              /* indicate block bad or good, offset in spare */    attr->layout_opt = RT_CONFIG_UFFS_LAYOUT;              /* let UFFS do the spare layout */}#elif  RT_CONFIG_UFFS_ECC_MODE == UFFS_ECC_HW_AUTOstatic int WritePageWithLayout(uffs_Device         *dev,                               u32                  block,                               u32                  page,                               const u8            *data,                               int                  data_len,                               const u8            *ecc,  //NULL                               const uffs_TagStore *ts){    int res;    int spare_len;    rt_uint8_t spare[UFFS_MAX_SPARE_SIZE];    RT_ASSERT(UFFS_MAX_SPARE_SIZE >= dev->attr->spare_size);    page = block * dev->attr->pages_per_block + page;    spare_len = dev->mem.spare_data_size;    if (data == NULL && ts == NULL)    {#if defined(RT_UFFS_USE_CHECK_MARK_FUNCITON)        RT_ASSERT(0); //should not be here#else        /* mark bad block  */        rt_memset(spare, 0xFF, UFFS_MAX_SPARE_SIZE);        spare[dev->attr->block_status_offs] =  0x00;        res = rt_mtd_nand_write(RT_MTD_NAND_DEVICE(dev->_private),                                page, RT_NULL, 0,                                spare, dev->attr->spare_size);//dev->mem.spare_data_size        if (res != RT_EOK)            goto __error;        dev->st.io_write++;        return UFFS_FLASH_NO_ERR;#endif    }    if (data != NULL && data_len != 0)    {        RT_ASSERT(data_len == dev->attr->page_data_size);        dev->st.page_write_count++;        dev->st.io_write += data_len;    }    if (ts != RT_NULL)    {        uffs_FlashMakeSpare(dev, ts, RT_NULL, (u8 *)spare);        dev->st.spare_write_count++;        dev->st.io_write += spare_len;    }    res = rt_mtd_nand_write(RT_MTD_NAND_DEVICE(dev->_private),                            page, data, data_len, spare, spare_len);    if (res != RT_EOK)        goto __error;    return UFFS_FLASH_NO_ERR;__error:    return UFFS_FLASH_IO_ERR;}static URET ReadPageWithLayout(uffs_Device   *dev,                               u32            block,                               u32            page,                               u8            *data,                               int            data_len,                               u8            *ecc,              //NULL                               uffs_TagStore *ts,                               u8            *ecc_store)        //NULL{    int res = UFFS_FLASH_NO_ERR;    int spare_len;    rt_uint8_t spare[UFFS_MAX_SPARE_SIZE];    RT_ASSERT(UFFS_MAX_SPARE_SIZE >= dev->attr->spare_size);    page = block * dev->attr->pages_per_block + page;    spare_len = dev->mem.spare_data_size;    if (data == RT_NULL && ts == RT_NULL)    {#if defined(RT_UFFS_USE_CHECK_MARK_FUNCITON)        RT_ASSERT(0); //should not be here#else        /* check block good or bad */        rt_mtd_nand_read(RT_MTD_NAND_DEVICE(dev->_private),                         page, RT_NULL, 0,                         spare, dev->attr->spare_size);//dev->mem.spare_data_size        dev->st.io_read++;        res = spare[dev->attr->block_status_offs] == 0xFF ?                               UFFS_FLASH_NO_ERR : UFFS_FLASH_BAD_BLK;        return res;#endif    }    if (data != RT_NULL)    {        dev->st.io_read += data_len;        dev->st.page_read_count++;    }    res = rt_mtd_nand_read(RT_MTD_NAND_DEVICE(dev->_private),                           page, data, data_len, spare, spare_len);    if (res == 0)        res = UFFS_FLASH_NO_ERR;    else if (res == -1)    {        //TODO ecc correct, add code to use hardware do ecc correct        res = UFFS_FLASH_ECC_OK;    }    else        res = UFFS_FLASH_ECC_FAIL;    if (ts != RT_NULL)    {        // unload ts and ecc from spare, you can modify it if you like        uffs_FlashUnloadSpare(dev, (const u8 *)spare, ts, RT_NULL);        if ((spare[spare_len - 1] == 0xFF) && (res == UFFS_FLASH_NO_ERR))            res = UFFS_FLASH_NOT_SEALED;        dev->st.io_read += spare_len;        dev->st.spare_read_count++;    }    return res;}const uffs_FlashOps nand_ops ={    nand_init_flash,    /* InitFlash() */    nand_release_flash, /* ReleaseFlash() */    NULL,               /* ReadPage() */    ReadPageWithLayout, /* ReadPageWithLayout */    NULL,               /* WritePage() */    WritePageWithLayout,/* WritePageWithLayout */#if defined(RT_UFFS_USE_CHECK_MARK_FUNCITON)    nand_check_block,    nand_mark_badblock,#else    NULL,               /* IsBadBlock(), let UFFS take care of it. */    NULL,               /* MarkBadBlock(), let UFFS take care of it. */#endif    nand_erase_block,   /* EraseBlock() */};static rt_uint8_t hw_flash_data_layout[UFFS_SPARE_LAYOUT_SIZE] ={    0x05, 0x08, 0xFF, 0x00};static rt_uint8_t hw_flash_ecc_layout[UFFS_SPARE_LAYOUT_SIZE] ={    0x00, 0x04, 0xFF, 0x00};void uffs_setup_storage(struct uffs_StorageAttrSt *attr,                        struct rt_mtd_nand_device *nand){    rt_memset(attr, 0, sizeof(struct uffs_StorageAttrSt));//  attr->total_blocks = nand->end_block - nand->start_block + 1;/* no use */    attr->page_data_size = nand->page_size;                /* page data size */    attr->pages_per_block = nand->pages_per_block;         /* pages per block */    attr->spare_size = nand->oob_size;                     /* page spare size */    attr->ecc_opt = RT_CONFIG_UFFS_ECC_MODE;               /* ecc option */    attr->ecc_size = nand->oob_size-nand->oob_free;        /* ecc size */    attr->block_status_offs = attr->ecc_size;              /* indicate block bad or good, offset in spare */    attr->layout_opt = RT_CONFIG_UFFS_LAYOUT;              /* let UFFS do the spare layout */    /* calculate the ecc layout array */    hw_flash_data_layout[0] = attr->ecc_size + 1; /* ecc size + 1byte block status */    hw_flash_data_layout[1] = 0x08;    hw_flash_data_layout[2] = 0xFF;    hw_flash_data_layout[3] = 0x00;    hw_flash_ecc_layout[0] = 0;    hw_flash_ecc_layout[1] = attr->ecc_size;    hw_flash_ecc_layout[2] = 0xFF;    hw_flash_ecc_layout[3] = 0x00;    /* initialize  _uffs_data_layout and _uffs_ecc_layout */    rt_memcpy(attr->_uffs_data_layout, hw_flash_data_layout, UFFS_SPARE_LAYOUT_SIZE);    rt_memcpy(attr->_uffs_ecc_layout, hw_flash_ecc_layout, UFFS_SPARE_LAYOUT_SIZE);    attr->data_layout = attr->_uffs_data_layout;    attr->ecc_layout = attr->_uffs_ecc_layout;}#endif
 |