Merge branch 'develop' of 10.10.10.29:/home/rockchip/kernel into develop
[firefly-linux-kernel-4.4.55.git] / drivers / mtd / rknand / rknand_base_ko.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 #include "rknand_base.h"\r
25 \r
26 \r
27 #define DRIVER_NAME     "rk29xxnand"\r
28 const char rknand_base_version[] = "rknand_base.c version: 4.26 20110610";\r
29 #define NAND_DEBUG_LEVEL0 0\r
30 #define NAND_DEBUG_LEVEL1 1\r
31 #define NAND_DEBUG_LEVEL2 2\r
32 #define NAND_DEBUG_LEVEL3 3\r
33 \r
34 int g_num_partitions = 0;\r
35 unsigned long SysImageWriteEndAdd = 0;\r
36 struct mtd_info         rknand_mtd;  \r
37 struct mtd_partition *rknand_parts;\r
38 struct rknand_info * gpNandInfo;\r
39 \r
40 #ifdef CONFIG_MTD_NAND_RK29XX_DEBUG\r
41 static int s_debug = CONFIG_MTD_NAND_RK29XX_DEBUG_VERBOSE;\r
42 #undef NAND_DEBUG\r
43 #define NAND_DEBUG(n, format, arg...) \\r
44         if (n <= s_debug) {      \\r
45                 printk(format,##arg); \\r
46         }\r
47 #else\r
48 #undef NAND_DEBUG\r
49 #define NAND_DEBUG(n, arg...)\r
50 static const int s_debug = 0;\r
51 #endif\r
52 \r
53 #include <linux/proc_fs.h>\r
54 #include <linux/version.h>\r
55 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))\r
56 #define NANDPROC_ROOT  (&proc_root)\r
57 #else\r
58 #define NANDPROC_ROOT  NULL\r
59 #endif\r
60 \r
61 #define MAX_BUFFER_SIZE     (long)(2048 * 8) //sector\r
62 long grknand_buf[MAX_BUFFER_SIZE * 512/4] __attribute__((aligned(4096)));\r
63 \r
64 static struct proc_dir_entry *my_proc_entry;\r
65 extern int rkNand_proc_ftlread(char *page);\r
66 extern int rkNand_proc_bufread(char *page);\r
67 static int rkNand_proc_read(char *page,\r
68                            char **start,\r
69                            off_t offset, int count, int *eof, void *data)\r
70 {\r
71         char *buf = page;\r
72         int step = offset;\r
73         *(int *)start = 1;\r
74         if(step == 0)\r
75         {\r
76         buf += sprintf(buf, "%s\n", rknand_base_version);\r
77         if(gpNandInfo->proc_ftlread)\r
78             buf += gpNandInfo->proc_ftlread(buf);\r
79         if(gpNandInfo->proc_bufread)\r
80             buf += gpNandInfo->proc_bufread(buf);\r
81     }\r
82         return buf - page < count ? buf - page : count;\r
83 }\r
84 \r
85 static void rk28nand_create_procfs(void)\r
86 {\r
87     /* Install the proc_fs entry */\r
88     my_proc_entry = create_proc_entry("rk29xxnand",\r
89                            S_IRUGO | S_IFREG,\r
90                            NANDPROC_ROOT);\r
91 \r
92     if (my_proc_entry) {\r
93         my_proc_entry->write_proc = NULL;\r
94         my_proc_entry->read_proc = rkNand_proc_read;\r
95         my_proc_entry->data = NULL;\r
96     } \r
97 }\r
98 \r
99 void printk_write_log(long lba,int len, const u_char *pbuf)\r
100 {\r
101     char debug_buf[100];\r
102     int i;\r
103     for(i=0;i<len;i++)\r
104     {\r
105         sprintf(debug_buf,"%lx :",lba+i);\r
106         print_hex_dump(KERN_WARNING, debug_buf, DUMP_PREFIX_NONE, 16,4, &pbuf[512*i], 8, 0);\r
107     }\r
108 }\r
109 \r
110 static int rk28xxnand_read(struct mtd_info *mtd, loff_t from, size_t len,\r
111         size_t *retlen, u_char *buf)\r
112 {\r
113         int ret = 0;\r
114         int sector = len>>9;\r
115         int LBA = (int)(from>>9);\r
116     //printk("rk28xxnand_read: from=%x,len=%x,\n",(int)from,len);\r
117     if(sector && gpNandInfo->ftl_read)\r
118     {\r
119                 ret = gpNandInfo->ftl_read(LBA, sector, buf);\r
120     }\r
121         *retlen = len;\r
122         return 0;//ret;\r
123 }\r
124 \r
125 static int rk28xxnand_write(struct mtd_info *mtd, loff_t from, size_t len,\r
126         size_t *retlen, const u_char *buf)\r
127 {\r
128         int ret = 0;\r
129         int sector = len>>9;\r
130         int LBA = (int)(from>>9);\r
131         //printk("*");\r
132     //printk(KERN_NOTICE "write: from=%lx,len=%x\n",(int)LBA,sector);\r
133     //printk_write_log(LBA,sector,buf);\r
134         if(sector && gpNandInfo->ftl_write)// cmy\r
135         {\r
136                 if(LBA < SysImageWriteEndAdd)//0x4E000)\r
137                 {\r
138                         NAND_DEBUG(NAND_DEBUG_LEVEL0,">>> FtlWriteImage: LBA=0x%08X  sector=%d\n",LBA, sector);\r
139             ret = gpNandInfo->ftl_write(LBA, sector, (void *)buf,1);\r
140         }\r
141                 else\r
142         {\r
143             ret = gpNandInfo->ftl_write(LBA, sector, (void *)buf,0);\r
144         }\r
145         }\r
146         *retlen = len;\r
147         return 0;\r
148 }\r
149 \r
150 static int rk28xxnand_erase(struct mtd_info *mtd, struct erase_info *instr)\r
151 {\r
152         int ret = 0;\r
153     if (instr->callback)\r
154                 instr->callback(instr);\r
155         return ret;\r
156 }\r
157 \r
158 static void rk28xxnand_sync(struct mtd_info *mtd)\r
159 {\r
160         NAND_DEBUG(NAND_DEBUG_LEVEL0,"rk28xxnand_sync: \n");\r
161     if(gpNandInfo->ftl_sync)\r
162         gpNandInfo->ftl_sync();\r
163 }\r
164 \r
165 extern void FtlWriteCacheEn(int);\r
166 static int rk28xxnand_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)\r
167 {\r
168         int sector = len >> 9;\r
169         int LBA = (int)(to >> 9);\r
170 \r
171         if (sector && gpNandInfo->ftl_write_panic) {\r
172             if(gpNandInfo->ftl_cache_en)\r
173                     gpNandInfo->ftl_cache_en(0);\r
174                 gpNandInfo->ftl_write_panic(LBA, sector, (void *)buf);\r
175             if(gpNandInfo->ftl_cache_en)\r
176                     gpNandInfo->ftl_cache_en(1);\r
177         }\r
178         *retlen = len;\r
179         return 0;\r
180 }\r
181 \r
182 \r
183 int GetIdBlockSysData(char * buf, int Sector)\r
184 {\r
185     if(gpNandInfo->GetIdBlockSysData)\r
186            return( gpNandInfo->GetIdBlockSysData( buf,  Sector));\r
187     return 0;\r
188 }\r
189 \r
190 char GetSNSectorInfo(char * pbuf)\r
191 {\r
192     if(gpNandInfo->GetSNSectorInfo)\r
193            return( gpNandInfo->GetSNSectorInfo( pbuf));\r
194     return 0;\r
195 }\r
196 \r
197 char GetChipSectorInfo(char * pbuf)\r
198 {\r
199     if(gpNandInfo->GetChipSectorInfo)\r
200            return( gpNandInfo->GetChipSectorInfo( pbuf));\r
201     return 0;\r
202 }\r
203 \r
204 int  GetParamterInfo(char * pbuf , int len)\r
205 {\r
206         int ret = -1;\r
207         int sector = (len)>>9;\r
208         int LBA = 0;\r
209         if(sector && gpNandInfo->ftl_read)\r
210         {\r
211                 ret = gpNandInfo->ftl_read(LBA, sector, pbuf);\r
212         }\r
213         return ret?-1:(sector<<9);\r
214 }\r
215 \r
216 \r
217 static int rk28xxnand_block_isbad(struct mtd_info *mtd, loff_t ofs)\r
218 {\r
219         return 0;\r
220 }\r
221 \r
222 static int rk28xxnand_block_markbad(struct mtd_info *mtd, loff_t ofs)\r
223 {\r
224         return 0;\r
225 }\r
226 \r
227 static int rk28xxnand_init(struct rknand_info *nand_info)\r
228 {\r
229         struct mtd_info    *mtd = &rknand_mtd;\r
230         struct rknand_chip *rknand = &nand_info->rknand;  \r
231 \r
232         rknand->state = FL_READY;\r
233         rknand->rknand_schedule_enable = 1;\r
234         rknand->pFlashCallBack = NULL;\r
235         init_waitqueue_head(&rknand->wq);\r
236 \r
237     mtd->oobsize = 0;\r
238     mtd->oobavail = 0;\r
239     mtd->ecclayout = 0;\r
240     mtd->erasesize = 32*0x200;\r
241     mtd->writesize = 8*0x200;\r
242 \r
243         // Fill in remaining MTD driver data \r
244         mtd->type = MTD_NANDFLASH;\r
245         mtd->flags = (MTD_WRITEABLE|MTD_NO_ERASE);//\r
246         mtd->erase = rk28xxnand_erase;\r
247         mtd->point = NULL;\r
248         mtd->unpoint = NULL;\r
249         mtd->read = rk28xxnand_read;\r
250         mtd->write = rk28xxnand_write;\r
251         mtd->read_oob = NULL;\r
252         mtd->write_oob = NULL;\r
253         mtd->panic_write = rk28xxnand_panic_write;\r
254 \r
255         mtd->sync = rk28xxnand_sync;\r
256         mtd->lock = NULL;\r
257         mtd->unlock = NULL;\r
258         mtd->suspend = NULL;\r
259         mtd->resume = NULL;\r
260         mtd->block_isbad = rk28xxnand_block_isbad;\r
261         mtd->block_markbad = rk28xxnand_block_markbad;\r
262         mtd->owner = THIS_MODULE;\r
263     return 0;\r
264 }\r
265 \r
266   \r
267 /*\r
268  * CMY: Ôö¼ÓÁ˶ÔÃüÁîÐзÖÇøÐÅÏ¢µÄÖ§³Ö\r
269  *              ÈôcmdlineÓÐÌṩ·ÖÇøÐÅÏ¢£¬ÔòʹÓÃcmdlineµÄ·ÖÇøÐÅÏ¢½øÐзÖÇø\r
270  *              ÈôcmdlineûÓÐÌṩ·ÖÇøÐÅÏ¢£¬ÔòʹÓÃĬÈϵķÖÇøÐÅÏ¢(rk28_partition_info)½øÐзÖÇø\r
271  */\r
272 \r
273 #ifdef CONFIG_MTD_CMDLINE_PARTS\r
274 const char *part_probes[] = { "cmdlinepart", NULL }; \r
275 #endif \r
276 \r
277 static int rk29xxnand_add_partitions(struct rknand_info *nand_info)\r
278 {\r
279 #ifdef CONFIG_MTD_CMDLINE_PARTS\r
280     int num_partitions = 0; \r
281 \r
282         // ´ÓÃüÁîÐнâÎö·ÖÇøµÄÐÅÏ¢\r
283     num_partitions = parse_mtd_partitions(&(rknand_mtd), part_probes, &rknand_parts, 0); \r
284     NAND_DEBUG(NAND_DEBUG_LEVEL0,"num_partitions = %d\n",num_partitions);\r
285     if(num_partitions > 0) { \r
286         int i;\r
287         for (i = 0; i < num_partitions; i++) \r
288         {\r
289             rknand_parts[i].offset *= 0x200;\r
290             rknand_parts[i].size   *=0x200;\r
291         }\r
292         rknand_parts[num_partitions - 1].size = rknand_mtd.size - rknand_parts[num_partitions - 1].offset;\r
293         \r
294                 g_num_partitions = num_partitions;\r
295                 return add_mtd_partitions(&(rknand_mtd), rknand_parts, num_partitions);\r
296     } \r
297 #endif \r
298         return 0;\r
299 }\r
300 \r
301 int add_rknand_device(struct rknand_info * prknand_Info)\r
302 {\r
303     struct mtd_partition *parts;\r
304     int i;\r
305     NAND_DEBUG(NAND_DEBUG_LEVEL0,"add_rknand_device: \n");\r
306     \r
307     rknand_mtd.size = (uint64_t)gpNandInfo->nandCapacity*0x200;\r
308     \r
309     rk29xxnand_add_partitions(prknand_Info);\r
310  \r
311     parts = rknand_parts;\r
312     for(i=0;i<g_num_partitions;i++)\r
313     {\r
314         //printk(">>> part[%d]: name=%s offset=0x%012llx\n", i, parts[i].name, parts[i].offset);\r
315         if(strcmp(parts[i].name,"backup") == 0)\r
316         {\r
317             SysImageWriteEndAdd = (unsigned long)(parts[i].offset + parts[i].size)>>9;//sector\r
318             //printk(">>> SysImageWriteEndAdd=0x%lx\n", SysImageWriteEndAdd);\r
319             break;\r
320         }\r
321     }\r
322 \r
323     gpNandInfo->SysImageWriteEndAdd = SysImageWriteEndAdd;\r
324     return 0;\r
325 }\r
326 \r
327 int get_rknand_device(struct rknand_info ** prknand_Info)\r
328 {\r
329     *prknand_Info = gpNandInfo;\r
330     return 0;    \r
331 }\r
332 \r
333 EXPORT_SYMBOL(get_rknand_device);\r
334 \r
335 static int rknand_probe(struct platform_device *pdev)\r
336 {\r
337         struct rknand_info *nand_info;\r
338         int err = 0;\r
339         NAND_DEBUG(NAND_DEBUG_LEVEL0,"rk28xxnand_probe: \n");\r
340         gpNandInfo = kzalloc(sizeof(struct rknand_info), GFP_KERNEL);\r
341         if (!gpNandInfo)\r
342                 return -ENOMEM;\r
343     \r
344     nand_info = gpNandInfo;\r
345 \r
346     memset(gpNandInfo,0,sizeof(struct rknand_info));\r
347 \r
348     gpNandInfo->bufSize = MAX_BUFFER_SIZE * 512;\r
349     gpNandInfo->pbuf = grknand_buf;\r
350 \r
351 #ifdef CONFIG_MTD_EMMC_CLK_POWER_SAVE\r
352     gpNandInfo->emmc_clk_power_save_en = 1;\r
353 #endif\r
354 \r
355         rknand_mtd.name = dev_name(&pdev->dev);\r
356         rknand_mtd.priv = &nand_info->rknand;\r
357         rknand_mtd.owner = THIS_MODULE;\r
358     \r
359         if(rk28xxnand_init(nand_info))\r
360         {\r
361                 err = -ENXIO;\r
362                 goto  exit_free;\r
363         }\r
364         \r
365         nand_info->add_rknand_device = add_rknand_device;\r
366         nand_info->get_rknand_device = get_rknand_device;\r
367 \r
368         rk28nand_create_procfs();\r
369         return 0;\r
370 \r
371 exit_free:\r
372         if(nand_info)\r
373         kfree(nand_info);\r
374 \r
375         return err;\r
376 }\r
377 \r
378 static int rknand_suspend(struct platform_device *pdev, pm_message_t state)\r
379 {\r
380     gpNandInfo->rknand.rknand_schedule_enable = 0;\r
381         NAND_DEBUG(NAND_DEBUG_LEVEL0,"rknand_suspend: \n");\r
382         return 0;\r
383 }\r
384 \r
385 static int rknand_resume(struct platform_device *pdev)\r
386 {\r
387     gpNandInfo->rknand.rknand_schedule_enable = 1;\r
388         NAND_DEBUG(NAND_DEBUG_LEVEL0,"rknand_resume: \n");\r
389         return 0;\r
390 }\r
391 \r
392 void rknand_shutdown(struct platform_device *pdev)\r
393 {\r
394     printk("rknand_shutdown...\n");\r
395     gpNandInfo->rknand.rknand_schedule_enable = 0;\r
396     if(gpNandInfo->rknand_buffer_shutdown)\r
397         gpNandInfo->rknand_buffer_shutdown();    \r
398 }\r
399 \r
400 static struct platform_driver rknand_driver = {\r
401         .probe          = rknand_probe,\r
402         .suspend        = rknand_suspend,\r
403         .resume         = rknand_resume,\r
404         .shutdown   = rknand_shutdown,\r
405         .driver         = {\r
406                 .name   = DRIVER_NAME,\r
407                 .owner  = THIS_MODULE,\r
408         },\r
409 };\r
410 \r
411 \r
412 MODULE_ALIAS(DRIVER_NAME);\r
413 \r
414 static int __init rknand_init(void)\r
415 {\r
416         int ret;\r
417         NAND_DEBUG(NAND_DEBUG_LEVEL0,"rknand_init: \n");\r
418         ret = platform_driver_register(&rknand_driver);\r
419         NAND_DEBUG(NAND_DEBUG_LEVEL0,"platform_driver_register:ret = %x \n",ret);\r
420         return ret;\r
421 }\r
422 \r
423 static void __exit rknand_exit(void)\r
424 {\r
425     platform_driver_unregister(&rknand_driver);\r
426 }\r
427 \r
428 module_init(rknand_init);\r
429 module_exit(rknand_exit);\r
430 \r
431 MODULE_LICENSE("GPL");\r
432 MODULE_AUTHOR("ZYF <zyf@rock-chips.com>");\r
433 MODULE_DESCRIPTION("rknand driver.");\r
434 \r
435 \r