xref: /nrf52832-nimble/rt-thread/components/drivers/mtd/mtd_nand.c (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /*
2*10465441SEvalZero  * Copyright (c) 2006-2018, RT-Thread Development Team
3*10465441SEvalZero  *
4*10465441SEvalZero  * SPDX-License-Identifier: Apache-2.0
5*10465441SEvalZero  *
6*10465441SEvalZero  * Change Logs:
7*10465441SEvalZero  * Date           Author       Notes
8*10465441SEvalZero  * 2011-12-05     Bernard      the first version
9*10465441SEvalZero  */
10*10465441SEvalZero 
11*10465441SEvalZero /*
12*10465441SEvalZero  * COPYRIGHT (C) 2012, Shanghai Real Thread
13*10465441SEvalZero  */
14*10465441SEvalZero 
15*10465441SEvalZero #include <drivers/mtd_nand.h>
16*10465441SEvalZero 
17*10465441SEvalZero #ifdef RT_USING_MTD_NAND
18*10465441SEvalZero 
19*10465441SEvalZero /**
20*10465441SEvalZero  * RT-Thread Generic Device Interface
21*10465441SEvalZero  */
_mtd_init(rt_device_t dev)22*10465441SEvalZero static rt_err_t _mtd_init(rt_device_t dev)
23*10465441SEvalZero {
24*10465441SEvalZero     return RT_EOK;
25*10465441SEvalZero }
26*10465441SEvalZero 
_mtd_open(rt_device_t dev,rt_uint16_t oflag)27*10465441SEvalZero static rt_err_t _mtd_open(rt_device_t dev, rt_uint16_t oflag)
28*10465441SEvalZero {
29*10465441SEvalZero     return RT_EOK;
30*10465441SEvalZero }
31*10465441SEvalZero 
_mtd_close(rt_device_t dev)32*10465441SEvalZero static rt_err_t _mtd_close(rt_device_t dev)
33*10465441SEvalZero {
34*10465441SEvalZero     return RT_EOK;
35*10465441SEvalZero }
36*10465441SEvalZero 
_mtd_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)37*10465441SEvalZero static rt_size_t _mtd_read(rt_device_t dev,
38*10465441SEvalZero                            rt_off_t    pos,
39*10465441SEvalZero                            void       *buffer,
40*10465441SEvalZero                            rt_size_t   size)
41*10465441SEvalZero {
42*10465441SEvalZero     return size;
43*10465441SEvalZero }
44*10465441SEvalZero 
_mtd_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)45*10465441SEvalZero static rt_size_t _mtd_write(rt_device_t dev,
46*10465441SEvalZero                             rt_off_t    pos,
47*10465441SEvalZero                             const void *buffer,
48*10465441SEvalZero                             rt_size_t   size)
49*10465441SEvalZero {
50*10465441SEvalZero     return size;
51*10465441SEvalZero }
52*10465441SEvalZero 
_mtd_control(rt_device_t dev,int cmd,void * args)53*10465441SEvalZero static rt_err_t _mtd_control(rt_device_t dev, int cmd, void *args)
54*10465441SEvalZero {
55*10465441SEvalZero     return RT_EOK;
56*10465441SEvalZero }
57*10465441SEvalZero 
58*10465441SEvalZero #ifdef RT_USING_DEVICE_OPS
59*10465441SEvalZero const static struct rt_device_ops mtd_nand_ops =
60*10465441SEvalZero {
61*10465441SEvalZero     _mtd_init,
62*10465441SEvalZero     _mtd_open,
63*10465441SEvalZero     _mtd_close,
64*10465441SEvalZero     _mtd_read,
65*10465441SEvalZero     _mtd_write,
66*10465441SEvalZero     _mtd_control
67*10465441SEvalZero };
68*10465441SEvalZero #endif
69*10465441SEvalZero 
rt_mtd_nand_register_device(const char * name,struct rt_mtd_nand_device * device)70*10465441SEvalZero rt_err_t rt_mtd_nand_register_device(const char                *name,
71*10465441SEvalZero                                      struct rt_mtd_nand_device *device)
72*10465441SEvalZero {
73*10465441SEvalZero     rt_device_t dev;
74*10465441SEvalZero 
75*10465441SEvalZero     dev = RT_DEVICE(device);
76*10465441SEvalZero     RT_ASSERT(dev != RT_NULL);
77*10465441SEvalZero 
78*10465441SEvalZero     /* set device class and generic device interface */
79*10465441SEvalZero     dev->type        = RT_Device_Class_MTD;
80*10465441SEvalZero #ifdef RT_USING_DEVICE_OPS
81*10465441SEvalZero 	dev->ops         = &mtd_nand_ops;
82*10465441SEvalZero #else
83*10465441SEvalZero     dev->init        = _mtd_init;
84*10465441SEvalZero     dev->open        = _mtd_open;
85*10465441SEvalZero     dev->read        = _mtd_read;
86*10465441SEvalZero     dev->write       = _mtd_write;
87*10465441SEvalZero     dev->close       = _mtd_close;
88*10465441SEvalZero     dev->control     = _mtd_control;
89*10465441SEvalZero #endif
90*10465441SEvalZero 
91*10465441SEvalZero     dev->rx_indicate = RT_NULL;
92*10465441SEvalZero     dev->tx_complete = RT_NULL;
93*10465441SEvalZero 
94*10465441SEvalZero     /* register to RT-Thread device system */
95*10465441SEvalZero     return rt_device_register(dev, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
96*10465441SEvalZero }
97*10465441SEvalZero 
98*10465441SEvalZero #if defined(RT_MTD_NAND_DEBUG) && defined(RT_USING_FINSH)
99*10465441SEvalZero #include <finsh.h>
100*10465441SEvalZero #define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
101*10465441SEvalZero 
mtd_dump_hex(const rt_uint8_t * ptr,rt_size_t buflen)102*10465441SEvalZero static void mtd_dump_hex(const rt_uint8_t *ptr, rt_size_t buflen)
103*10465441SEvalZero {
104*10465441SEvalZero 	unsigned char *buf = (unsigned char*)ptr;
105*10465441SEvalZero 	int i, j;
106*10465441SEvalZero 	for (i=0; i<buflen; i+=16)
107*10465441SEvalZero 	{
108*10465441SEvalZero 		rt_kprintf("%06x: ", i);
109*10465441SEvalZero 		for (j=0; j<16; j++)
110*10465441SEvalZero 			if (i+j < buflen)
111*10465441SEvalZero 				rt_kprintf("%02x ", buf[i+j]);
112*10465441SEvalZero 			else
113*10465441SEvalZero 				rt_kprintf("   ");
114*10465441SEvalZero 		rt_kprintf(" ");
115*10465441SEvalZero 		for (j=0; j<16; j++)
116*10465441SEvalZero 			if (i+j < buflen)
117*10465441SEvalZero 				rt_kprintf("%c", __is_print(buf[i+j]) ? buf[i+j] : '.');
118*10465441SEvalZero 		rt_kprintf("\n");
119*10465441SEvalZero 	}
120*10465441SEvalZero }
121*10465441SEvalZero 
mtd_nandid(const char * name)122*10465441SEvalZero int mtd_nandid(const char* name)
123*10465441SEvalZero {
124*10465441SEvalZero 	struct rt_mtd_nand_device *nand;
125*10465441SEvalZero 	nand = RT_MTD_NAND_DEVICE(rt_device_find(name));
126*10465441SEvalZero 	if (nand == RT_NULL)
127*10465441SEvalZero 	{
128*10465441SEvalZero 		rt_kprintf("no nand device found!\n");
129*10465441SEvalZero 		return -RT_ERROR;
130*10465441SEvalZero 	}
131*10465441SEvalZero 
132*10465441SEvalZero 	return rt_mtd_nand_read_id(nand);
133*10465441SEvalZero }
134*10465441SEvalZero FINSH_FUNCTION_EXPORT_ALIAS(mtd_nandid, nand_id, read ID - nandid(name));
135*10465441SEvalZero 
mtd_nand_read(const char * name,int block,int page)136*10465441SEvalZero int mtd_nand_read(const char* name, int block, int page)
137*10465441SEvalZero {
138*10465441SEvalZero 	rt_err_t result;
139*10465441SEvalZero 	rt_uint8_t *page_ptr;
140*10465441SEvalZero 	rt_uint8_t *oob_ptr;
141*10465441SEvalZero 	struct rt_mtd_nand_device *nand;
142*10465441SEvalZero 
143*10465441SEvalZero 	nand = RT_MTD_NAND_DEVICE(rt_device_find(name));
144*10465441SEvalZero 	if (nand == RT_NULL)
145*10465441SEvalZero 	{
146*10465441SEvalZero 		rt_kprintf("no nand device found!\n");
147*10465441SEvalZero 		return -RT_ERROR;
148*10465441SEvalZero 	}
149*10465441SEvalZero 
150*10465441SEvalZero 	page_ptr = rt_malloc(nand->page_size + nand->oob_size);
151*10465441SEvalZero 	if (page_ptr == RT_NULL)
152*10465441SEvalZero 	{
153*10465441SEvalZero 		rt_kprintf("out of memory!\n");
154*10465441SEvalZero 		return -RT_ENOMEM;
155*10465441SEvalZero 	}
156*10465441SEvalZero 
157*10465441SEvalZero 	oob_ptr = page_ptr + nand->page_size;
158*10465441SEvalZero 	rt_memset(page_ptr, 0xff, nand->page_size + nand->oob_size);
159*10465441SEvalZero 
160*10465441SEvalZero 	/* calculate the page number */
161*10465441SEvalZero 	page = block * nand->pages_per_block + page;
162*10465441SEvalZero 	result = rt_mtd_nand_read(nand, page, page_ptr, nand->page_size,
163*10465441SEvalZero 		oob_ptr, nand->oob_size);
164*10465441SEvalZero 
165*10465441SEvalZero 	rt_kprintf("read page, rc=%d\n", result);
166*10465441SEvalZero 	mtd_dump_hex(page_ptr, nand->page_size);
167*10465441SEvalZero 	mtd_dump_hex(oob_ptr, nand->oob_size);
168*10465441SEvalZero 
169*10465441SEvalZero 	rt_free(page_ptr);
170*10465441SEvalZero 	return 0;
171*10465441SEvalZero }
172*10465441SEvalZero FINSH_FUNCTION_EXPORT_ALIAS(mtd_nand_read, nand_read, read page in nand - nand_read(name, block, page));
173*10465441SEvalZero 
mtd_nand_readoob(const char * name,int block,int page)174*10465441SEvalZero int mtd_nand_readoob(const char* name, int block, int page)
175*10465441SEvalZero {
176*10465441SEvalZero 	struct rt_mtd_nand_device *nand;
177*10465441SEvalZero 	rt_uint8_t *oob_ptr;
178*10465441SEvalZero 
179*10465441SEvalZero 	nand = RT_MTD_NAND_DEVICE(rt_device_find(name));
180*10465441SEvalZero 	if (nand == RT_NULL)
181*10465441SEvalZero 	{
182*10465441SEvalZero 		rt_kprintf("no nand device found!\n");
183*10465441SEvalZero 		return -RT_ERROR;
184*10465441SEvalZero 	}
185*10465441SEvalZero 
186*10465441SEvalZero 	oob_ptr = rt_malloc(nand->oob_size);
187*10465441SEvalZero 	if (oob_ptr == RT_NULL)
188*10465441SEvalZero 	{
189*10465441SEvalZero 		rt_kprintf("out of memory!\n");
190*10465441SEvalZero 		return -RT_ENOMEM;
191*10465441SEvalZero 	}
192*10465441SEvalZero 
193*10465441SEvalZero 	/* calculate the page number */
194*10465441SEvalZero 	page = block * nand->pages_per_block + page;
195*10465441SEvalZero 	rt_mtd_nand_read(nand, page, RT_NULL, nand->page_size,
196*10465441SEvalZero 		oob_ptr, nand->oob_size);
197*10465441SEvalZero 	mtd_dump_hex(oob_ptr, nand->oob_size);
198*10465441SEvalZero 
199*10465441SEvalZero 	rt_free(oob_ptr);
200*10465441SEvalZero 	return 0;
201*10465441SEvalZero }
202*10465441SEvalZero FINSH_FUNCTION_EXPORT_ALIAS(mtd_nand_readoob, nand_readoob, read spare data in nand - nand_readoob(name, block, page));
203*10465441SEvalZero 
mtd_nand_write(const char * name,int block,int page)204*10465441SEvalZero int mtd_nand_write(const char* name, int block, int page)
205*10465441SEvalZero {
206*10465441SEvalZero 	rt_err_t result;
207*10465441SEvalZero 	rt_uint8_t *page_ptr;
208*10465441SEvalZero 	rt_uint8_t *oob_ptr;
209*10465441SEvalZero 	rt_uint32_t index;
210*10465441SEvalZero 	struct rt_mtd_nand_device *nand;
211*10465441SEvalZero 
212*10465441SEvalZero 	nand = RT_MTD_NAND_DEVICE(rt_device_find(name));
213*10465441SEvalZero 	if (nand == RT_NULL)
214*10465441SEvalZero 	{
215*10465441SEvalZero 		rt_kprintf("no nand device found!\n");
216*10465441SEvalZero 		return -RT_ERROR;
217*10465441SEvalZero 	}
218*10465441SEvalZero 
219*10465441SEvalZero 	page_ptr = rt_malloc(nand->page_size + nand->oob_size);
220*10465441SEvalZero 	if (page_ptr == RT_NULL)
221*10465441SEvalZero 	{
222*10465441SEvalZero 		rt_kprintf("out of memory!\n");
223*10465441SEvalZero 		return -RT_ENOMEM;
224*10465441SEvalZero 	}
225*10465441SEvalZero 
226*10465441SEvalZero 	oob_ptr = page_ptr + nand->page_size;
227*10465441SEvalZero 	/* prepare page data */
228*10465441SEvalZero 	for (index = 0; index < nand->page_size; index ++)
229*10465441SEvalZero 	{
230*10465441SEvalZero 		page_ptr[index] = index & 0xff;
231*10465441SEvalZero 	}
232*10465441SEvalZero 	/* prepare oob data */
233*10465441SEvalZero 	for (index = 0; index < nand->oob_size; index ++)
234*10465441SEvalZero 	{
235*10465441SEvalZero 		oob_ptr[index] = index & 0xff;
236*10465441SEvalZero 	}
237*10465441SEvalZero 
238*10465441SEvalZero 	/* calculate the page number */
239*10465441SEvalZero 	page = block * nand->pages_per_block + page;
240*10465441SEvalZero 	result = rt_mtd_nand_write(nand, page, page_ptr, nand->page_size,
241*10465441SEvalZero 		oob_ptr, nand->oob_size);
242*10465441SEvalZero 	if (result != RT_MTD_EOK)
243*10465441SEvalZero 	{
244*10465441SEvalZero 		rt_kprintf("write page failed!, rc=%d\n", result);
245*10465441SEvalZero 	}
246*10465441SEvalZero 
247*10465441SEvalZero 	rt_free(page_ptr);
248*10465441SEvalZero 	return 0;
249*10465441SEvalZero }
250*10465441SEvalZero FINSH_FUNCTION_EXPORT_ALIAS(mtd_nand_write, nand_write, write dump data to nand - nand_write(name, block, page));
251*10465441SEvalZero 
mtd_nand_erase(const char * name,int block)252*10465441SEvalZero int mtd_nand_erase(const char* name, int block)
253*10465441SEvalZero {
254*10465441SEvalZero 	struct rt_mtd_nand_device *nand;
255*10465441SEvalZero 	nand = RT_MTD_NAND_DEVICE(rt_device_find(name));
256*10465441SEvalZero 	if (nand == RT_NULL)
257*10465441SEvalZero 	{
258*10465441SEvalZero 		rt_kprintf("no nand device found!\n");
259*10465441SEvalZero 		return -RT_ERROR;
260*10465441SEvalZero 	}
261*10465441SEvalZero 
262*10465441SEvalZero 	return rt_mtd_nand_erase_block(nand, block);
263*10465441SEvalZero }
264*10465441SEvalZero FINSH_FUNCTION_EXPORT_ALIAS(mtd_nand_erase, nand_erase, nand_erase(name, block));
265*10465441SEvalZero 
mtd_nand_erase_all(const char * name)266*10465441SEvalZero int mtd_nand_erase_all(const char* name)
267*10465441SEvalZero {
268*10465441SEvalZero 	rt_uint32_t index = 0;
269*10465441SEvalZero 	struct rt_mtd_nand_device *nand;
270*10465441SEvalZero 
271*10465441SEvalZero 	nand = RT_MTD_NAND_DEVICE(rt_device_find(name));
272*10465441SEvalZero 	if (nand == RT_NULL)
273*10465441SEvalZero 	{
274*10465441SEvalZero 		rt_kprintf("no nand device found!\n");
275*10465441SEvalZero 		return -RT_ERROR;
276*10465441SEvalZero 	}
277*10465441SEvalZero 
278*10465441SEvalZero 	for (index = 0; index < (nand->block_end - nand->block_start); index ++)
279*10465441SEvalZero 	{
280*10465441SEvalZero 		rt_mtd_nand_erase_block(nand, index);
281*10465441SEvalZero 	}
282*10465441SEvalZero 
283*10465441SEvalZero 	return 0;
284*10465441SEvalZero }
285*10465441SEvalZero FINSH_FUNCTION_EXPORT_ALIAS(mtd_nand_erase_all, nand_erase_all, erase all of nand device - nand_erase_all(name, block));
286*10465441SEvalZero #endif
287*10465441SEvalZero 
288*10465441SEvalZero #endif
289