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
main()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
nand_read_page(uffs_Device * dev,u32 block,u32 page,u8 * data,int data_len,u8 * ecc,u8 * spare,int spare_len)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
nand_write_page(uffs_Device * dev,u32 block,u32 page,const u8 * data,int data_len,const u8 * spare,int spare_len)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
nand_erase_block(uffs_Device * dev,u32 block)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
nand_init_flash(uffs_Device * dev)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
nand_release_flash(uffs_Device * dev)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
init_nand_chip(struct my_nand_chip * chip)335 static void init_nand_chip(struct my_nand_chip *chip)
336 {
337 // init chip IO address, etc.
338 }
339
setup_flash_storage(struct uffs_StorageAttrSt * attr)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
my_InitDevice(uffs_Device * dev)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
my_ReleaseDevice(uffs_Device * dev)365 static URET my_ReleaseDevice(uffs_Device *dev)
366 {
367 return U_SUCC;
368 }
369
370
my_init_filesystem(void)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
my_release_filesystem(void)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 */
main()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