1 /* 2 This file is part of UFFS, the Ultra-low-cost Flash File System. 3 4 Copyright (C) 2005-2009 Ricky Zheng <[email protected]> 5 6 UFFS is free software; you can redistribute it and/or modify it under 7 the GNU Library General Public License as published by the Free Software 8 Foundation; either version 2 of the License, or (at your option) any 9 later version. 10 11 UFFS is distributed in the hope that it will be useful, but WITHOUT 12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 or GNU Library General Public License, as applicable, for more details. 15 16 You should have received a copy of the GNU General Public License 17 and GNU Library General Public License along with UFFS; if not, write 18 to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 Boston, MA 02110-1301, USA. 20 21 As a special exception, if other files instantiate templates or use 22 macros or inline functions from this file, or you compile this file 23 and link it with other works to produce a work based on this file, 24 this file does not by itself cause the resulting work to be covered 25 by the GNU General Public License. However the source code for this 26 file must still be made available in accordance with section (3) of 27 the GNU General Public License v2. 28 29 This exception does not invalidate any other reasons why a work based 30 on this file might be covered by the GNU General Public License. 31 */ 32 /** 33 * \file flash-interface-example.c 34 * \brief example for using flash driver and multiple partitions, with static memory allocator. 35 * \author Ricky Zheng, created at 27 Nov, 2007 36 */ 37 38 #include <string.h> 39 #include "uffs_config.h" 40 #include "uffs/uffs_os.h" 41 #include "uffs/uffs_device.h" 42 #include "uffs/uffs_flash.h" 43 #include "uffs/uffs_mtb.h" 44 #include "uffs/uffs_fs.h" 45 46 #define PFX "ndrv: " 47 48 struct my_nand_chip { 49 void *IOR_ADDR; 50 void *IOW_ADDR; 51 UBOOL inited; 52 // ... 53 }; 54 55 /* 56 * Standard NAND flash commands 57 */ 58 #define NAND_CMD_READ0 0 59 #define NAND_CMD_READ1 1 60 #define NAND_CMD_RNDOUT 5 61 #define NAND_CMD_PAGEPROG 0x10 62 #define NAND_CMD_READOOB 0x50 63 #define NAND_CMD_ERASE1 0x60 64 #define NAND_CMD_STATUS 0x70 65 #define NAND_CMD_STATUS_MULTI 0x71 66 #define NAND_CMD_SEQIN 0x80 67 #define NAND_CMD_RNDIN 0x85 68 #define NAND_CMD_READID 0x90 69 #define NAND_CMD_ERASE2 0xd0 70 #define NAND_CMD_RESET 0xff 71 72 73 /* impelent the following functions for your NAND flash */ 74 #define CHIP_SET_CLE(chip) { chip = chip; } 75 #define CHIP_CLR_CLE(chip) {} 76 #define CHIP_SET_ALE(chip) {} 77 #define CHIP_CLR_ALE(chip) {} 78 #define CHIP_SET_NCS(chip) {} 79 #define CHIP_CLR_NCS(chip) {} 80 #define CHIP_BUSY(chip) {} 81 #define CHIP_READY(chip) {} 82 #define WRITE_COMMAND(chip, cmd) {} 83 #define WRITE_DATA_ADDR(chip, block, page, offset) {} 84 #define WRITE_ERASE_ADDR(chip, block) {} 85 #define WRITE_DATA(chip, data, len) {} 86 #define READ_DATA(chip, data, len) {} 87 88 #define PARSE_STATUS(v) (UFFS_FLASH_NO_ERR) // parse status to UFFS_FLASH_NO_ERR or UFFS_FLASH_BAD_BLK 89 90 91 92 #if CONFIG_USE_STATIC_MEMORY_ALLOCATOR == 0 93 int main() 94 { 95 uffs_Perror(UFFS_MSG_NORMAL, "This example need CONFIG_USE_STATIC_MEMORY_ALLOCATOR = 1"); 96 return 0; 97 } 98 #else 99 100 101 static int nand_read_page(uffs_Device *dev, u32 block, u32 page, u8 *data, int data_len, u8 *ecc, 102 u8 *spare, int spare_len) 103 { 104 u8 val = 0; 105 int ret = UFFS_FLASH_NO_ERR; 106 struct my_nand_chip *chip = (struct my_nand_chip *) dev->attr->_private; 107 108 CHIP_CLR_NCS(chip); 109 if (data && data_len > 0) { 110 CHIP_SET_CLE(chip); 111 WRITE_COMMAND(chip, NAND_CMD_READ0); 112 CHIP_CLR_CLE(chip); 113 CHIP_SET_ALE(chip); 114 WRITE_DATA_ADDR(chip, block, page, 0); 115 CHIP_CLR_ALE(chip); 116 READ_DATA(chip, data, data_len); 117 118 // for now, we return all 0xFF to pass UFFS mount, you should remove this at your driver 119 memset(data, 0xFF, data_len); 120 } 121 122 if (spare && spare_len > 0) { 123 CHIP_SET_CLE(chip); 124 WRITE_COMMAND(chip, NAND_CMD_READOOB); 125 CHIP_CLR_CLE(chip); 126 CHIP_SET_ALE(chip); 127 WRITE_DATA_ADDR(chip, block, page, dev->attr->page_data_size); 128 CHIP_CLR_ALE(chip); 129 READ_DATA(chip, spare, spare_len); 130 131 // for now, we return all 0xFF to pass UFFS mount, you should remove this at your driver 132 memset(spare, 0xFF, spare_len); 133 } 134 135 if (data == NULL && spare == NULL) { 136 // read bad block mark 137 CHIP_SET_CLE(chip); 138 WRITE_COMMAND(chip, NAND_CMD_READOOB); 139 CHIP_CLR_CLE(chip); 140 CHIP_SET_ALE(chip); 141 WRITE_DATA_ADDR(chip, block, page, dev->attr->page_data_size + attr->block_status_offs); 142 CHIP_CLR_ALE(chip); 143 READ_DATA(chip, &val, 1); 144 ret = (val == 0xFF ? UFFS_FLASH_NO_ERR : UFFS_FLASH_BAD_BLK); 145 146 // for now, we return UFFS_FLASH_NO_ERR to pass UFFS mount, you should remove this at your driver 147 ret = UFFS_FLASH_NO_ERR; 148 } 149 150 CHIP_SET_NCS(chip); 151 152 return ret; 153 } 154 155 static int nand_write_page(uffs_Device *dev, u32 block, u32 page, 156 const u8 *data, int data_len, const u8 *spare, int spare_len) 157 { 158 u8 val = 0; 159 int ret = UFFS_FLASH_NO_ERR; 160 UBOOL fall_through = FALSE; 161 struct my_nand_chip *chip = (struct my_nand_chip *) dev->attr->_private; 162 163 CHIP_CLR_NCS(chip); 164 165 if (data && data_len > 0) { 166 CHIP_SET_CLE(chip); 167 WRITE_COMMAND(chip, NAND_CMD_READ0); 168 WRITE_COMMAND(chip, NAND_CMD_SEQIN); 169 CHIP_CLR_CLE(chip); 170 CHIP_SET_ALE(chip); 171 WRITE_DATA_ADDR(chip, block, page, 0); 172 CHIP_CLR_ALE(chip); 173 CHIP_BUSY(chip); 174 WRITE_DATA(chip, data, data_len); 175 if (data_len == dev->attr->page_data_size) 176 fall_through = U_TRUE; 177 else { 178 CHIP_SET_CLE(chip); 179 WRITE_COMMAND(chip, NAND_CMD_PAGEPROG); 180 WRITE_COMMAND(chip, NAND_CMD_STATUS); 181 CHIP_CLR_CLE(chip); 182 CHIP_READY(chip); 183 READ_DATA(chip, &val, 1); 184 ret = PARSE_STATUS(val); 185 } 186 } 187 188 if (ret != UFFS_FLASH_NO_ERR) 189 goto ext; 190 191 if (spare && spare_len > 0) { 192 if (!fall_through) { 193 CHIP_SET_CLE(chip); 194 WRITE_COMMAND(chip, NAND_CMD_READOOB); 195 WRITE_COMMAND(chip, NAND_CMD_SEQIN); 196 CHIP_CLR_CLE(chip); 197 CHIP_SET_ALE(chip); 198 WRITE_DATA_ADDR(chip, block, page, dev->attr->page_data_size); 199 CHIP_CLR_ALE(chip); 200 CHIP_BUSY(chip); 201 } 202 WRITE_DATA(chip, spare, spare_len); 203 CHIP_SET_CLE(chip); 204 WRITE_COMMAND(chip, NAND_CMD_PAGEPROG); 205 WRITE_COMMAND(chip, NAND_CMD_STATUS); 206 CHIP_CLR_CLE(chip); 207 CHIP_READY(chip); 208 READ_DATA(chip, &val, 1); 209 ret = PARSE_STATUS(val); 210 } 211 212 if (data == NULL && spare == NULL) { 213 // mark bad block 214 CHIP_SET_CLE(chip); 215 WRITE_COMMAND(chip, NAND_CMD_READOOB); 216 WRITE_COMMAND(chip, NAND_CMD_SEQIN); 217 CHIP_CLR_CLE(chip); 218 CHIP_SET_ALE(chip); 219 WRITE_DATA_ADDR(chip, block, page, dev->attr->page_data_size + attr->block_status_offs); 220 CHIP_CLR_ALE(chip); 221 CHIP_BUSY(chip); 222 val = 0; 223 WRITE_DATA(chip, &val, 1); 224 CHIP_SET_CLE(chip); 225 WRITE_COMMAND(chip, NAND_CMD_PAGEPROG); 226 WRITE_COMMAND(chip, NAND_CMD_STATUS); 227 CHIP_CLR_CLE(chip); 228 CHIP_READY(chip); 229 READ_DATA(chip, &val, 1); 230 ret = PARSE_STATUS(val); 231 } 232 233 ext: 234 CHIP_SET_NCS(chip); 235 236 return ret; 237 } 238 239 static int nand_erase_block(uffs_Device *dev, u32 block) 240 { 241 u8 val = 0; 242 struct my_nand_chip *chip = (struct my_nand_chip *) dev->attr->_private; 243 244 CHIP_CLR_NCS(chip); 245 246 CHIP_SET_CLE(chip); 247 WRITE_COMMAND(chip, NAND_CMD_ERASE1); 248 CHIP_CLR_CLE(chip); 249 CHIP_SET_ALE(chip); 250 WRITE_ERASE_ADDR(chip, blcok); 251 CHIP_CLR_ALE(chip); 252 CHIP_SET_CLE(chip); 253 WRITE_COMMAND(chip, NAND_CMD_ERASE2); 254 WRITE_COMMAND(chip, NAND_CMD_STATUS); 255 CHIP_CLR_CLE(chip); 256 CHIP_READY(chip); 257 READ_DATA(chip, &val, 1); 258 259 CHIP_SET_NCS(chip); 260 261 val = val; // just for eliminating warning 262 263 return PARSE_STATUS(val); 264 } 265 266 267 static int nand_init_flash(uffs_Device *dev) 268 { 269 // initialize your hardware here ... 270 struct my_nand_chip *chip = (struct my_nand_chip *) dev->attr->_private; 271 272 if (!chip->inited) { 273 // setup chip I/O address, setup NAND flash controller ... etc. 274 // chip->IOR_ADDR = 0xF0000000 275 // chip->IOW_ADDR = 0xF0000000 276 chip->inited = U_TRUE; 277 } 278 return 0; 279 } 280 281 static int nand_release_flash(uffs_Device *dev) 282 { 283 // release your hardware here 284 struct my_nand_chip *chip = (struct my_nand_chip *) dev->attr->_private; 285 286 chip = chip; 287 288 return 0; 289 } 290 291 static uffs_FlashOps g_my_nand_ops = { 292 nand_init_flash, // InitFlash() 293 nand_release_flash, // ReleaseFlash() 294 nand_read_page, // ReadPage() 295 NULL, // ReadPageWithLayout 296 nand_write_page, // WritePage() 297 NULL, // WirtePageWithLayout 298 NULL, // IsBadBlock(), let UFFS take care of it. 299 NULL, // MarkBadBlock(), let UFFS take care of it. 300 nand_erase_block, // EraseBlock() 301 }; 302 303 ///////////////////////////////////////////////////////////////////////////////// 304 305 // change these parameters to fit your nand flash specification 306 307 #define TOTAL_BLOCKS 1024 308 #define PAGE_DATA_SIZE 512 309 #define PAGE_SPARE_SIZE 16 310 #define PAGES_PER_BLOCK 32 311 #define PAGE_SIZE (PAGE_DATA_SIZE + PAGE_SPARE_SIZE) 312 #define BLOCK_DATA_SIZE (PAGE_DATA_SIZE * PAGES_PER_BLOCK) 313 314 #define NR_PARTITION 2 /* total partitions */ 315 #define PAR_1_BLOCKS 100 /* partition 1 */ 316 #define PAR_2_BLOCKS (TOTAL_BLOCKS - PAR_1_BLOCKS) /* partition 2 */ 317 318 struct my_nand_chip g_nand_chip = {0}; 319 static struct uffs_StorageAttrSt g_my_flash_storage = {0}; 320 321 /* define mount table */ 322 static uffs_Device demo_device_1 = {0}; 323 static uffs_Device demo_device_2 = {0}; 324 325 static uffs_MountTable demo_mount_table[] = { 326 { &demo_device_1, 0, PAR_1_BLOCKS - 1, "/data/" }, 327 { &demo_device_2, PAR_1_BLOCKS, PAR_1_BLOCKS + PAR_2_BLOCKS - 1, "/" }, 328 { NULL, 0, 0, NULL } 329 }; 330 331 /* static alloc the memory for each partition */ 332 static int static_buffer_par1[UFFS_STATIC_BUFF_SIZE(PAGES_PER_BLOCK, PAGE_SIZE, PAR_1_BLOCKS) / sizeof(int)]; 333 static int static_buffer_par2[UFFS_STATIC_BUFF_SIZE(PAGES_PER_BLOCK, PAGE_SIZE, PAR_2_BLOCKS) / sizeof(int)];; 334 335 static void init_nand_chip(struct my_nand_chip *chip) 336 { 337 // init chip IO address, etc. 338 } 339 340 static void setup_flash_storage(struct uffs_StorageAttrSt *attr) 341 { 342 memset(attr, 0, sizeof(struct uffs_StorageAttrSt)); 343 344 // setup NAND flash attributes. 345 attr->total_blocks = TOTAL_BLOCKS; /* total blocks */ 346 attr->page_data_size = PAGE_DATA_SIZE; /* page data size */ 347 attr->pages_per_block = PAGES_PER_BLOCK; /* pages per block */ 348 attr->spare_size = PAGE_SPARE_SIZE; /* page spare size */ 349 attr->block_status_offs = 4; /* block status offset is 5th byte in spare */ 350 attr->ecc_opt = UFFS_ECC_SOFT; /* ecc option */ 351 attr->layout_opt = UFFS_LAYOUT_UFFS; /* let UFFS do the spare layout */ 352 } 353 354 static URET my_InitDevice(uffs_Device *dev) 355 { 356 dev->attr = &g_my_flash_storage; // NAND flash attributes 357 dev->attr->_private = (void *) &g_nand_chip;// hook nand_chip data structure to attr->_private 358 dev->ops = &g_my_nand_ops; // NAND driver 359 360 init_nand_chip(&g_nand_chip); 361 362 return U_SUCC; 363 } 364 365 static URET my_ReleaseDevice(uffs_Device *dev) 366 { 367 return U_SUCC; 368 } 369 370 371 static int my_init_filesystem(void) 372 { 373 uffs_MountTable *mtbl = &(demo_mount_table[0]); 374 375 /* setup nand storage attributes */ 376 setup_flash_storage(&g_my_flash_storage); 377 378 /* setup memory allocator */ 379 uffs_MemSetupStaticAllocator(&demo_device_1.mem, static_buffer_par1, sizeof(static_buffer_par1)); 380 uffs_MemSetupStaticAllocator(&demo_device_2.mem, static_buffer_par2, sizeof(static_buffer_par2)); 381 382 /* register mount table */ 383 while(mtbl->dev) { 384 // setup device init/release entry 385 mtbl->dev->Init = my_InitDevice; 386 mtbl->dev->Release = my_ReleaseDevice; 387 uffs_RegisterMountTable(mtbl); 388 mtbl++; 389 } 390 391 // mount partitions 392 for (mtbl = &(demo_mount_table[0]); mtbl->mount != NULL; mtbl++) { 393 uffs_Mount(mtbl->mount); 394 } 395 396 return uffs_InitFileSystemObjects() == U_SUCC ? 0 : -1; 397 } 398 399 static int my_release_filesystem(void) 400 { 401 uffs_MountTable *mtb; 402 int ret = 0; 403 404 // unmount parttions 405 for (mtb = &(demo_mount_table[0]); ret == 0 && mtb->mount != NULL; mtb++) { 406 ret = uffs_UnMount(mtb->mount); 407 } 408 409 // release objects 410 if (ret == 0) 411 ret = (uffs_ReleaseFileSystemObjects() == U_SUCC ? 0 : -1); 412 413 return ret; 414 } 415 416 /* application entry */ 417 int main() 418 { 419 uffs_SetupDebugOutput(); // setup debug output as early as possible 420 421 my_init_filesystem(); 422 423 // ... my application codes .... 424 // read/write/create/delete files ... 425 426 my_release_filesystem(); 427 428 return 0; 429 } 430 431 #endif 432 433 434 ///////////////////////////////////////////////////////////////////////////////// 435