5d9221b0fee101ad8103f8e7ee8268d2871dc09c
[firefly-linux-kernel-4.4.55.git] / drivers / mtd / rknand / rknand_base.c
1 /*\r
2  *  linux/drivers/mtd/rknand/rknand_base.c\r
3  *\r
4  *  Copyright (C) 2005-2009 Fuzhou Rockchip Electronics\r
5  *  ZYF <zyf@rock-chips.com>\r
6  *\r
7  *   \r
8  */\r
9 \r
10 #include <linux/module.h>\r
11 #include <linux/sched.h>\r
12 #include <linux/delay.h>\r
13 #include <linux/init.h>\r
14 #include <linux/slab.h>\r
15 #include <linux/platform_device.h>\r
16 #include <linux/mtd/mtd.h>\r
17 #include <linux/mtd/partitions.h>\r
18 #include <linux/mutex.h>\r
19 #include <linux/kthread.h>\r
20 #include <linux/reboot.h>\r
21 #include <asm/io.h>\r
22 #include <asm/mach/flash.h>\r
23 #include "api_flash.h"\r
24 \r
25 extern int rknand_queue_read(int Index, int nSec, void *buf);\r
26 extern int rknand_queue_write(int Index, int nSec, void *buf,int mode);\r
27 extern int rknand_buffer_init(void);\r
28 extern void rknand_buffer_shutdown(void);\r
29 extern void rknand_buffer_sync(void);\r
30 \r
31 #define DRIVER_NAME     "rk29xxnand"\r
32 const char rknand_base_version[] = "rknand_base.c version: 4.20 20110127";\r
33 #define NAND_DEBUG_LEVEL0 0\r
34 #define NAND_DEBUG_LEVEL1 1\r
35 #define NAND_DEBUG_LEVEL2 2\r
36 #define NAND_DEBUG_LEVEL3 3\r
37 //#define PAGE_REMAP\r
38 \r
39 #ifndef CONFIG_RKFTL_PAGECACHE_SIZE\r
40 #define CONFIG_RKFTL_PAGECACHE_SIZE  64 //¶¨ÒåpageÓ³ÉäÇø´óС£¬µ¥Î»ÎªMB,mount ÔÚ/data/dataÏ¡£\r
41 #endif\r
42 \r
43 unsigned long SysImageWriteEndAdd = 0;\r
44 int g_num_partitions = 0;\r
45 \r
46 #ifdef CONFIG_MTD_NAND_RK29XX_DEBUG\r
47 static int s_debug = CONFIG_MTD_NAND_RK29XX_DEBUG_VERBOSE;\r
48 #undef NAND_DEBUG\r
49 #define NAND_DEBUG(n, format, arg...) \\r
50         if (n <= s_debug) {      \\r
51                 printk(format,##arg); \\r
52         }\r
53 #else\r
54 #undef NAND_DEBUG\r
55 #define NAND_DEBUG(n, arg...)\r
56 static const int s_debug = 0;\r
57 #endif\r
58 \r
59 /*\r
60 * RK28 LBA PARTITIONS,the size and offset value below is default value in this program,\r
61 * when RK28 LBA FLASH init,the value will be modify to the value in the nand flash.\r
62 */\r
63 static struct mtd_partition rk28_partition_info[] = {\r
64         { \r
65           name: "misc",\r
66           offset:  0x2000*0x200,\r
67           size:    0x2000*0x200,//100MB\r
68         },\r
69 \r
70         { \r
71           name: "kernel",\r
72           offset:  0x4000*0x200,\r
73           size:   0x4000*0x200,//200MB\r
74         },\r
75 \r
76         { \r
77           name: "boot",\r
78           offset:  0x8000*0x200,\r
79           size:   0x2000*0x200,//200MB\r
80         },\r
81 \r
82         { \r
83           name: "system",\r
84           offset:  0xE000*0x200,\r
85           size:   0x38000*0x200,//200MB\r
86         },\r
87      \r
88 };\r
89 \r
90 #ifdef PAGE_REMAP\r
91 static struct mtd_partition rk28_page_part_info[] = {\r
92         { \r
93           name: "pagecache",\r
94           offset:  0,\r
95           size:    CONFIG_RKFTL_PAGECACHE_SIZE * 0x800*0x200,//32MB\r
96         },\r
97 \r
98         { \r
99           name: "swap",\r
100           offset:  (CONFIG_RKFTL_PAGECACHE_SIZE) * 0x800*0x200,\r
101           size:    64 * 0x800*0x200,//64MB\r
102         },\r
103 };\r
104 #endif\r
105 /*\r
106  * onenand_state_t - chip states\r
107  * Enumeration for OneNAND flash chip state\r
108  */\r
109 typedef enum {\r
110         FL_READY,\r
111         FL_READING,\r
112         FL_WRITING,\r
113         FL_ERASING,\r
114         FL_SYNCING,\r
115         FL_UNVALID,\r
116 } rknand_state_t;\r
117 \r
118 struct rknand_chip {\r
119         wait_queue_head_t       wq;\r
120         rknand_state_t          state;\r
121         int rknand_schedule_enable;//1 enable ,0 disable\r
122     void (*pFlashCallBack)(void);//call back funtion\r
123 };\r
124 \r
125 struct rknand_info {\r
126         struct mtd_info         mtd;\r
127     struct mtd_info             page_mtd;    \r
128         struct mtd_partition *parts;\r
129         struct rknand_chip      rknand;\r
130     struct task_struct *thread;\r
131 };\r
132 \r
133 struct rknand_info * gpNandInfo;\r
134 \r
135 #include <linux/proc_fs.h>\r
136 #include <linux/version.h>\r
137 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))\r
138 #define NANDPROC_ROOT  (&proc_root)\r
139 #else\r
140 #define NANDPROC_ROOT  NULL\r
141 #endif\r
142 \r
143 static struct proc_dir_entry *my_proc_entry;\r
144 extern int rkNand_proc_ftlread(char *page);\r
145 extern int rkNand_proc_bufread(char *page);\r
146 static int rkNand_proc_read(char *page,\r
147                            char **start,\r
148                            off_t offset, int count, int *eof, void *data)\r
149 {\r
150         char *buf = page;\r
151         int step = offset;\r
152         *(int *)start = 1;\r
153         if(step == 0)\r
154         {\r
155         buf += sprintf(buf, "%s\n", rknand_base_version);\r
156         buf += rkNand_proc_ftlread(buf);\r
157 #ifdef  CONFIG_MTD_RKNAND_BUFFER\r
158         buf += rkNand_proc_bufread(buf);\r
159 #endif        \r
160     }\r
161         return buf - page < count ? buf - page : count;\r
162 }\r
163 \r
164 static void rk28nand_create_procfs(void)\r
165 {\r
166     /* Install the proc_fs entry */\r
167     my_proc_entry = create_proc_entry("rk29xxnand",\r
168                            S_IRUGO | S_IFREG,\r
169                            NANDPROC_ROOT);\r
170 \r
171     if (my_proc_entry) {\r
172         my_proc_entry->write_proc = NULL;\r
173         my_proc_entry->read_proc = rkNand_proc_read;\r
174         my_proc_entry->data = NULL;\r
175     } \r
176 }\r
177 \r
178 void rkNand_cond_resched(void)\r
179 {\r
180     if(gpNandInfo->rknand.rknand_schedule_enable == 1)\r
181         {\r
182         //msleep(1);\r
183         //mdelay(1);\r
184         cond_resched();\r
185     }\r
186 }\r
187 \r
188 #ifdef  CONFIG_MTD_RKNAND_BUFFER\r
189 static int rk28xxnand_read(struct mtd_info *mtd, loff_t from, size_t len,\r
190         size_t *retlen, u_char *buf)\r
191 {\r
192         int ret = 0;\r
193         int sector = len>>9;\r
194         int LBA = (int)(from>>9);\r
195     //printk("rk28xxnand_read: from=%x,len=%x,\n",(int)from,len);\r
196     if(sector)\r
197     {\r
198                 ret = rknand_queue_read(LBA, sector, buf);\r
199     }\r
200         *retlen = len;\r
201         return 0;//ret;\r
202 }\r
203 \r
204 static int rk28xxnand_write(struct mtd_info *mtd, loff_t from, size_t len,\r
205         size_t *retlen, const u_char *buf)\r
206 {\r
207         int ret = 0;\r
208         int sector = len>>9;\r
209         int LBA = (int)(from>>9);\r
210         //printk("*");\r
211         //printk(KERN_NOTICE "write: from=%lx,len=%x\n",(int)from,len);\r
212         if(sector)// cmy\r
213         {\r
214                 if(LBA < SysImageWriteEndAdd)//0x4E000)\r
215                 {\r
216                         printk(">>> FtlWriteImage: LBA=0x%08X  sector=%d\n",LBA, sector);\r
217             ret = rknand_queue_write(LBA, sector, (void *)buf,1);\r
218         }\r
219                 else\r
220         {\r
221             ret = rknand_queue_write(LBA, sector, (void *)buf,0);\r
222         }\r
223         }\r
224         *retlen = len;\r
225         return 0;//ret;\r
226 }\r
227 #else\r
228 \r
229 void rknand_queue_cond_resched(void)\r
230 {\r
231     ;\r
232 }\r
233 \r
234 static int rknand_get_device(int new_state)\r
235 {\r
236         struct rknand_chip *nand_info = &gpNandInfo->rknand;\r
237         DECLARE_WAITQUEUE(wait, current);\r
238         while (1) {\r
239                 if (nand_info->state == FL_READY) {\r
240                         nand_info->state = new_state;\r
241                         break;\r
242                 }\r
243                 NAND_DEBUG(NAND_DEBUG_LEVEL1,"FLASH not ready\n");\r
244                 set_current_state(TASK_UNINTERRUPTIBLE);\r
245                 add_wait_queue(&nand_info->wq, &wait);\r
246                 schedule();\r
247                 remove_wait_queue(&nand_info->wq, &wait);\r
248         }\r
249         return 0;\r
250 }\r
251 \r
252 static void rknand_release_device(void)\r
253 {\r
254         struct rknand_chip *nand_info = &gpNandInfo->rknand;\r
255         if(nand_info->pFlashCallBack)\r
256             nand_info->pFlashCallBack();//call back\r
257         nand_info->pFlashCallBack = NULL;\r
258         nand_info->state = FL_READY;\r
259         wake_up(&nand_info->wq);\r
260 }\r
261 \r
262 static int rk28xxnand_read(struct mtd_info *mtd, loff_t from, size_t len,\r
263         size_t *retlen, u_char *buf)\r
264 {\r
265         int ret = 0;\r
266         int sector = len>>9;\r
267         int LBA = (int)(from>>9);\r
268     rknand_get_device(FL_READING);\r
269     if(sector)\r
270     {\r
271         {\r
272                     ret = NandRead(LBA, sector, buf);\r
273         }\r
274     }\r
275     rknand_release_device();\r
276         *retlen = len;\r
277         return 0;//ret;\r
278 }\r
279 \r
280 static int rk28xxnand_write(struct mtd_info *mtd, loff_t from, size_t len,\r
281         size_t *retlen, const u_char *buf)\r
282 {\r
283         int ret = 0;\r
284         int sector = len>>9;\r
285         int LBA = (int)(from>>9);\r
286     //NAND_DEBUG(NAND_DEBUG_LEVEL0,"+");\r
287         //printk(KERN_NOTICE "write: from=%lx,len=%x\n",(int)from,len);\r
288     rknand_get_device(FL_WRITING);\r
289         if(sector)// cmy\r
290         {\r
291                 if(LBA < SysImageWriteEndAdd)//0x4E000)\r
292                 {\r
293                         printk(">>> FtlWriteImage: LBA=0x%08X  sector=%d\n",LBA, sector);\r
294                         ret = NandWriteImage(LBA&0xFFFFFFE0, sector, (void *)buf);// LBA align to 32\r
295         }\r
296                 else\r
297         {\r
298             ret = NandWrite(LBA, sector, (void *)buf);\r
299         }\r
300         }\r
301     rknand_release_device();\r
302         *retlen = len;\r
303         return 0;//ret;\r
304 }\r
305 #endif\r
306 \r
307 #ifdef PAGE_REMAP\r
308 static int rk28xxnand_page_write(struct mtd_info *mtd, loff_t from, size_t len,\r
309         size_t *retlen, const u_char *buf)\r
310 {\r
311         int ret = 0;\r
312         int sector = len;\r
313         int LBA = (int)(from);\r
314     NAND_DEBUG(NAND_DEBUG_LEVEL1,"*");\r
315     //printk("+");\r
316         //printk(KERN_NOTICE "pagewrite: from=%lx,len=%x\n",(int)from,len);\r
317     rknand_get_device(FL_WRITING);\r
318         if(sector)// cmy\r
319         {\r
320         ret = FtlPageWrite(LBA, sector, (void *)buf);\r
321         }\r
322     rknand_release_device();\r
323         *retlen = len;\r
324         return 0;//ret;\r
325 }\r
326 \r
327 static int rk28xxnand_page_read(struct mtd_info *mtd, loff_t from, size_t len,\r
328         size_t *retlen,  u_char *buf)\r
329 {\r
330         int ret = 0;\r
331         int sector = len;\r
332         int LBA = (int)(from);\r
333         NAND_DEBUG(NAND_DEBUG_LEVEL2,"-");\r
334     //printk("-");\r
335     //if(len&511)\r
336     //    printk("rk28xxnand_read: from=%x,len=%x,\n",(int)from,len);\r
337     rknand_get_device(FL_READING);\r
338     if(sector)\r
339     {\r
340         ret = FtlPageRead(LBA, sector,(void *) buf);\r
341     }\r
342     rknand_release_device();\r
343         *retlen = len;\r
344         return 0;//ret;\r
345 }\r
346 #endif\r
347 \r
348 static int rk28xxnand_erase(struct mtd_info *mtd, struct erase_info *instr)\r
349 {\r
350         int ret = 0;\r
351     if (instr->callback)\r
352                 instr->callback(instr);\r
353     NAND_DEBUG(NAND_DEBUG_LEVEL0,"rk28xxnand_erase,add:0x%012llx,len:0x%012llx\n",instr->addr,instr->len);\r
354         return ret;\r
355 }\r
356 \r
357 static void rk28xxnand_sync(struct mtd_info *mtd)\r
358 {\r
359         NAND_DEBUG(NAND_DEBUG_LEVEL0,"rk28xxnand_sync: \n");\r
360 #ifdef CONFIG_MTD_RKNAND_BUFFER\r
361     rknand_buffer_sync();\r
362 #endif\r
363 }\r
364 \r
365 extern void FtlWriteCacheEn(int);\r
366 static int rk28xxnand_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)\r
367 {\r
368         int sector = len >> 9;\r
369         int LBA = (int)(to >> 9);\r
370 \r
371         if (sector) {\r
372                 FtlWriteCacheEn(0);\r
373                 NandWrite(LBA, sector, (void *)buf);\r
374                 FtlWriteCacheEn(1);\r
375         }\r
376         *retlen = len;\r
377         return 0;\r
378 }\r
379 \r
380 static int rk28xxnand_block_isbad(struct mtd_info *mtd, loff_t ofs)\r
381 {\r
382         return 0;\r
383 }\r
384 \r
385 static int rk28xxnand_block_markbad(struct mtd_info *mtd, loff_t ofs)\r
386 {\r
387         return 0;\r
388 }\r
389 \r
390 static int rk28xxnand_init(struct rknand_info *nand_info)\r
391 {\r
392         struct mtd_info    *mtd = &nand_info->mtd;\r
393         struct rknand_chip *rknand = &nand_info->rknand;\r
394 #ifdef PAGE_REMAP\r
395         struct mtd_info    *page_mtd = &nand_info->page_mtd;\r
396 #endif    \r
397 \r
398         rknand->state = FL_READY;\r
399         rknand->rknand_schedule_enable = 1;\r
400         rknand->pFlashCallBack = NULL;\r
401         init_waitqueue_head(&rknand->wq);\r
402     NAND_DEBUG(NAND_DEBUG_LEVEL0,"FTLInit ...: \n");\r
403     if(NandInit())\r
404         {\r
405                 NAND_DEBUG(NAND_DEBUG_LEVEL0,"FTLInit Error: \n");\r
406                 return -ENXIO;\r
407     }\r
408     NAND_DEBUG(NAND_DEBUG_LEVEL0,"FTLInit OK: \n");\r
409     mtd->size = (uint64_t)NandGetCapacity()*0x200;\r
410     //readflash modify rk28_partition_info\r
411     \r
412     NAND_DEBUG(NAND_DEBUG_LEVEL0,"mtd->size: 0x%012llx\n",mtd->size);\r
413     mtd->oobsize = 0;\r
414     mtd->oobavail = 0;\r
415     mtd->ecclayout = 0;\r
416     mtd->erasesize = 8*0x200; //sectorFlashGetPageSize()\r
417     mtd->writesize = 8*0x200; //FlashGetPageSize()\r
418 \r
419         // Fill in remaining MTD driver data \r
420         mtd->type = MTD_NANDFLASH;//MTD_RAM;//\r
421         mtd->flags = (MTD_WRITEABLE|MTD_NO_ERASE);//\r
422         mtd->erase = rk28xxnand_erase;\r
423         mtd->point = NULL;\r
424         mtd->unpoint = NULL;\r
425         mtd->read = rk28xxnand_read;\r
426         mtd->write = rk28xxnand_write;\r
427         mtd->read_oob = NULL;\r
428         mtd->write_oob = NULL;\r
429         mtd->panic_write = rk28xxnand_panic_write;\r
430 \r
431         mtd->sync = rk28xxnand_sync;\r
432         mtd->lock = NULL;\r
433         mtd->unlock = NULL;\r
434         mtd->suspend = NULL;\r
435         mtd->resume = NULL;\r
436         mtd->block_isbad = rk28xxnand_block_isbad;\r
437         mtd->block_markbad = rk28xxnand_block_markbad;\r
438         mtd->owner = THIS_MODULE;\r
439 \r
440 #ifdef PAGE_REMAP\r
441     page_mtd->size = FtlGetPageZoneCapacity()*0x200;\r
442     //readflash modify rk28_partition_info\r
443     NAND_DEBUG(NAND_DEBUG_LEVEL0,"page_mtd->size: 0x%012llx\n",page_mtd->size);\r
444     page_mtd->oobsize = 0;\r
445     page_mtd->oobavail = 0;\r
446     page_mtd->ecclayout = 0;\r
447     page_mtd->erasesize = FlashGetPageSize()*0x200; //sector\r
448     page_mtd->writesize = FlashGetPageSize()*0x200;\r
449 \r
450         // Fill in remaining MTD driver data \r
451         page_mtd->type = MTD_NANDFLASH;//MTD_RAM;//\r
452         page_mtd->flags = (MTD_WRITEABLE|MTD_NO_ERASE);//\r
453         page_mtd->erase = rk28xxnand_erase;\r
454         page_mtd->point = NULL;\r
455         page_mtd->unpoint = NULL;\r
456         page_mtd->read = rk28xxnand_page_read;\r
457         page_mtd->write = rk28xxnand_page_write;\r
458         page_mtd->read_oob = NULL;\r
459         page_mtd->write_oob = NULL;\r
460         page_mtd->panic_write = NULL;\r
461 \r
462         page_mtd->sync = rk28xxnand_sync;\r
463         page_mtd->lock = NULL;\r
464         page_mtd->unlock = NULL;\r
465         page_mtd->suspend = NULL;\r
466         page_mtd->resume = NULL;\r
467         page_mtd->block_isbad = NULL;\r
468         page_mtd->block_markbad = NULL;\r
469         page_mtd->owner = THIS_MODULE;\r
470 #endif\r
471 \r
472     return 0;\r
473 }\r
474 \r
475 \r
476 /*\r
477  * CMY: Ôö¼ÓÁ˶ÔÃüÁîÐзÖÇøÐÅÏ¢µÄÖ§³Ö\r
478  *              ÈôcmdlineÓÐÌṩ·ÖÇøÐÅÏ¢£¬ÔòʹÓÃcmdlineµÄ·ÖÇøÐÅÏ¢½øÐзÖÇø\r
479  *              ÈôcmdlineûÓÐÌṩ·ÖÇøÐÅÏ¢£¬ÔòʹÓÃĬÈϵķÖÇøÐÅÏ¢(rk28_partition_info)½øÐзÖÇø\r
480  */\r
481 \r
482 #ifdef CONFIG_MTD_CMDLINE_PARTS\r
483 const char *part_probes[] = { "cmdlinepart", NULL }; \r
484 #endif \r
485 \r
486 static int rk28xxnand_add_partitions(struct rknand_info *nand_info)\r
487 {\r
488 #ifdef CONFIG_MTD_CMDLINE_PARTS\r
489     int num_partitions = 0; \r
490 \r
491         // ´ÓÃüÁîÐнâÎö·ÖÇøµÄÐÅÏ¢\r
492     num_partitions = parse_mtd_partitions(&(nand_info->mtd), part_probes, &nand_info->parts, 0); \r
493     printk("num_partitions = %d\n",num_partitions);\r
494     if(num_partitions > 0) { \r
495         int i;\r
496         for (i = 0; i < num_partitions; i++) \r
497         {\r
498             nand_info->parts[i].offset *= 0x200;\r
499             nand_info->parts[i].size   *=0x200;\r
500                     //printk(KERN_ERR"offset 0x%012llx  size :0x%012llx\n",nand_info->parts[i].offset, nand_info->parts[i].size);\r
501         }\r
502         nand_info->parts[num_partitions - 1].size = nand_info->mtd.size - nand_info->parts[num_partitions - 1].offset;\r
503         \r
504                 g_num_partitions = num_partitions;\r
505                 return add_mtd_partitions(&nand_info->mtd, nand_info->parts, num_partitions);\r
506     } \r
507 #endif \r
508         // Èç¹ûÃüÁîÐÐûÓÐÌṩ·ÖÇøÐÅÏ¢£¬ÔòʹÓÃĬÈϵķÖÇøÐÅÏ¢\r
509         printk("parse_mtd_partitions\n");\r
510 \r
511 //      rk28_partition_info[1].size = nand_info->mtd.size - ((ROOTFS_PART_SIZE + PARA_PART_SIZE + KERNEL_PART_SIZE)*0x100000);\r
512 //      rk28_partition_info[2].offset = rk28_partition_info[1].size + rk28_partition_info[1].offset;\r
513         g_num_partitions = sizeof(rk28_partition_info)/sizeof(struct mtd_partition);\r
514         return add_mtd_partitions(&nand_info->mtd, rk28_partition_info, sizeof(rk28_partition_info)/sizeof(struct mtd_partition));//MAX_FLASH_PARTITION);\r
515 }\r
516 \r
517 static int rknand_probe(struct platform_device *pdev)\r
518 {\r
519         struct rknand_info *nand_info;\r
520     struct mtd_partition *parts;\r
521     int i;\r
522         //struct resource *res = pdev->resource;\r
523         int err = 0;\r
524         NAND_DEBUG(NAND_DEBUG_LEVEL0,"rk28xxnand_probe: \n");\r
525         gpNandInfo = kzalloc(sizeof(struct rknand_info), GFP_KERNEL);\r
526         if (!gpNandInfo)\r
527                 return -ENOMEM;\r
528     \r
529     nand_info = gpNandInfo;\r
530     \r
531         nand_info->mtd.name = dev_name(&pdev->dev);//pdev->dev.bus_id\r
532         nand_info->mtd.priv = &nand_info->rknand;\r
533         nand_info->mtd.owner = THIS_MODULE;\r
534     \r
535         nand_info->page_mtd.name = dev_name(&pdev->dev);//pdev->dev.bus_id\r
536         nand_info->page_mtd.priv = &nand_info->rknand;\r
537         nand_info->page_mtd.owner = THIS_MODULE;\r
538 \r
539         if(rk28xxnand_init(nand_info))\r
540         {\r
541                 err = -ENXIO;\r
542                 goto  exit_free;\r
543         }\r
544 #ifdef  CONFIG_MTD_RKNAND_BUFFER\r
545         if(rknand_buffer_init())\r
546         {\r
547                 err = -ENXIO;\r
548                 goto  exit_free;\r
549         }\r
550 #endif  \r
551         rk28nand_create_procfs();\r
552         /*{\r
553             char pbuf[512];\r
554             GetSNSectorInfo(pbuf);\r
555         printk("SN: %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x",pbuf[2],pbuf[3],pbuf[4],pbuf[5],pbuf[6],pbuf[7],pbuf[8],pbuf[9],\r
556             pbuf[10],pbuf[11],pbuf[12],pbuf[13],pbuf[14],pbuf[15],pbuf[16],pbuf[17]);\r
557     } */  \r
558         \r
559         rk28xxnand_add_partitions(nand_info);\r
560 \r
561 #ifdef PAGE_REMAP\r
562     rk28_page_part_info[1].size = nand_info->page_mtd.size - rk28_page_part_info[0].size;\r
563     add_mtd_partitions(&nand_info->page_mtd, rk28_page_part_info, 2);\r
564 #endif\r
565  \r
566     parts = nand_info->parts;\r
567     for(i=0;i<g_num_partitions;i++)\r
568     {\r
569         printk(">>> part[%d]: name=%s offset=0x%012llx\n", i, parts[i].name, parts[i].offset);\r
570         if(strcmp(parts[i].name,"cache") == 0)\r
571         {\r
572             SysImageWriteEndAdd = (unsigned long)parts[i].offset>>9;//sector\r
573                 printk(">>> SysImageWriteEndAdd=0x%lx\n", SysImageWriteEndAdd);\r
574             break;\r
575         }\r
576     }\r
577 \r
578     NandSetSysProtAddr(SysImageWriteEndAdd);\r
579         dev_set_drvdata(&pdev->dev, nand_info);\r
580 \r
581         return 0;\r
582 \r
583 exit_free:\r
584         if(nand_info)\r
585         kfree(nand_info);\r
586 \r
587         return err;\r
588 }\r
589 #if 0\r
590 static int rknand_remove(struct device *dev)\r
591 {\r
592         struct platform_device *pdev = to_platform_device(dev);\r
593         struct rknand_info *nand_info = dev_get_drvdata(&pdev->dev);\r
594         struct resource *res = pdev->resource;\r
595         unsigned long size = res->end - res->start + 1;\r
596         NAND_DEBUG(NAND_DEBUG_LEVEL0,"rk28xx_rknand_remove: \n");\r
597         dev_set_drvdata(&pdev->dev, NULL);\r
598 \r
599         if (nand_info) {\r
600                 if (nand_info->parts)\r
601                         del_mtd_partitions(&nand_info->mtd);\r
602                 else\r
603                         del_mtd_device(&nand_info->mtd);\r
604 \r
605                 //rknand_release(&nand_info->mtd);\r
606                 release_mem_region(res->start, size);           \r
607                 kfree(nand_info);\r
608         }\r
609         return 0;\r
610 }\r
611 #endif\r
612 static int rknand_suspend(struct platform_device *pdev, pm_message_t state)\r
613 {\r
614     gpNandInfo->rknand.rknand_schedule_enable = 0;\r
615         NAND_DEBUG(NAND_DEBUG_LEVEL0,"rknand_suspend: \n");\r
616         return 0;\r
617 }\r
618 \r
619 static int rknand_resume(struct platform_device *pdev)\r
620 {\r
621     gpNandInfo->rknand.rknand_schedule_enable = 1;\r
622         NAND_DEBUG(NAND_DEBUG_LEVEL0,"rknand_resume: \n");\r
623         return 0;\r
624 }\r
625 \r
626 void rknand_shutdown(struct platform_device *pdev)\r
627 {\r
628 #ifdef CONFIG_MTD_RKNAND_BUFFER\r
629     //NAND_DEBUG(NAND_DEBUG_LEVEL0,"rknand_shutdown...\n");\r
630     printk("rknand_shutdown...\n");\r
631     gpNandInfo->rknand.rknand_schedule_enable = 0;\r
632     rknand_buffer_shutdown();    \r
633 #else\r
634         struct rknand_chip *nand_info = &gpNandInfo->rknand;\r
635     nand_info->rknand_schedule_enable = 0;\r
636         NAND_DEBUG(NAND_DEBUG_LEVEL0,"rknand_shutdown...\n");\r
637     if (nand_info->state == FL_READY)\r
638     {\r
639         nand_info->state = FL_UNVALID;\r
640         NandDeInit();\r
641         rknand_release_device();\r
642     }\r
643     else\r
644     {\r
645         nand_info->pFlashCallBack = NandDeInit;\r
646     }\r
647 #endif\r
648 }\r
649 \r
650 static struct platform_driver rknand_driver = {\r
651         .probe          = rknand_probe,\r
652         //.remove               = rknand_remove,\r
653         .suspend        = rknand_suspend,\r
654         .resume         = rknand_resume,\r
655         .shutdown   = rknand_shutdown,\r
656         .driver         = {\r
657                 .name   = DRIVER_NAME,\r
658                 .owner  = THIS_MODULE,\r
659                 //.bus          = &platform_bus_type,\r
660         },\r
661 };\r
662 \r
663 \r
664 MODULE_ALIAS(DRIVER_NAME);\r
665 \r
666 static int __init rknand_init(void)\r
667 {\r
668         int ret;\r
669         NAND_DEBUG(NAND_DEBUG_LEVEL0,"rknand_init: \n");\r
670         ret = platform_driver_register(&rknand_driver);\r
671         NAND_DEBUG(NAND_DEBUG_LEVEL0,"platform_driver_register:ret = %x \n",ret);\r
672         return ret;\r
673 }\r
674 \r
675 static void __exit rknand_exit(void)\r
676 {\r
677         //NAND_DEBUG(NAND_DEBUG_LEVEL0,"rknand_exit: \n");\r
678     //rknand_get_device(FL_UNVALID);\r
679     //FtlClose();\r
680     //rknand_release_device();\r
681     platform_driver_unregister(&rknand_driver);\r
682 }\r
683 \r
684 module_init(rknand_init);\r
685 module_exit(rknand_exit);\r
686 \r
687 #if 0//def CONFIG_rknand\r
688 /*\r
689 ×¢²áÒ»¸ösys dev £¬ÔڹػúºÍ¸´Î»Ê±»Øµ÷£¬°Ñflash¹Ø¼üÐÅϢдµ½nand flashÖУ¬Ï´οª»úʱ¿ÉÒÔ¿ìËÙ¿ª»ú¡£\r
690 */\r
691 \r
692 #include <linux/sysdev.h>\r
693 #include <linux/timer.h>\r
694 \r
695 static int rknand_sys_suspend(struct sys_device *dev, pm_message_t state)\r
696 {\r
697         struct rknand_chip *nand_info = &gpNandInfo->rknand;\r
698     extern void FtlCacheWriteBack(void);\r
699     NAND_DEBUG(NAND_DEBUG_LEVEL0,"...rknand_sys_suspend...\n");\r
700     nand_info->rknand_schedule_enable = 0;\r
701     if (nand_info->state == FL_READY)\r
702     {\r
703         nand_info->state = FL_WRITING;\r
704         FtlCacheWriteBack();\r
705         rknand_release_device();\r
706     }\r
707     else\r
708     {\r
709         nand_info->pFlashCallBack = FtlCacheWriteBack;\r
710     }  \r
711     NAND_DEBUG(NAND_DEBUG_LEVEL0,"...rknand_sys_suspend done...\n");\r
712         return 0;\r
713 \r
714 }\r
715 \r
716 static int rknand_sys_resume(struct sys_device *dev)\r
717 {\r
718         struct rknand_chip *nand_info = &gpNandInfo->rknand;\r
719     nand_info->rknand_schedule_enable = 1;\r
720     NAND_DEBUG(NAND_DEBUG_LEVEL0,"...rknand_sys_resume...\n");\r
721         return 0;\r
722 }\r
723 \r
724 static int rknand_sys_shutdown(struct sys_device *dev)\r
725 {\r
726         struct rknand_chip *nand_info = &gpNandInfo->rknand;\r
727     NAND_DEBUG(NAND_DEBUG_LEVEL0,"...rknand_sys_shutdown...\n");\r
728     nand_info->rknand_schedule_enable = 0;\r
729     \r
730     if (nand_info->state == FL_READY)\r
731     {\r
732         //rknand_get_device(FL_UNVALID);\r
733         nand_info->state = FL_UNVALID;\r
734         NandDeInit();\r
735         rknand_release_device();\r
736     }\r
737     else\r
738     {//flash not ready,use call back\r
739         nand_info->pFlashCallBack = NandDeInit;\r
740     } \r
741         return 0;\r
742 }\r
743 \r
744 static struct sysdev_class rknand_sysclass = {\r
745         .name           = "rknand_sysdev",\r
746         .shutdown       = rknand_sys_shutdown,\r
747         .suspend        = rknand_sys_suspend,\r
748         .resume         = rknand_sys_resume,\r
749 };\r
750 \r
751 static struct sys_device rknand_sysdevice = {\r
752         .id             = 0,\r
753         .cls            = &rknand_sysclass,\r
754 };\r
755 \r
756 static int __init rknand_sys_init(void)\r
757 {\r
758         int ret;\r
759     NAND_DEBUG(NAND_DEBUG_LEVEL0,"rknand_sys_init!!!!!!!!!!!!!!\n");\r
760         ret = sysdev_class_register(&rknand_sysclass);\r
761         if (ret == 0)\r
762                 ret = sysdev_register(&rknand_sysdevice);\r
763         return ret;\r
764 }\r
765 \r
766 device_initcall(rknand_sys_init);\r
767 #endif\r
768 \r
769 \r
770 MODULE_LICENSE("");\r
771 MODULE_AUTHOR("ZYF <zyf@rock-chips.com>");\r
772 MODULE_DESCRIPTION("FTL layer for SLC and MlC nand flash on RK28xx SDK boards");\r
773 \r
774 \r