uffs_nandif.c 11.3 KB
Newer Older
M
Ming, Bai 已提交
1 2 3 4 5 6 7 8 9 10
/*
 * RT-Thread Device Interface for uffs
 */

#include <rtthread.h>
#include <rtdevice.h>
#include "dfs_uffs.h"

static int nand_init_flash(uffs_Device *dev)
{
Y
yiyue.fang 已提交
11
    return UFFS_FLASH_NO_ERR;
M
Ming, Bai 已提交
12 13 14 15
}

static int nand_release_flash(uffs_Device *dev)
{
Y
yiyue.fang 已提交
16
    return UFFS_FLASH_NO_ERR;
M
Ming, Bai 已提交
17 18 19
}
static int nand_erase_block(uffs_Device *dev, unsigned block)
{
Y
yiyue.fang 已提交
20 21 22 23 24
    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;
M
Ming, Bai 已提交
25 26 27 28 29
}

#if defined(RT_UFFS_USE_CHECK_MARK_FUNCITON)
static int nand_check_block(uffs_Device *dev, unsigned block)
{
Y
yiyue.fang 已提交
30 31 32 33 34
    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;
M
Ming, Bai 已提交
35 36 37 38
}

static int nand_mark_badblock(uffs_Device *dev, unsigned block)
{
Y
yiyue.fang 已提交
39 40 41 42 43
    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;
M
Ming, Bai 已提交
44 45 46 47
}
#endif

#if (RT_CONFIG_UFFS_ECC_MODE == UFFS_ECC_NONE) || (RT_CONFIG_UFFS_ECC_MODE == UFFS_ECC_SOFT)
Y
yiyue.fang 已提交
48 49 50 51 52 53 54 55
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)
M
Ming, Bai 已提交
56
{
Y
yiyue.fang 已提交
57
    int res;
M
Ming, Bai 已提交
58

Y
yiyue.fang 已提交
59 60 61
    page = block * dev->attr->pages_per_block + page;
    if (data == NULL && spare == NULL)
    {
M
Ming, Bai 已提交
62
#if defined(RT_UFFS_USE_CHECK_MARK_FUNCITON)
Y
yiyue.fang 已提交
63
        RT_ASSERT(0); //should not be here
M
Ming, Bai 已提交
64
#else
Y
yiyue.fang 已提交
65 66 67 68
        /* check block status: bad or good */
        rt_uint8_t spare[UFFS_MAX_SPARE_SIZE];

        rt_memset(spare, 0, UFFS_MAX_SPARE_SIZE);
M
Ming, Bai 已提交
69

Y
yiyue.fang 已提交
70 71 72
        rt_mtd_nand_read(RT_MTD_NAND_DEVICE(dev->_private),
                         page, RT_NULL, 0,
                         spare, dev->attr->spare_size);//dev->mem.spare_data_size
M
Ming, Bai 已提交
73

Y
yiyue.fang 已提交
74 75
        res = spare[dev->attr->block_status_offs] == 0xFF ?
                               UFFS_FLASH_NO_ERR : UFFS_FLASH_BAD_BLK;
M
Ming, Bai 已提交
76

Y
yiyue.fang 已提交
77
        return res;
M
Ming, Bai 已提交
78
#endif
Y
yiyue.fang 已提交
79
    }
M
Ming, Bai 已提交
80

Y
yiyue.fang 已提交
81 82
    rt_mtd_nand_read(RT_MTD_NAND_DEVICE(dev->_private),
                     page, data, data_len, spare, spare_len);
M
Ming, Bai 已提交
83

Y
yiyue.fang 已提交
84
    return UFFS_FLASH_NO_ERR;
M
Ming, Bai 已提交
85 86
}

Y
yiyue.fang 已提交
87 88 89 90 91 92 93
static int nand_write_page(uffs_Device *dev,
                           u32          block,
                           u32          page,
                           const u8    *data,
                           int          data_len,
                           const u8    *spare,
                           int          spare_len)
