blob: a7ed7032dfdb983955121e0ff31eb4f2546332bc [file] [log] [blame]
yuezonghe824eb0c2024-06-27 02:32:26 -07001/*
2 * Linux driver for NAND NV Flash Translation Layer
3 * Copyright (C) 2013, ZTE Corporation.
4 */
5
6
7#include <linux/mtd/mtd.h>
8#include <linux/kernel.h>
9#include <linux/module.h>
10#include <asm/errno.h>
11#include <asm/io.h>
12#include <asm/uaccess.h>
13#include <linux/delay.h>
14#include <linux/slab.h>
15#include <linux/init.h>
16#include <linux/hdreg.h>
17#include <linux/blkdev.h>
18
19#include <linux/kmod.h>
20#include <linux/mtd/mtd.h>
21#include <linux/mtd/nand.h>
22
23#include <linux/mtd/blktrans.h>
24#include <linux/mtd/zftl.h>
25
26
27
28#include <linux/types.h>
29#include <linux/mtd/map.h>
30#include <linux/mtd/partitions.h>
31#include <asm/io.h>
32
33#ifdef CONFIG_MTD_NVRESUME
34#include <linux/mfd/zx234290.h>
35#endif
36
37#include <linux/mtd/partition_guard.h>
38
39#define ZFTL_DEBUG 0
40
41
42/* DEBUG */
43#if ZFTL_DEBUG
44#define zftl_debug(fmt,args...) printk (fmt ,##args)
45#define zftl_debugX(level,fmt,args...) if (DEBUG>=level) printk(fmt,##args);
46#else
47#define zftl_debug(fmt,args...)
48#define zftl_debugX(level,fmt,args...)
49#endif /* DEBUG */
50
51int g_oob_zftl_offset = 48;
52/* defined in cmd_nand.c */
53int arg_off_size(int argc, char *const argv[], int *idx,
54 loff_t *off, loff_t *size);
55extern int nand_block_isbad(struct mtd_info *mtd, loff_t offs);
56
57#ifdef CONFIG_MTD_NVRESUME
58int zftl_res = 0;
59extern int hal_Comm_Soft_Reset(T_ZDrvSys_RESET_TYPE reset_type);
60extern int zOss_NvInResume(void);
61extern void zOss_NvSetErrorAddr(int dwAddr);
62#endif
63
64struct ZFTLrecord *zftl_info[CONFIG_ZFTL_MAX_PARTITIONS] = {NULL};
65extern struct mtd_info *mtd_fota;
66extern struct cmdline_mtd_partition *partitions;
67
68struct cmdline_mtd_partition {
69 struct cmdline_mtd_partition *next;
70 char *mtd_id;
71 int num_parts;
72 struct mtd_partition *parts;
73};
74
75int partnum = 0;
76static struct mutex zftl_mutex;
77static int mutex_inited = 0;
78int cdrom_partsize = 0;
79
80/* nvro partition size */
81int nvro_partsize = 0;
82
83
84
85int nand_NvProgram(int dwStart, int dwLen, char* from);
86int nand_NvRead(int dwStart, int dwLen, char* to);
87
88
89static int memcmpb(void *a, int c, int n)
90{
91 int i;
92 for (i = 0; i < n; i++) {
93 if (c != ((unsigned char *)a)[i])
94 return 1;
95 }
96 return 0;
97}
98
99/* Read oob data from flash */
100static int zftl_read_oob(struct ZFTLrecord *zftl, uint32_t offs, uint8_t *buf)
101{
102 nand_info_t *nand = zftl->nand;
103 uint32_t mask = zftl->writesize - 1;
104 struct mtd_oob_ops ops;
105 int32_t res;
106
107 ops.mode = MTD_OPS_PLACE_OOB;
108 ops.ooboffs = offs & mask;
109 ops.ooblen = zftl->oobsize;
110 ops.oobbuf = buf;
111 ops.datbuf = NULL;
112
113 res = nand->_read_oob(nand, (offs & ~mask), &ops);
114 return res;
115}
116
117
118static int zftl_setup_table(struct ZFTLrecord *zftl, uint32_t *is_writed)
119{
120 nand_info_t *nand = zftl->nand;
121 uint32_t block_num = zftl->numBlocks;
122 uint32_t first_block = zftl->firstBlock;
123 uint32_t erasesize = zftl->erasesize;
124 uint32_t oobsize = zftl->oobsize;
125 unsigned char *oob = zftl->oobbuf;
126 uint32_t index = 0;
127 uint32_t addr = 0;
128 unsigned char zftl_buffer[256] = {0};
129 struct zftl_oob zftl_oob ={0};
130
131 memset(oob, 0x0, oobsize);
132
133 for( index = 0; index < block_num; index++ )
134 {
135 addr = (first_block + index) * erasesize;
136 if(nand->_block_isbad(nand, (loff_t)addr))
137 {
138 zftl->blockTable[index] = BLOCK_BAD;
139 continue;
140 }
141
142 /* д¿éµÄ˳ÐòΪ ÏÈдµÚ¶þÒ³¿ªÊ¼µ½×îºóÒ»Ò³£¬ÔÙдµÚÒ»Ò³ */
143 /* µÚÒ»Ò³oob µÚ¶þÒ³oob ¿é״̬ ˵Ã÷ */
144 /* 0xff 0xff BLOCK_FREE ¶¼Ã»ÓпªÊ¼Ð´ */
145 /* 0xff ---- BLOCK_DIRTY ¿ªÊ¼Ð´£¬µ«Ã»ÓÐдÍêµÚÒ»Ò³£¬Öм䱻ÖÐ¶Ï */
146 /* ---- 0xff BLOCK_USED/DIRTY дÍêµÚÒ»Ò³£¬Íê³É¿éдÈë */
147 /* ---- ---- BLOCK_USED/DIRTY дÍêµÚÒ»Ò³£¬Íê³É¿éдÈë */
148
149 if(zftl_read_oob(zftl, addr, (uint8_t *)oob ))/* ¶ÁÈ¡µÚÒ»Ò³ */
150 {
151 printk("[zftl_setup_table] read oob error at = 0x%08x\n", addr);
152 return NAND_READ_WRITE_ERROR;
153 }
154
155 memcpy(zftl_buffer,oob + g_oob_zftl_offset,oobsize -g_oob_zftl_offset);
156 memcpy((unsigned char *)&zftl_oob,zftl_buffer,sizeof(struct zftl_oob));
157 if(memcmpb(oob, 0xff, oobsize)) /* µÚÒ»Ò³oob != 0xff */
158 {
159 //if( oob.used == 1 ) /* block is used */
160 if( !memcmp(zftl_oob.head, CONFIG_ZFLT_HEAD, CONFIG_ZFLT_HEAD_BYTE) ) /* °üº¬ÓзÖÇøÍ· */
161 {
162 *is_writed += 1;
163 if( zftl_oob.version > zftl->versionTable[zftl_oob.logicBlockID])
164 {
165 /* version is newer */
166 if(zftl->versionTable[zftl_oob.logicBlockID] != 0) /* ÒѾ­ÓжÔÓ¦µÄused¿éÁË */
167 zftl->blockTable[zftl->blockRepTable[zftl_oob.logicBlockID]] = BLOCK_DIRTY;
168
169 zftl->blockRepTable[zftl_oob.logicBlockID] = index;
170 zftl->versionTable[zftl_oob.logicBlockID] = zftl_oob.version;
171 zftl->blockTable[index] = BLOCK_USED;
172 /* Added by zhouqi for xxx, 2014/04/23 */
173 zftl->lastFreeBlock = index + 1;
174 }
175 else
176 zftl->blockTable[index] = BLOCK_DIRTY;
177 }
178 else
179 zftl->blockTable[index] = BLOCK_DIRTY;
180 }
181 else /* 0xff£¬block is free */
182 {
183 if(zftl_read_oob(zftl, addr + zftl->writesize, (uint8_t *)oob ))/* ¶ÁÈ¡µÚ¶þÒ³ */
184 {
185 printk("[zftl_setup_table] read oob error at = 0x%08x\n", addr);
186 return NAND_READ_WRITE_ERROR;
187 }
188
189 if(memcmpb(oob, 0xff, oobsize)) /* µÚ¶þÒ³oob != 0xff */
190 {
191 zftl->blockTable[index] = BLOCK_DIRTY;
192 }
193 else /* µÚ¶þÒ³oob = 0xff */
194 zftl->blockTable[index] = BLOCK_FREE;
195 }
196 }
197
198 return 0;
199}
200
201
202/* ²Á³ýÒ»¿é£¬ebnumΪ¿éºÅ */
203static int zftl_erase_block(nand_info_t *nand, uint32_t ebnum)
204{
205 int err = -1;
206 struct erase_info ei;
207 uint32_t addr = ebnum * nand->erasesize;
208
209 memset(&ei, 0, sizeof(struct erase_info));
210 ei.mtd = nand;
211 ei.addr = (uint64_t)addr;
212 ei.len = (uint64_t)nand->erasesize;
213
214 err = nand->_erase(nand, &ei);
215 if (err)
216 {
217 printk("[zftl_erase_block]: erasing %d error %d\n", ebnum, err);
218 return err;
219 }
220
221 if (ei.state == MTD_ERASE_FAILED)
222 {
223 printk("[zftl_erase_block]: erasing %d\n",ebnum);
224 return -1;
225 }
226 return 0;
227}
228
229
230void zftl_garbage_collect(struct ZFTLrecord *zftl)
231{
232 uint32_t block_num = zftl->numBlocks;
233 uint32_t firstBlock = zftl->firstBlock;
234 uint32_t index = 0;
235 nand_info_t *nand = zftl->nand;
236
237 zftl_debug("\n");
238
239 for( index = 0; index < block_num; index++ )
240 {
241 if( zftl->blockTable[index] == BLOCK_DIRTY )
242 {
243 zftl_debug(" [zftl_garbage_collect] eraseblock zftl->blockTable[-%d-]\n", index);
244 if( zftl_erase_block(nand, firstBlock + index) )
245 {
246 /* ²Á³ýʧ°Ü£¬±ê¼ÇΪ»µ¿ì */
247 zftl_debug(" [zftl_garbage_collect] eraseblock zftl->blockTable[-%d-] ERROR\n", index);
248 zftl->blockTable[index] = BLOCK_BAD;
249 /* ±ê¼Ç»µ¿é£¬¸üлµ¿é±í mtd->erase ÖУ¬ÒÔ°üº¬²Á³ýʧ°Ü¸üÐÂBBT*/
250 nand->_block_markbad(nand, (loff_t)((firstBlock + index) << zftl->erasesize_shift));
251 }
252 else
253 {
254 /* ²Á³ý³É¹¦ */
255 zftl->blockTable[index] = BLOCK_FREE;;
256 }
257 }
258 }
259 zftl_debug("\n");
260}
261
262
263/* Added by zhouqi for xxx, 2014/04/23 */
264
265static int zftl_find_free_block(struct ZFTLrecord *zftl, uint32_t *freeBlock)
266 {
267 uint32_t i = 2;
268 uint32_t index = 0;
269 uint32_t max = 0;
270
271 do
272 {
273 index = zftl->lastFreeBlock;
274 max = zftl->numBlocks;
275 for( ; index < max; index++ )
276 {
277 if( zftl->blockTable[index] == BLOCK_FREE )
278 {
279 *freeBlock = index ;
280 zftl->lastFreeBlock = index + 1;
281 zftl_debug(" [zftl_find_free_block++] zftl->blockTable[ -%d- ] -BLOCK_FREE-\n", index - 1);
282 return 0;
283 }
284 }
285
286 max = zftl->lastFreeBlock;
287 index = 1;
288 for( ; index < max; index++ )
289 {
290 if( zftl->blockTable[index - 1] == BLOCK_FREE )
291 {
292 *freeBlock = index - 1;
293 zftl->lastFreeBlock = index;
294 zftl_debug(" [zftl_find_free_block--] zftl->blockTable[ -%d- ] -BLOCK_FREE-\n", index - 1);
295 return 0;
296 }
297 }
298
299 /* ûÓÐÕÒµ½¿ÕÏеĿ飬Ôò½øÐÐÀ¬»ø»ØÊÕ */
300 zftl_debug(" [zftl_find_free_block] no free block --> zftl_garbage_collect()\n");
301 zftl_garbage_collect(zftl);
302 } while( --i !=0 );
303
304 return 1;
305 }
306
307
308#if 0
309static int zftl_check_offset_and_size(struct ZFTLrecord *zftl,
310 loff_t off, loff_t size)
311{
312 if( off > (zftl->numBlocks << zftl->erasesize_shift) ||
313 ( off + size) > (zftl->numBlocks << zftl->erasesize_shift))
314 return 1;
315
316 return 0;
317}
318#endif
319
320static int zftl_write_block(nand_info_t *nand, uint32_t offs, size_t *retlen,
321 uint8_t *oob, u_char *buf)
322{
323 struct mtd_oob_ops ops;
324 int32_t res = 0;
325 uint32_t offset = offs;
326 size_t ret_len = 0;
327 size_t pagesize = nand->writesize;
328
329 /* write the remain */
330 res = nand->_write(nand, (loff_t)(offset + nand->writesize), nand->erasesize - pagesize,
331 &ret_len, (u_char *)(buf + pagesize) );
332
333 /* write the first page of the block write the oob */
334 ops.mode = MTD_OPS_PLACE_OOB;
335 ops.ooboffs = 0;
336 ops.ooblen = nand->oobsize;
337 ops.oobbuf = oob;
338 ops.datbuf = buf;
339 ops.len = pagesize;
340 res += nand->_write_oob(nand, (loff_t)offset, &ops);
341 *retlen = ops.retlen + ret_len;
342 return res;
343}
344
345
346
347int zftl_write(struct ZFTLrecord *zftl, uint32_t to, uint32_t len, u_char *buf)
348{
349 int ret = 0;
350 uint32_t offset_block_phy = 0;
351 uint32_t block_new = 0;
352 size_t retlen = 0;
353 u_char *buffer = buf;
354 unsigned char *oob = zftl->oobbuf;
355 uint32_t block_offset = 0;
356 uint32_t erasesize_shift = zftl->erasesize_shift;
357 uint32_t block_log = 0;
358 uint32_t erasesize = zftl->erasesize;
359 uint32_t is_upthreshold = 0;
360 uint32_t oob_size = zftl->oobsize;
361 uint32_t firstBlock = zftl->firstBlock;
362 u_char *blockbuf = zftl->blockbuf;
363
364 uint32_t left_to_write = len;
365 uint32_t write_length = 0;
366 uint32_t offset = to;
367
368 nand_info_t *nand = zftl->nand;
369
370 unsigned char zftl_buffer[256] = {0};
371 struct zftl_oob zftl_oob ={0};
372
373 if((zftl == NULL) || (buf == NULL))
374 {
375 BUG();
376 }
377
378 while(left_to_write > 0)
379 {
380 /* ¿Õ¼ä£¬³õʼ»¯Îª 0xFF */
381 memset(blockbuf, 0xff, erasesize);
382 memset(oob, 0xff, oob_size);
383 memset(zftl_buffer,0xff,256);
384
385 /* »ñÈ¡Âß¼­¿é£¬¼°¿éÄÚÆ«ÒÆ */
386 block_log = offset >> (zftl->erasesize_shift);
387 block_offset = offset & (zftl->erasesize - 1); /* ¿éÄ򵀮«ÒƵØÖ· */
388
389 /* ÅжÏÂß¼­¿éÊÇ·ñÓÐÎïÀí¶ÔÓ¦¿é£¬Èç¹ûÓУ¬ÔòΪ¸ÄдÊý¾Ý£»Èç¹ûûÓУ¬ÔòΪµÚÒ»´Îд´Ë¿é */
390 if(zftl->blockRepTable[block_log] != BLOCK_NIL)
391 {
392 /* »ñÈ¡Âß¼­¿é¶ÔÓ¦µÄÎïÀí¿é */
393 offset_block_phy = zftl->blockRepTable[block_log];
394 zftl_debug(" [zftl_write] zftl->blockRepTable[%d] = %d\n", block_log, offset_block_phy);
395
396 /* Õû¸ö¶Áȡһ¿éÊý¾Ý */
397 zftl_debug(" [zftl_read] nand->read( -0x%0x-, -0x%0x-)\n",
398 ((firstBlock + offset_block_phy) << erasesize_shift),erasesize);
399 ret = nand->_read(nand, ((firstBlock + offset_block_phy) << erasesize_shift), erasesize, &retlen, blockbuf);
400 if (ret || retlen != erasesize)
401 {
402 printk(KERN_ERR"[zfltl]: -zftl_read- error\n");
403#ifdef CONFIG_MTD_NVRESUME
404 if((!zOss_NvInResume())&&(zftl==zftl_info[1])&&(zftl_res != 1))
405 {
406 return -1;
407 }
408#endif
409 }
410
411 /* ¶ÁÈ¡ÕâÒ»¿éµÄOOBÐÅÏ¢£¬²¢¸üРVERSION, Èç¹û´ïµ½°æ±¾ºÅµÄãÐÖµ£¬Ôò½øÐлØÊÕ */
412 if(zftl_read_oob(zftl, ((firstBlock + offset_block_phy) << erasesize_shift), (uint8_t *)oob ))
413 {
414 printk(" [zftl_write] read oob error at = 0x%x\n", (offset_block_phy << erasesize_shift));
415 //return -1;
416 }
417 memcpy(zftl_buffer,oob + g_oob_zftl_offset,oob_size-g_oob_zftl_offset);
418 memcpy((unsigned char *)&zftl_oob,zftl_buffer,sizeof(struct zftl_oob));
419 if( zftl_oob.version == CONFIG_ZFLT_VERSION_THRESHOLD )
420 {
421 zftl_debug(" [zftl_write] up to the -CONFIG_ZFLT_VERSION_THRESHOLD-\n");
422 is_upthreshold = 1;
423 zftl_garbage_collect(zftl);
424 zftl_oob.version = 1;
425 }
426 else
427 {
428
429 zftl_oob.version += 1;
430 zftl_debug(" [zftl_write] oob->version = %d,oob->logicBlockID = %d\n", zftl_oob.version, zftl_oob.logicBlockID);
431 }
432
433 memcpy(zftl_oob.head, CONFIG_ZFLT_HEAD, CONFIG_ZFLT_HEAD_BYTE); /* ¿½±´zftlÍ· */
434 zftl_oob.logicBlockID = block_log;
435
436 /* Ìî³ä¸üРdata */
437 if (left_to_write < (erasesize - block_offset))
438 write_length = left_to_write;
439 else
440 write_length = nand->erasesize - block_offset;
441
442 memcpy(blockbuf + block_offset, buffer, write_length);
443 zftl_debug(" [zftl_write] update the date ( -0x%0x-, -0x%0x- )\n",
444 block_offset, write_length);
445
446
447 /* ѰÕÒÒ»¸ö FREE µÄÎïÀí¿é */
448 find_next_free_block_1:
449 if( zftl_find_free_block(zftl, &block_new) )/* BLOCK_USED */
450 {
451 /* ûÓÐÕÒµ½FREE¿é */
452 printk(" [zftl_write] there is enough block, please enlarge the partition\n");
453 return CAN_NOT_FIND_FREE_BLOCK;
454 }
455
456 /* дÈëÒ»¿é */
457 zftl_debug(" [zftl_write_block] nand->write( -0x%0x-, -0x%0x-)\n",
458 ((firstBlock + block_new) << erasesize_shift), erasesize);
459 memcpy(oob + g_oob_zftl_offset,(uint8_t *)&zftl_oob,sizeof(struct zftl_oob));
460
461 if( zftl_write_block(nand, (loff_t)((firstBlock + block_new) << erasesize_shift), &retlen,
462 (uint8_t *)oob, blockbuf) )
463 {
464 /* дÊý¾Ýʧ°Üʱ£¬±ê¼ÇBBT£¬¸üРTABLE£¬ÖØÐ²éÕÒеĿéд */
465 printk(" -ERROR-\n");
466 zftl->blockTable[block_new] = BLOCK_BAD;
467 nand->_block_markbad(nand, (loff_t)((firstBlock + block_new) << erasesize_shift));
468 goto find_next_free_block_1;
469 }
470
471 /* ¸üРblockRepTable¡¢blockTable */
472 zftl->blockRepTable[zftl_oob.logicBlockID] = block_new;
473
474 zftl_debug(" [zftl_write] zftl->blockRepTable[oob->logicBlockID] = %d,oob->logicBlockID = %d\n", zftl->blockRepTable[zftl_oob.logicBlockID], zftl_oob.logicBlockID);
475
476 zftl->blockTable[block_new] = BLOCK_USED;
477 zftl->blockTable[offset_block_phy] = BLOCK_DIRTY;
478
479 /* ¸üРblockRepTable¡¢blockTable */
480 if( is_upthreshold == 1 )
481 {
482 zftl_debug(" [zftl_write] ( is_upthreshold == 1 )\n");
483 zftl_debug(" [zftl_write] eraseblock zftl->blockTable[-%d-]\n", offset_block_phy);
484 if( zftl_erase_block(nand, firstBlock + offset_block_phy) )
485 {
486 /* ²Á³ýʧ°Ü£¬±ê¼ÇΪ»µ¿ì */
487 zftl_debug(" [zftl_write] eraseblock zftl->blockTable[-%d-] ERROR!\n",
488 (firstBlock + offset_block_phy) << erasesize);
489 zftl->blockTable[offset_block_phy] = BLOCK_BAD;
490 nand->_block_markbad(nand, (loff_t)((firstBlock + offset_block_phy) << erasesize_shift)); /* ±ê¼Ç»µ¿é£¬¸üлµ¿é±í */
491 }
492 else
493 zftl->blockTable[offset_block_phy] = BLOCK_FREE;
494 }
495 zftl_debug("\n");
496
497 left_to_write -= write_length;
498 offset += write_length;
499 buffer += write_length;
500 }
501 else /* zftl->blockRepTable[block_log] == BLOCK_NIL */
502 {
503 /* ´ËÂß¼­µØÖ·µÚÒ»´Î±»Ð´ÈëÊý¾Ý */
504 zftl_debug(" [zftl_write] zftl->blockRepTable[%d] == BLOCK_NIL\n", block_log);
505
506 /* ²¢¸üÐÂOOB */
507 zftl_oob.logicBlockID = block_log;
508 zftl_oob.used = 0x1;
509 zftl_oob.version = 0x1;
510 memcpy(zftl_oob.head, CONFIG_ZFLT_HEAD, CONFIG_ZFLT_HEAD_BYTE); /* ¿½±´zftlÍ· */
511
512 /* Ìî³ä¸üРdata */
513 if (left_to_write < (erasesize - block_offset))
514 write_length = left_to_write;
515 else
516 write_length = nand->erasesize - block_offset;
517
518 memcpy(blockbuf + block_offset, buffer, write_length);
519 zftl_debug(" [zftl_write] update the date ( -0x%0x-, -0x%0x- )\n",
520 block_offset, write_length);
521
522 /* ѰÕÒÒ»¸ö FREE µÄÎïÀí¿é */
523 find_next_free_block_2:
524 if( zftl_find_free_block(zftl, &block_new) )
525 {
526 /* ûÓÐÕÒµ½FREE¿é */
527 printk(" [zftl_write] there is enough block, please enlarge the partition\n");
528 return CAN_NOT_FIND_FREE_BLOCK;
529 }
530
531 /* дÈëÒ»¿é */
532 zftl_debug(" [zftl_write_block] nand->write( -0x%0x-, -0x%0x-)\n",
533 ((firstBlock + block_new) << erasesize_shift), erasesize);
534 memcpy(oob + g_oob_zftl_offset,(uint8_t *)&zftl_oob,sizeof(struct zftl_oob));
535
536 if( zftl_write_block(nand, (loff_t)((firstBlock + block_new) << erasesize_shift), &retlen,
537 (uint8_t *)oob, blockbuf) )
538 {
539 /* дÊý¾Ýʧ°Üʱ£¬±ê¼ÇBBT£¬¸üРTABLE£¬ÖØÐ²éÕÒеĿéд */
540 printk(" -ERROR-\n");
541 zftl->blockTable[block_new] = BLOCK_BAD;
542 nand->_block_markbad(nand, (loff_t)((firstBlock + block_new) << erasesize_shift));
543 goto find_next_free_block_2;
544 }
545
546 /* ¸üРblockRepTable¡¢blockTable */
547 zftl->blockRepTable[zftl_oob.logicBlockID] = block_new;
548
549 zftl_debug(" [zftl_write2] zftl->blockRepTable[oob->logicBlockID] = %d,oob->logicBlockID = %d\n", zftl->blockRepTable[zftl_oob.logicBlockID], zftl_oob.logicBlockID);
550
551 zftl->blockTable[block_new] = BLOCK_USED;
552
553 zftl_debug("\n");
554
555 left_to_write -= write_length;
556 offset += write_length;
557 buffer += write_length;
558 }
559
560 }
561
562 /* Added by zhouqi for xxx, 2014/04/23 */
563 zftl_garbage_collect(zftl);
564 zftl_debug("\n");
565
566 return 0;
567}
568
569
570int zftl_read(struct ZFTLrecord *zftl, uint32_t from, uint32_t len, u_char *buffer)
571{
572 int ret = 0;
573 uint32_t offset_block_phy;
574 uint32_t left_to_read = len;
575 uint32_t read_length = 0;
576 uint32_t retlen = 0;
577 u_char *buf = buffer;
578 uint32_t offset = from;
579 uint32_t block_offset = 0;
580 uint32_t block_log = 0;
581 uint32_t erasesize = zftl->erasesize;
582 uint32_t erasesize_shift = zftl->erasesize_shift;
583 nand_info_t *nand = zftl->nand;
584 uint32_t firstBlock = zftl->firstBlock;
585
586 if((zftl == NULL) || (buf == NULL))
587 {
588 BUG();
589 }
590
591 while( left_to_read > 0 )
592 {
593 block_offset = offset & (zftl->erasesize - 1);
594 block_log = offset >> zftl->erasesize_shift;
595
596 /* »ñÈ¡Âß¼­¿é¶ÔÓ¦µÄÎïÀí¿é */
597 if( zftl->blockRepTable[block_log] != BLOCK_NIL )
598 offset_block_phy = zftl->blockRepTable[block_log];
599 else
600 {
601 /* µ±Ã»ÓÐдÈëÊý¾Ýʱ£¬Ã»ÓÐÓ³Éä¹ØÏµ£¬¶ÁÈ¡Êý¾ÝȫΪ 0XFF */
602
603 if (left_to_read < (erasesize - block_offset))
604 read_length = left_to_read;
605 else
606 read_length = nand->erasesize - block_offset;
607
608 memset(buf, 0xff, read_length);
609
610 left_to_read -= read_length;
611 offset += read_length;
612 buf += read_length;
613
614 continue;
615
616 }
617
618 if (left_to_read < (erasesize - block_offset))
619 read_length = left_to_read;
620 else
621 read_length = nand->erasesize - block_offset;
622
623
624 zftl_debug(" [zftl_read] nand->read( -0x%0x-, -0x%0x-)\n",
625 ((firstBlock + offset_block_phy) << erasesize_shift) + block_offset,
626 read_length);
627 ret = nand->_read(nand, ((firstBlock + offset_block_phy) << erasesize_shift) + block_offset,
628 read_length, &retlen, buf);
629 if (ret || retlen != read_length)
630 {
631 printk(KERN_ERR"[zfltl]: -zftl_read- error\n");
632 //return -1;
633#ifdef CONFIG_MTD_NVRESUME
634 if((!zOss_NvInResume())&&(zftl==zftl_info[1])&&(zftl_res != 1))
635 {
636 return -1;
637 }
638#endif
639 }
640
641 left_to_read -= read_length;
642 offset += read_length;
643 buf += read_length;
644 }
645
646 zftl_debug("\n");
647 return 0;
648}
649
650
651struct ZFTLrecord * zftl_get_ZFTLrecord_byname(char* part_name)
652{
653 uint32_t i;
654
655 for(i = 0; zftl_partition_name[i] != NULL; i++ )
656 {
657 if(zftl_info[i]!=NULL)
658 {
659 if(strcmp(zftl_info[i]->mbd.mtd->name, part_name) == 0)
660 {
661 return zftl_info[i];
662 }
663 }
664
665 }
666 return NULL;
667}
668
669
670int zftl_init(unsigned char *part_name,struct ZFTLrecord *zftlinfo )
671{
672 nand_info_t *nand = mtd_fota;
673 //uint32_t i, j,k, block;
674 uint32_t k = 0;
675 struct ZFTLrecord *zftl = NULL;
676 uint32_t partition_size = 0;
677 uint32_t partition_offest = 0;
678 struct cmdline_mtd_partition *part;
679
680 printk( "zftl[%d] is %s\n",partnum,part_name);
681
682 /* ZFTLrecord½á¹¹ÌåÄÚ´æÉêÇë */
683 zftl_info[partnum] = zftlinfo;
684 if (!zftl_info[partnum])
685 {
686 printk( "zftl: out of memory for data structure ZFTLrecord\n");
687 return 1;
688 }
689 zftl = zftl_info[partnum];
690
691 zftl->nand = nand;
692 zftl->erasesize = nand->erasesize;
693 zftl->writesize = nand->writesize;
694 zftl->erasesize_shift = ffs(nand->erasesize) - 1;
695 zftl->writesize_shift = ffs(nand->writesize) - 1;
696 zftl->oobsize = nand->oobsize;
697
698 part = partitions;
699
700 for(k=0;k<part->num_parts;k++)
701 {
702 if ( strcmp( (char *)part->parts[k].name, part_name ) == 0 )
703 break;
704
705 } /* nvr */
706
707 partition_offest = part->parts[k].offset;
708 partition_size = part->parts[k].size;
709
710 if ( strcmp(part_name,"cdrom") == 0 )
711 {
712 cdrom_partsize = partition_size;
713 }
714
715 if ( strcmp(part_name,"nvro") == 0 )
716 {
717 nvro_partsize = partition_size;
718 printk("nvro_partsize=0x%0x\n",nvro_partsize);
719 }
720
721 zftl->firstBlock= partition_offest >> zftl->erasesize_shift; /* ¾ßÌåµÄÊýÖµ´Ó·ÖÇøÖлñµÃ */
722 zftl->numBlocks = partition_size / zftl->erasesize; /* ÔõôȷÈÏÇøÓò·¶Î§ zhouqi,ʵ¼ÊʹÓÃʱ¿éºÅÒª -1 ?*/
723
724 /* ¿é»º´æÉêÇë */
725 zftl->blockbuf = kmalloc(zftl->erasesize, GFP_KERNEL);
726 if (!zftl->blockbuf)
727 {
728 printk( "zftl: out of memory for data structure blockbuf\n");
729 goto failed_alloc_blockbuf;
730 }
731
732 /* OOB»º´æÉêÇë */
733 zftl->oobbuf = kmalloc(zftl->oobsize, GFP_KERNEL);
734 if (!zftl->oobbuf)
735 {
736 printk( "zftl: out of memory for data oobbuf\n");
737 goto failed_alloc_oobbuf;
738 }
739
740 /* blockRepTable±íÄÚ´æÉêÇë, ³õʼ»¯Îª 0xFFFF*/
741 zftl->blockRepTable = kmalloc(zftl->numBlocks * sizeof(zftl->blockRepTable), GFP_KERNEL);
742 if (!zftl->blockRepTable)
743 {
744 printk( "zftl: out of memory for data structure blockRepTable\n");
745 goto failed_alloc_blockreptable;
746 }
747 memset(zftl->blockRepTable, 0xff, zftl->numBlocks * sizeof(zftl->blockRepTable));
748
749 /* versionTable±íÄÚ´æÉêÇë */
750 /* ³õʼ»¯Îª¶¼Îª0£¬NANDÖеÄÊý¾Ýversion×îСΪ 1 */
751 zftl->versionTable = kzalloc(zftl->numBlocks * sizeof(zftl->versionTable), GFP_KERNEL);
752 if (!zftl->versionTable)
753 {
754 printk( "zftl: out of memory for data structure versionTable\n");
755 goto failed_alloc_versionTable;
756 }
757
758 /* blockTable±íÄÚ´æÉêÇë */
759 zftl->blockTable = kzalloc(zftl->numBlocks * sizeof(zftl->blockTable), GFP_KERNEL);
760 if (!zftl->blockTable)
761 {
762 printk( "zftl: out of memory for data structure blockTable\n");
763 goto failed_alloc_blocktable;
764 }
765
766 /* ·ÖÎö¹ÒÔØzftl·ÖÇø£¬½¨Á¢ÄÚ´æ±í */
767 if ( zftl_setup_table((zftl), &zftl->is_writed))
768 {
769 printk( "zftl: could not mount device\n");
770 goto failed_setup_table;
771 }
772
773 zftl_debug(" [zftl_init] is_writed[%d] = %d\n", partnum, zftl->is_writed);
774 partnum++;
775 if(!mutex_inited)
776 {
777 mutex_init(&zftl_mutex);
778 mutex_inited = 1;
779 }
780 return 0;
781
782failed_setup_table:
783 kfree(zftl->blockTable);
784failed_alloc_blocktable:
785 kfree(zftl->versionTable);
786failed_alloc_versionTable:
787 kfree(zftl->blockRepTable);
788failed_alloc_blockreptable:
789 kfree(zftl->oobbuf);
790failed_alloc_oobbuf:
791 kfree(zftl->blockbuf);
792failed_alloc_blockbuf:
793 kfree(zftl);
794 return 1;
795}
796
797static void zftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
798{
799 uint32_t i;
800 struct ZFTLrecord *zftl = NULL;
801
802 for(i=0; zftl_partition_name[i] != NULL; i++)
803 {
804
805 if(strcmp(mtd->name, zftl_partition_name[i]) == 0)
806 {
807
808 break;
809 }
810 }
811
812 if(zftl_partition_name[i] == NULL)
813 {
814 return;
815 }
816
817 zftl = kzalloc(sizeof(struct ZFTLrecord), GFP_KERNEL);
818 if (!zftl)
819 {
820 kfree(zftl);
821 return;
822 }
823 zftl->mbd.mtd = mtd;
824 zftl->mbd.devnum = mtd->index;
825 zftl->mbd.tr = tr;
826 zftl->mbd.size = mtd->size >> 12;
827
828 zftl_init(mtd->name,zftl);
829
830 if (add_mtd_blktrans_dev(&zftl->mbd))
831 {
832 kfree(zftl);
833 }
834
835 return;
836}
837static void zftl_remove_dev(struct mtd_blktrans_dev *dev)
838{
839 del_mtd_blktrans_dev(dev);
840}
841static int zftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
842 char *buffer)
843{
844 struct ZFTLrecord *zftl = NULL;
845 int ret = 0;
846
847 mutex_lock(&zftl_mutex);
848
849 zftl = zftl_get_ZFTLrecord_byname(mbd->mtd->name);
850 if(!zftl)
851 {
852 mutex_unlock(&zftl_mutex);
853 return -2;
854 }
855 ret = zftl_read(zftl, block<<12, (uint32_t)4096, (u_char *)buffer);
856 mutex_unlock(&zftl_mutex);
857 return ret;
858}
859
860static int zftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
861 char *buffer)
862{
863 struct ZFTLrecord *zftl = NULL;
864 int ret = 0;
865
866 mutex_lock(&zftl_mutex);
867
868 zftl = zftl_get_ZFTLrecord_byname(mbd->mtd->name);
869 if(!zftl)
870 {
871 mutex_unlock(&zftl_mutex);
872 return -2;
873 }
874 ret = zftl_write(zftl, block<<12, (uint32_t)4096, (u_char *)buffer);
875 mutex_unlock(&zftl_mutex);
876 return ret;
877}
878
879int zftl_nvread(uint32_t from, uint32_t len, u_char *buffer)
880{
881 mutex_lock(&zftl_mutex);
882 struct ZFTLrecord *zftl = NULL;
883 int ret = 0;
884
885 //zftl = zftl_info[4]; /* ramdisk */
886 zftl = zftl_get_ZFTLrecord_byname("ramdisk");
887 if(!zftl)
888 {
889 mutex_unlock(&zftl_mutex);
890 return -2;
891 }
892 ret = zftl_read(zftl, from, len, buffer);
893 mutex_unlock(&zftl_mutex);
894 return ret;
895
896
897}
898EXPORT_SYMBOL_GPL(zftl_nvread);
899
900int zftl_nvwrite(uint32_t from, uint32_t len, u_char *buffer)
901{
902 mutex_lock(&zftl_mutex);
903 struct ZFTLrecord *zftl = NULL;
904 int ret = 0;
905
906 //zftl = zftl_info[4]; /* ramdisk */
907 zftl = zftl_get_ZFTLrecord_byname("ramdisk");
908 if(!zftl)
909 {
910 mutex_unlock(&zftl_mutex);
911 return -2;
912 }
913 ret = zftl_write(zftl, from, len, buffer);
914 mutex_unlock(&zftl_mutex);
915 return ret;
916
917
918}
919EXPORT_SYMBOL_GPL(zftl_nvwrite);
920
921int zftl_wrapper_write(char *part_name, int dwStart, int dwLen, char* from)
922{
923 int ret = 0;
924 struct ZFTLrecord *zftl = NULL;
925
926 mutex_lock(&zftl_mutex);
927
928 if((part_name == NULL) || (from == NULL))
929 {
930 mutex_unlock(&zftl_mutex);
931 return -5;
932 }
933
934 zftl = zftl_get_ZFTLrecord_byname(part_name);
935 if(zftl == NULL)
936 {
937 BUG();
938 mutex_unlock(&zftl_mutex);
939 return -1; //×ö¶ÏÑÔ
940 }
941
942 ret = zftl_write(zftl, dwStart, dwLen, from);
943 if(ret != 0)
944 {
945 mutex_unlock(&zftl_mutex);
946 return ret;
947 }
948
949 mutex_unlock(&zftl_mutex);
950
951 return 0;
952}
953EXPORT_SYMBOL_GPL(zftl_wrapper_write);
954
955int zftl_wrapper_read(char *part_name, int dwStart, int dwLen, char* to)
956{
957 int ret = 0;
958 struct ZFTLrecord *zftl = NULL;
959
960 mutex_lock(&zftl_mutex);
961
962 if((part_name == NULL) || (to == NULL))
963 {
964 mutex_unlock(&zftl_mutex);
965 return -5;
966 }
967
968 zftl = zftl_get_ZFTLrecord_byname(part_name);
969 if(zftl == NULL)
970
971 {
972 BUG();
973 mutex_unlock(&zftl_mutex);
974 return -1; //×ö¶ÏÑÔ
975 }
976
977 ret = zftl_read(zftl, dwStart, dwLen, to);
978 if(ret != 0)
979 {
980 mutex_unlock(&zftl_mutex);
981 return ret;
982 }
983
984 mutex_unlock(&zftl_mutex);
985 return 0;
986}
987EXPORT_SYMBOL_GPL(zftl_wrapper_read);
988
989int nand_NvRead(int dwStart, int dwLen, char* to)
990{
991 mutex_lock(&zftl_mutex);
992 struct ZFTLrecord *zftl = NULL;
993 int ret = 0;
994
995 if( dwStart < nvro_partsize )
996 {
997 zftl = zftl_get_ZFTLrecord_byname("nvro"); /*NVR,0~1M*/
998 }
999 else
1000 {
1001 zftl = zftl_get_ZFTLrecord_byname("nvrw"); /* NVRW, 1~5M*/
1002 dwStart -= nvro_partsize;
1003 }
1004 if(!zftl)
1005 {
1006 mutex_unlock(&zftl_mutex);
1007 return -2;
1008 }
1009 ret = zftl_read(zftl, (uint32_t)dwStart, (uint32_t)dwLen, (u_char*)to);
1010 mutex_unlock(&zftl_mutex);
1011#ifdef CONFIG_MTD_NVRESUME
1012 if(ret == -1)
1013 {
1014 zftl_res = 1;
1015 zOss_NvSetErrorAddr(dwStart + nvro_partsize);
1016 hal_Comm_Soft_Reset(RESET_TO_NORMAL);
1017 }
1018#endif
1019 return ret;
1020
1021}
1022EXPORT_SYMBOL_GPL(nand_NvRead);
1023
1024int nand_NvProgram(int dwStart, int dwLen, char* from)
1025{
1026 mutex_lock(&zftl_mutex);
1027 struct ZFTLrecord *zftl = NULL;
1028 int ret = 0;
1029
1030 if( dwStart < nvro_partsize )
1031 {
1032 zftl = zftl_get_ZFTLrecord_byname("nvro"); /*NVR,0~1M*/
1033 }
1034 else
1035 {
1036 zftl = zftl_get_ZFTLrecord_byname("nvrw"); /* NVRW, 1~5M*/
1037 dwStart -= nvro_partsize;
1038 }
1039 if(!zftl)
1040 {
1041 mutex_unlock(&zftl_mutex);
1042 return -2;
1043 }
1044 ret = zftl_write(zftl, (uint32_t)dwStart, (uint32_t)dwLen, (u_char*)from);
1045 mutex_unlock(&zftl_mutex);
1046#ifdef CONFIG_MTD_NVRESUME
1047 if(ret == -1)
1048 {
1049 zftl_res = 1;
1050 zOss_NvSetErrorAddr(dwStart + nvro_partsize);
1051 hal_Comm_Soft_Reset(RESET_TO_NORMAL);
1052 }
1053#endif
1054 return ret;
1055}
1056EXPORT_SYMBOL_GPL(nand_NvProgram);
1057
1058
1059int nand_CdromRead(void *devData,void *buffer, uint32_t blkcnt, uint32_t pos )
1060{
1061 mutex_lock(&zftl_mutex);
1062 struct ZFTLrecord *zftl = NULL;
1063 int ret = 0;
1064
1065 zftl = zftl_get_ZFTLrecord_byname("cdrom");
1066 if(!zftl)
1067 {
1068 mutex_unlock(&zftl_mutex);
1069 return -2;
1070 }
1071 ret = zftl_read(zftl, (pos<<9), (uint32_t)(blkcnt<<9), (u_char *)buffer);
1072 if(ret == 0)
1073 {
1074 ret = blkcnt;
1075 }
1076 mutex_unlock(&zftl_mutex);
1077 return ret;
1078
1079}
1080EXPORT_SYMBOL_GPL(nand_CdromRead);
1081
1082int nand_CdromProgram(void *devData,void *buffer, uint32_t blkcnt, uint32_t pos)
1083{
1084 mutex_lock(&zftl_mutex);
1085 struct ZFTLrecord *zftl = NULL;
1086 int ret = 0;
1087
1088 zftl = zftl_get_ZFTLrecord_byname("cdrom");
1089 if(!zftl)
1090 {
1091 mutex_unlock(&zftl_mutex);
1092 return -2;
1093 }
1094 ret = zftl_write(zftl, (pos<<9), (uint32_t)(blkcnt<<9), (u_char *)buffer);
1095
1096 if(ret == 0)
1097 {
1098 ret = blkcnt;
1099 }
1100 mutex_unlock(&zftl_mutex);
1101 return ret;
1102}
1103EXPORT_SYMBOL_GPL(nand_CdromProgram);
1104int nand_SmsRead(int dwStart, int dwLen, char* to)
1105{
1106 mutex_lock(&zftl_mutex);
1107 struct ZFTLrecord *zftl = NULL;
1108 int ret = 0;
1109
1110 zftl = zftl_get_ZFTLrecord_byname("sms");
1111 if(!zftl)
1112 {
1113 mutex_unlock(&zftl_mutex);
1114 return -2;
1115 }
1116 ret = zftl_read(zftl, (uint32_t)dwStart, (uint32_t)dwLen, (u_char*)to);
1117 mutex_unlock(&zftl_mutex);
1118 return ret;
1119
1120}
1121EXPORT_SYMBOL_GPL(nand_SmsRead);
1122
1123int nand_SmsProgram(int dwStart, int dwLen, char* from)
1124{
1125 mutex_lock(&zftl_mutex);
1126 struct ZFTLrecord *zftl = NULL;
1127 int ret = 0;
1128
1129 zftl = zftl_get_ZFTLrecord_byname("sms");
1130 if(!zftl)
1131 {
1132 mutex_unlock(&zftl_mutex);
1133 return -2;
1134 }
1135 ret = zftl_write(zftl, (uint32_t)dwStart, (uint32_t)dwLen, (u_char*)from);
1136 mutex_unlock(&zftl_mutex);
1137 return ret;
1138}
1139EXPORT_SYMBOL_GPL(nand_SmsProgram);
1140
1141int nand_ResetFlagProgram(int dwStart, int dwLen, char* from)
1142{
1143 mutex_lock(&zftl_mutex);
1144 struct ZFTLrecord *zftl = NULL;
1145 int ret = 0;
1146
1147
1148 //zftl = zftl_info[2]; /* fotaflag */
1149 zftl = zftl_get_ZFTLrecord_byname("fotaflag");
1150 if(!zftl)
1151 {
1152 mutex_unlock(&zftl_mutex);
1153 return -2;
1154 }
1155 ret = zftl_write(zftl, (uint32_t)dwStart, (uint32_t)dwLen, (u_char*)from);
1156 mutex_unlock(&zftl_mutex);
1157
1158 return ret;
1159}
1160EXPORT_SYMBOL_GPL(nand_ResetFlagProgram);
1161
1162static struct mtd_blktrans_ops zftl_tr = {
1163 .name = "zftl",
1164 .major = 35,
1165 .part_bits = 0,
1166 .blksize = 4096,
1167 .readsect = zftl_readblock,
1168 .writesect = zftl_writeblock,
1169 .add_mtd = zftl_add_mtd,
1170 .remove_dev = zftl_remove_dev,
1171 .owner = THIS_MODULE,
1172};
1173
1174static int __init init_zftl(void)
1175{
1176 return register_mtd_blktrans(&zftl_tr);
1177}
1178
1179static void __exit cleanup_zftl(void)
1180{
1181 deregister_mtd_blktrans(&zftl_tr);
1182}
1183
1184module_init(init_zftl);
1185module_exit(cleanup_zftl);
1186
1187MODULE_LICENSE("GPL");
1188MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al.");
1189MODULE_DESCRIPTION("Support code for NAND Flash Translation Layer, used on M-Systems DiskOnChip 2000 and Millennium");
1190
1191
1192
1193
1194
1195
1196