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 <ricky_gz_zheng@yahoo.co.nz>
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