M
Ming, Bai 已提交
94
{
Y
yiyue.fang 已提交
95
    int res;
M
Ming, Bai 已提交
96

Y
yiyue.fang 已提交
97
    RT_ASSERT(UFFS_MAX_SPARE_SIZE >= dev->attr->spare_size);
M
Ming, Bai 已提交
98

Y
yiyue.fang 已提交
99
    page = block * dev->attr->pages_per_block + page;
M
Ming, Bai 已提交
100

Y
yiyue.fang 已提交
101 102
    if (data == NULL && spare == NULL)
    {
M
Ming, Bai 已提交
103
#if defined(RT_UFFS_USE_CHECK_MARK_FUNCITON)
Y
yiyue.fang 已提交
104
        RT_ASSERT(0); //should not be here
M
Ming, Bai 已提交
105
#else
Y
yiyue.fang 已提交
106 107
        /* mark bad block  */
        rt_uint8_t spare[UFFS_MAX_SPARE_SIZE];
M
Ming, Bai 已提交
108

Y
yiyue.fang 已提交
109 110
        rt_memset(spare, 0xFF, UFFS_MAX_SPARE_SIZE);
        spare[dev->attr->block_status_offs] =  0x00;
M
Ming, Bai 已提交
111

Y
yiyue.fang 已提交
112 113 114 115 116
        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;
M
Ming, Bai 已提交
117
#endif
Y
yiyue.fang 已提交
118
    }
M
Ming, Bai 已提交
119

Y
yiyue.fang 已提交
120 121 122 123
    res = rt_mtd_nand_write(RT_MTD_NAND_DEVICE(dev->_private),
                           page,  data, data_len, spare, spare_len);
    if (res != RT_EOK)
        goto __error;
M
Ming, Bai 已提交
124

Y
yiyue.fang 已提交
125
    return UFFS_FLASH_NO_ERR;
M
Ming, Bai 已提交
126 127

__error:
Y
yiyue.fang 已提交
128
    return UFFS_FLASH_IO_ERR;
M
Ming, Bai 已提交
129 130 131 132
}

const uffs_FlashOps nand_ops =
{
Y
yiyue.fang 已提交
133 134 135 136 137
    nand_init_flash,    /* InitFlash() */
    nand_release_flash, /* ReleaseFlash() */
    nand_read_page,     /* ReadPage() */
    NULL,               /* ReadPageWithLayout */
    nand_write_page,    /* WritePage() */
D
David Lin 已提交
138
    NULL,               /* WritePageWithLayout */
M
Ming, Bai 已提交
139
#if defined(RT_UFFS_USE_CHECK_MARK_FUNCITON)
Y
yiyue.fang 已提交
140 141
    nand_check_block,
    nand_mark_badblock,
M
Ming, Bai 已提交
142
#else
Y
yiyue.fang 已提交
143 144
    NULL,               /* IsBadBlock(), let UFFS take care of it. */
    NULL,               /* MarkBadBlock(), let UFFS take care of it. */
M
Ming, Bai 已提交
145
#endif
Y
yiyue.fang 已提交
146
    nand_erase_block,   /* EraseBlock() */
M
Ming, Bai 已提交
147 148
};

Y
yiyue.fang 已提交
149 150
void uffs_setup_storage(struct uffs_StorageAttrSt *attr,
                        struct rt_mtd_nand_device *nand)
M
Ming, Bai 已提交
151
{
Y
yiyue.fang 已提交
152 153 154 155 156 157 158 159 160 161
    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 */
M
Ming, Bai 已提交
162 163 164
}

#elif  RT_CONFIG_UFFS_ECC_MODE == UFFS_ECC_HW_AUTO
Y
yiyue.fang 已提交
165 166 167 168 169 170 171
static int WritePageWithLayout(uffs_Device         *dev,
                               u32                  block,
                               u32                  page,
                               const u8            *data,
                               int                  data_len,
                               const u8            *ecc,  //NULL
                               const uffs_TagStore *ts)
