xref: /nrf52832-nimble/rt-thread/components/dfs/filesystems/uffs/src/example/flash-interface-example.c (revision 104654410c56c573564690304ae786df310c91fc)
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