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