M
Ming, Bai 已提交
172
{
Y
yiyue.fang 已提交
173 174 175
    int res;
    int spare_len;
    rt_uint8_t spare[UFFS_MAX_SPARE_SIZE];
M
Ming, Bai 已提交
176

Y
yiyue.fang 已提交
177
    RT_ASSERT(UFFS_MAX_SPARE_SIZE >= dev->attr->spare_size);
M
Ming, Bai 已提交
178

Y
yiyue.fang 已提交
179 180
    page = block * dev->attr->pages_per_block + page;
    spare_len = dev->mem.spare_data_size;
M
Ming, Bai 已提交
181

Y
yiyue.fang 已提交
182 183
    if (data == NULL && ts == NULL)
    {
M
Ming, Bai 已提交
184
#if defined(RT_UFFS_USE_CHECK_MARK_FUNCITON)
Y
yiyue.fang 已提交
185
        RT_ASSERT(0); //should not be here
M
Ming, Bai 已提交
186
#else
Y
yiyue.fang 已提交
187 188 189 190 191 192 193 194 195 196 197 198
        /* 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;
M
Ming, Bai 已提交
199
#endif
Y
yiyue.fang 已提交
200
    }
M
Ming, Bai 已提交
201

Y
yiyue.fang 已提交
202 203 204
    if (data != NULL && data_len != 0)
    {
        RT_ASSERT(data_len == dev->attr->page_data_size);
M
Ming, Bai 已提交
205

Y
yiyue.fang 已提交
206 207 208
        dev->st.page_write_count++;
        dev->st.io_write += data_len;
    }
M
Ming, Bai 已提交
209

Y
yiyue.fang 已提交
210 211 212 213 214 215
    if (ts != RT_NULL)
    {
        uffs_FlashMakeSpare(dev, ts, RT_NULL, (u8 *)spare);
        dev->st.spare_write_count++;
        dev->st.io_write += spare_len;
    }
M
Ming, Bai 已提交
216

Y
yiyue.fang 已提交
217 218 219 220
    res = rt_mtd_nand_write(RT_MTD_NAND_DEVICE(dev->_private),
                            page, data, data_len, spare, spare_len);
    if (res != RT_EOK)
        goto __error;
M
Ming, Bai 已提交
221

Y
yiyue.fang 已提交
222
    return UFFS_FLASH_NO_ERR;
M
Ming, Bai 已提交
223 224

__error:
Y
yiyue.fang 已提交
225
    return UFFS_FLASH_IO_ERR;
M
Ming, Bai 已提交
226 227
}

Y
yiyue.fang 已提交
228 229 230 231 232 233 234 235
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
M
Ming, Bai 已提交
236
{
Y
yiyue.fang 已提交
237 238 239
    int res = UFFS_FLASH_NO_ERR;
    int spare_len;
    rt_uint8_t spare[UFFS_MAX_SPARE_SIZE];
M
Ming, Bai 已提交
240

Y
yiyue.fang 已提交
241
    RT_ASSERT(UFFS_MAX_SPARE_SIZE >= dev->attr->spare_size);
M
Ming, Bai 已提交
242

Y
yiyue.fang 已提交
243 244
    page = block * dev->attr->pages_per_block + page;
    spare_len = dev->mem.spare_data_size;
M
Ming, Bai 已提交
245

Y
yiyue.fang 已提交
246 247
    if (data == RT_NULL && ts == RT_NULL)
    {
M
Ming, Bai 已提交
248
#if defined(RT_UFFS_USE_CHECK_MARK_FUNCITON)
Y
yiyue.fang 已提交
249
        RT_ASSERT(0); //should not be here
M
Ming, Bai 已提交
250
#else
Y
yiyue.fang 已提交
251
        /* check block good or bad */
M
Ming, Bai 已提交
252

Y
yiyue.fang 已提交
253 254 255
        rt_mtd_nand_read(RT_MTD_NAND_DEVICE(dev->_private),
                         page, RT_NULL, 0,
                         spare, dev->attr->spare_size);//dev->mem.spare_data_size
M
Ming, Bai 已提交
256

Y
yiyue.fang 已提交
257
        dev->st.io_read++;
M
Ming, Bai 已提交
258

Y
yiyue.fang 已提交
259 260 261
        res = spare[dev->attr->block_status_offs] == 0xFF ?
                               UFFS_FLASH_NO_ERR : UFFS_FLASH_BAD_BLK;
        return res;
M
Ming, Bai 已提交
262
#endif
Y
yiyue.fang 已提交
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
    }

    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;
M
Ming, Bai 已提交
296 297 298 299
}

const uffs_FlashOps nand_ops =
{
Y
yiyue.fang 已提交
300 301 302 303 304
    nand_init_flash,    /* InitFlash() */
    nand_release_flash, /* ReleaseFlash() */
    NULL,               /* ReadPage() */
    ReadPageWithLayout, /* ReadPageWithLayout */
    NULL,               /* WritePage() */
D
David Lin 已提交
305
    WritePageWithLayout,/* WritePageWithLayout */
M
Ming, Bai 已提交
306 307

#if defined(RT_UFFS_USE_CHECK_MARK_FUNCITON)
Y
yiyue.fang 已提交
308 309
    nand_check_block,
    nand_mark_badblock,
M
Ming, Bai 已提交
310
#else
Y
yiyue.fang 已提交
311 312
    NULL,               /* IsBadBlock(), let UFFS take care of it. */
    NULL,               /* MarkBadBlock(), let UFFS take care of it. */
M
Ming, Bai 已提交
313
#endif
Y
yiyue.fang 已提交
314
    nand_erase_block,   /* EraseBlock() */
M
Ming, Bai 已提交
315 316 317
};

static rt_uint8_t hw_flash_data_layout[UFFS_SPARE_LAYOUT_SIZE] =
Y
yiyue.fang 已提交
318 319 320
{
    0x05, 0x08, 0xFF, 0x00
};
M
Ming, Bai 已提交
321 322

static rt_uint8_t hw_flash_ecc_layout[UFFS_SPARE_LAYOUT_SIZE] =
Y
yiyue.fang 已提交
323 324 325
{
    0x00, 0x04, 0xFF, 0x00
};
M
Ming, Bai 已提交
326

Y
yiyue.fang 已提交
327 328
void uffs_setup_storage(struct uffs_StorageAttrSt *attr,
                        struct rt_mtd_nand_device *nand)
M
Ming, Bai 已提交
329
{
Y
yiyue.fang 已提交
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
    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;
M
Ming, Bai 已提交
358 359
}
#endif