--- /dev/null
+/*\r
+ * linux/drivers/mtd/rknand/rknand_base.c\r
+ *\r
+ * Copyright (C) 2005-2009 Fuzhou Rockchip Electronics\r
+ * ZYF <zyf@rock-chips.com>\r
+ *\r
+ * \r
+ */\r
+\r
+//#include "api_flash.h"\r
+\r
+#define DRIVER_NAME "rk29xxnand"\r
+\r
+#define NAND_DEBUG_LEVEL0 0\r
+#define NAND_DEBUG_LEVEL1 1\r
+#define NAND_DEBUG_LEVEL2 2\r
+#define NAND_DEBUG_LEVEL3 3\r
+//#define PAGE_REMAP\r
+\r
+#ifndef CONFIG_RKFTL_PAGECACHE_SIZE\r
+#define CONFIG_RKFTL_PAGECACHE_SIZE 64 //¶¨ÒåpageÓ³ÉäÇø´óС£¬µ¥Î»ÎªMB,mount ÔÚ/data/dataÏ¡£\r
+#endif\r
+\r
+extern unsigned long SysImageWriteEndAdd;\r
+extern int g_num_partitions;\r
+\r
+/*\r
+ * rknand_state_t - chip states\r
+ * Enumeration for Rknand flash chip state\r
+ */\r
+typedef enum {\r
+ FL_READY,\r
+ FL_READING,\r
+ FL_WRITING,\r
+ FL_ERASING,\r
+ FL_SYNCING,\r
+ FL_UNVALID,\r
+} rknand_state_t;\r
+\r
+struct rknand_chip {\r
+ wait_queue_head_t wq;\r
+ rknand_state_t state;\r
+ int rknand_schedule_enable;//1 enable ,0 disable\r
+ void (*pFlashCallBack)(void);//call back funtion\r
+};\r
+\r
+struct rknand_info {\r
+ int enable;\r
+ char *pbuf;\r
+ int bufSize;\r
+ unsigned int SysImageWriteEndAdd;\r
+ unsigned int nandCapacity;\r
+ struct rknand_chip rknand;\r
+ int (*ftl_cache_en)(int en); \r
+ int (*ftl_read) (int Index, int nSec, void *buf); \r
+ int (*ftl_write) (int Index, int nSec, void *buf ,int mode);\r
+ int (*ftl_write_panic) (int Index, int nSec, void *buf);\r
+ int (*ftl_close)(void);\r
+ int (*ftl_sync)(void);\r
+ int (*proc_bufread)(char *page);\r
+ int (*proc_ftlread)(char *page);\r
+ int (*rknand_schedule_enable)(int en);\r
+ int (*add_rknand_device)(struct rknand_info * prknand_Info);\r
+ int (*get_rknand_device)(struct rknand_info ** prknand_Info);\r
+ void (*rknand_buffer_shutdown)(void);\r
+ int (*GetIdBlockSysData)(char * buf, int Sector);\r
+ char (*GetSNSectorInfo)(char * pbuf);\r
+ char (*GetChipSectorInfo)(char * pbuf);\r
+};\r
+\r
+extern int rknand_queue_read(int Index, int nSec, void *buf);\r
+extern int rknand_queue_write(int Index, int nSec, void *buf,int mode);\r
+extern int rknand_buffer_init(char * pbuf,int size);\r
+extern void rknand_buffer_shutdown(void);\r
+extern int add_rknand_device(struct rknand_info * prknand_Info);\r
+extern int get_rknand_device(struct rknand_info ** prknand_Info);\r
+extern void rknand_buffer_sync(void);
\ No newline at end of file
--- /dev/null
+/*\r
+ * linux/drivers/mtd/rknand/rknand_base.c\r
+ *\r
+ * Copyright (C) 2005-2009 Fuzhou Rockchip Electronics\r
+ * ZYF <zyf@rock-chips.com>\r
+ *\r
+ * \r
+ */\r
+\r
+#include <linux/module.h>\r
+#include <linux/sched.h>\r
+#include <linux/delay.h>\r
+#include <linux/init.h>\r
+#include <linux/slab.h>\r
+#include <linux/platform_device.h>\r
+#include <linux/mtd/mtd.h>\r
+#include <linux/mtd/partitions.h>\r
+#include <linux/mutex.h>\r
+#include <linux/kthread.h>\r
+#include <linux/reboot.h>\r
+#include <asm/io.h>\r
+#include <asm/mach/flash.h>\r
+//#include "api_flash.h"\r
+#include "rknand_base.h"\r
+\r
+\r
+#define DRIVER_NAME "rk29xxnand"\r
+const char rknand_base_version[] = "rknand_base.c version: 4.26 20110610";\r
+#define NAND_DEBUG_LEVEL0 0\r
+#define NAND_DEBUG_LEVEL1 1\r
+#define NAND_DEBUG_LEVEL2 2\r
+#define NAND_DEBUG_LEVEL3 3\r
+\r
+int g_num_partitions = 0;\r
+unsigned long SysImageWriteEndAdd = 0;\r
+struct mtd_info rknand_mtd; \r
+struct mtd_partition *rknand_parts;\r
+struct rknand_info * gpNandInfo;\r
+\r
+#ifdef CONFIG_MTD_NAND_RK29XX_DEBUG\r
+static int s_debug = CONFIG_MTD_NAND_RK29XX_DEBUG_VERBOSE;\r
+#undef NAND_DEBUG\r
+#define NAND_DEBUG(n, format, arg...) \\r
+ if (n <= s_debug) { \\r
+ printk(format,##arg); \\r
+ }\r
+#else\r
+#undef NAND_DEBUG\r
+#define NAND_DEBUG(n, arg...)\r
+static const int s_debug = 0;\r
+#endif\r
+\r
+#include <linux/proc_fs.h>\r
+#include <linux/version.h>\r
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))\r
+#define NANDPROC_ROOT (&proc_root)\r
+#else\r
+#define NANDPROC_ROOT NULL\r
+#endif\r
+\r
+#define MAX_BUFFER_SIZE (long)(2048 * 8) //sector\r
+long grknand_buf[MAX_BUFFER_SIZE * 512/4] __attribute__((aligned(4096)));\r
+\r
+static struct proc_dir_entry *my_proc_entry;\r
+extern int rkNand_proc_ftlread(char *page);\r
+extern int rkNand_proc_bufread(char *page);\r
+static int rkNand_proc_read(char *page,\r
+ char **start,\r
+ off_t offset, int count, int *eof, void *data)\r
+{\r
+ char *buf = page;\r
+ int step = offset;\r
+ *(int *)start = 1;\r
+ if(step == 0)\r
+ {\r
+ buf += sprintf(buf, "%s\n", rknand_base_version);\r
+ if(gpNandInfo->proc_ftlread)\r
+ buf += gpNandInfo->proc_ftlread(buf);\r
+ if(gpNandInfo->proc_bufread)\r
+ buf += gpNandInfo->proc_bufread(buf);\r
+ }\r
+ return buf - page < count ? buf - page : count;\r
+}\r
+\r
+static void rk28nand_create_procfs(void)\r
+{\r
+ /* Install the proc_fs entry */\r
+ my_proc_entry = create_proc_entry("rk29xxnand",\r
+ S_IRUGO | S_IFREG,\r
+ NANDPROC_ROOT);\r
+\r
+ if (my_proc_entry) {\r
+ my_proc_entry->write_proc = NULL;\r
+ my_proc_entry->read_proc = rkNand_proc_read;\r
+ my_proc_entry->data = NULL;\r
+ } \r
+}\r
+\r
+void printk_write_log(long lba,int len, const u_char *pbuf)\r
+{\r
+ char debug_buf[100];\r
+ int i;\r
+ for(i=0;i<len;i++)\r
+ {\r
+ sprintf(debug_buf,"%lx :",lba+i);\r
+ print_hex_dump(KERN_WARNING, debug_buf, DUMP_PREFIX_NONE, 16,4, &pbuf[512*i], 8, 0);\r
+ }\r
+}\r
+\r
+static int rk28xxnand_read(struct mtd_info *mtd, loff_t from, size_t len,\r
+ size_t *retlen, u_char *buf)\r
+{\r
+ int ret = 0;\r
+ int sector = len>>9;\r
+ int LBA = (int)(from>>9);\r
+ //printk("rk28xxnand_read: from=%x,len=%x,\n",(int)from,len);\r
+ if(sector && gpNandInfo->ftl_read)\r
+ {\r
+ ret = gpNandInfo->ftl_read(LBA, sector, buf);\r
+ }\r
+ *retlen = len;\r
+ return 0;//ret;\r
+}\r
+\r
+static int rk28xxnand_write(struct mtd_info *mtd, loff_t from, size_t len,\r
+ size_t *retlen, const u_char *buf)\r
+{\r
+ int ret = 0;\r
+ int sector = len>>9;\r
+ int LBA = (int)(from>>9);\r
+ //printk("*");\r
+ //printk(KERN_NOTICE "write: from=%lx,len=%x\n",(int)LBA,sector);\r
+ //printk_write_log(LBA,sector,buf);\r
+ if(sector && gpNandInfo->ftl_write)// cmy\r
+ {\r
+ if(LBA < SysImageWriteEndAdd)//0x4E000)\r
+ {\r
+ NAND_DEBUG(NAND_DEBUG_LEVEL0,">>> FtlWriteImage: LBA=0x%08X sector=%d\n",LBA, sector);\r
+ ret = gpNandInfo->ftl_write(LBA, sector, (void *)buf,1);\r
+ }\r
+ else\r
+ {\r
+ ret = gpNandInfo->ftl_write(LBA, sector, (void *)buf,0);\r
+ }\r
+ }\r
+ *retlen = len;\r
+ return 0;\r
+}\r
+\r
+static int rk28xxnand_erase(struct mtd_info *mtd, struct erase_info *instr)\r
+{\r
+ int ret = 0;\r
+ if (instr->callback)\r
+ instr->callback(instr);\r
+ return ret;\r
+}\r
+\r
+static void rk28xxnand_sync(struct mtd_info *mtd)\r
+{\r
+ NAND_DEBUG(NAND_DEBUG_LEVEL0,"rk28xxnand_sync: \n");\r
+ if(gpNandInfo->ftl_sync)\r
+ gpNandInfo->ftl_sync();\r
+}\r
+\r
+extern void FtlWriteCacheEn(int);\r
+static int rk28xxnand_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)\r
+{\r
+ int sector = len >> 9;\r
+ int LBA = (int)(to >> 9);\r
+\r
+ if (sector && gpNandInfo->ftl_write_panic) {\r
+ if(gpNandInfo->ftl_cache_en)\r
+ gpNandInfo->ftl_cache_en(0);\r
+ gpNandInfo->ftl_write_panic(LBA, sector, (void *)buf);\r
+ if(gpNandInfo->ftl_cache_en)\r
+ gpNandInfo->ftl_cache_en(1);\r
+ }\r
+ *retlen = len;\r
+ return 0;\r
+}\r
+\r
+\r
+int GetIdBlockSysData(char * buf, int Sector)\r
+{\r
+ if(gpNandInfo->GetIdBlockSysData)\r
+ return( gpNandInfo->GetIdBlockSysData( buf, Sector));\r
+ return 0;\r
+}\r
+\r
+char GetSNSectorInfo(char * pbuf)\r
+{\r
+ if(gpNandInfo->GetSNSectorInfo)\r
+ return( gpNandInfo->GetSNSectorInfo( pbuf));\r
+ return 0;\r
+}\r
+\r
+char GetChipSectorInfo(char * pbuf)\r
+{\r
+ if(gpNandInfo->GetChipSectorInfo)\r
+ return( gpNandInfo->GetChipSectorInfo( pbuf));\r
+ return 0;\r
+}\r
+\r
+static int rk28xxnand_block_isbad(struct mtd_info *mtd, loff_t ofs)\r
+{\r
+ return 0;\r
+}\r
+\r
+static int rk28xxnand_block_markbad(struct mtd_info *mtd, loff_t ofs)\r
+{\r
+ return 0;\r
+}\r
+\r
+static int rk28xxnand_init(struct rknand_info *nand_info)\r
+{\r
+ struct mtd_info *mtd = &rknand_mtd;\r
+ struct rknand_chip *rknand = &nand_info->rknand; \r
+\r
+ rknand->state = FL_READY;\r
+ rknand->rknand_schedule_enable = 1;\r
+ rknand->pFlashCallBack = NULL;\r
+ init_waitqueue_head(&rknand->wq);\r
+\r
+ mtd->oobsize = 0;\r
+ mtd->oobavail = 0;\r
+ mtd->ecclayout = 0;\r
+ mtd->erasesize = 8*0x200; \r
+ mtd->writesize = 8*0x200;\r
+\r
+ // Fill in remaining MTD driver data \r
+ mtd->type = MTD_NANDFLASH;\r
+ mtd->flags = (MTD_WRITEABLE|MTD_NO_ERASE);//\r
+ mtd->erase = rk28xxnand_erase;\r
+ mtd->point = NULL;\r
+ mtd->unpoint = NULL;\r
+ mtd->read = rk28xxnand_read;\r
+ mtd->write = rk28xxnand_write;\r
+ mtd->read_oob = NULL;\r
+ mtd->write_oob = NULL;\r
+ mtd->panic_write = rk28xxnand_panic_write;\r
+\r
+ mtd->sync = rk28xxnand_sync;\r
+ mtd->lock = NULL;\r
+ mtd->unlock = NULL;\r
+ mtd->suspend = NULL;\r
+ mtd->resume = NULL;\r
+ mtd->block_isbad = rk28xxnand_block_isbad;\r
+ mtd->block_markbad = rk28xxnand_block_markbad;\r
+ mtd->owner = THIS_MODULE;\r
+ return 0;\r
+}\r
+\r
+\r
+/*\r
+ * CMY: Ôö¼ÓÁ˶ÔÃüÁîÐзÖÇøÐÅÏ¢µÄÖ§³Ö\r
+ * ÈôcmdlineÓÐÌṩ·ÖÇøÐÅÏ¢£¬ÔòʹÓÃcmdlineµÄ·ÖÇøÐÅÏ¢½øÐзÖÇø\r
+ * ÈôcmdlineûÓÐÌṩ·ÖÇøÐÅÏ¢£¬ÔòʹÓÃĬÈϵķÖÇøÐÅÏ¢(rk28_partition_info)½øÐзÖÇø\r
+ */\r
+\r
+#ifdef CONFIG_MTD_CMDLINE_PARTS\r
+const char *part_probes[] = { "cmdlinepart", NULL }; \r
+#endif \r
+\r
+static int rk29xxnand_add_partitions(struct rknand_info *nand_info)\r
+{\r
+#ifdef CONFIG_MTD_CMDLINE_PARTS\r
+ int num_partitions = 0; \r
+\r
+ // ´ÓÃüÁîÐнâÎö·ÖÇøµÄÐÅÏ¢\r
+ num_partitions = parse_mtd_partitions(&(rknand_mtd), part_probes, &rknand_parts, 0); \r
+ NAND_DEBUG(NAND_DEBUG_LEVEL0,"num_partitions = %d\n",num_partitions);\r
+ if(num_partitions > 0) { \r
+ int i;\r
+ for (i = 0; i < num_partitions; i++) \r
+ {\r
+ rknand_parts[i].offset *= 0x200;\r
+ rknand_parts[i].size *=0x200;\r
+ }\r
+ rknand_parts[num_partitions - 1].size = rknand_mtd.size - rknand_parts[num_partitions - 1].offset;\r
+ \r
+ g_num_partitions = num_partitions;\r
+ return add_mtd_partitions(&(rknand_mtd), rknand_parts, num_partitions);\r
+ } \r
+#endif \r
+ return 0;\r
+}\r
+\r
+int add_rknand_device(struct rknand_info * prknand_Info)\r
+{\r
+ struct mtd_partition *parts;\r
+ int i;\r
+ NAND_DEBUG(NAND_DEBUG_LEVEL0,"add_rknand_device: \n");\r
+ \r
+ rknand_mtd.size = (uint64_t)gpNandInfo->nandCapacity*0x200;\r
+ \r
+ rk29xxnand_add_partitions(prknand_Info);\r
+ \r
+ parts = rknand_parts;\r
+ for(i=0;i<g_num_partitions;i++)\r
+ {\r
+ //printk(">>> part[%d]: name=%s offset=0x%012llx\n", i, parts[i].name, parts[i].offset);\r
+ if(strcmp(parts[i].name,"backup") == 0)\r
+ {\r
+ SysImageWriteEndAdd = (unsigned long)(parts[i].offset + parts[i].size)>>9;//sector\r
+ //printk(">>> SysImageWriteEndAdd=0x%lx\n", SysImageWriteEndAdd);\r
+ break;\r
+ }\r
+ }\r
+\r
+ gpNandInfo->SysImageWriteEndAdd = SysImageWriteEndAdd;\r
+ return 0;\r
+}\r
+\r
+int get_rknand_device(struct rknand_info ** prknand_Info)\r
+{\r
+ *prknand_Info = gpNandInfo;\r
+ return 0; \r
+}\r
+\r
+EXPORT_SYMBOL(get_rknand_device);\r
+\r
+static int rknand_probe(struct platform_device *pdev)\r
+{\r
+ struct rknand_info *nand_info;\r
+ int err = 0;\r
+ NAND_DEBUG(NAND_DEBUG_LEVEL0,"rk28xxnand_probe: \n");\r
+ gpNandInfo = kzalloc(sizeof(struct rknand_info), GFP_KERNEL);\r
+ if (!gpNandInfo)\r
+ return -ENOMEM;\r
+ \r
+ nand_info = gpNandInfo;\r
+\r
+ memset(gpNandInfo,0,sizeof(struct rknand_info));\r
+\r
+ gpNandInfo->bufSize = MAX_BUFFER_SIZE * 512;\r
+ gpNandInfo->pbuf = grknand_buf;\r
+ \r
+ rknand_mtd.name = dev_name(&pdev->dev);\r
+ rknand_mtd.priv = &nand_info->rknand;\r
+ rknand_mtd.owner = THIS_MODULE;\r
+ \r
+ if(rk28xxnand_init(nand_info))\r
+ {\r
+ err = -ENXIO;\r
+ goto exit_free;\r
+ }\r
+ \r
+ nand_info->add_rknand_device = add_rknand_device;\r
+ nand_info->get_rknand_device = get_rknand_device;\r
+\r
+ rk28nand_create_procfs();\r
+ return 0;\r
+\r
+exit_free:\r
+ if(nand_info)\r
+ kfree(nand_info);\r
+\r
+ return err;\r
+}\r
+\r
+static int rknand_suspend(struct platform_device *pdev, pm_message_t state)\r
+{\r
+ gpNandInfo->rknand.rknand_schedule_enable = 0;\r
+ NAND_DEBUG(NAND_DEBUG_LEVEL0,"rknand_suspend: \n");\r
+ return 0;\r
+}\r
+\r
+static int rknand_resume(struct platform_device *pdev)\r
+{\r
+ gpNandInfo->rknand.rknand_schedule_enable = 1;\r
+ NAND_DEBUG(NAND_DEBUG_LEVEL0,"rknand_resume: \n");\r
+ return 0;\r
+}\r
+\r
+void rknand_shutdown(struct platform_device *pdev)\r
+{\r
+ printk("rknand_shutdown...\n");\r
+ gpNandInfo->rknand.rknand_schedule_enable = 0;\r
+ if(gpNandInfo->rknand_buffer_shutdown)\r
+ gpNandInfo->rknand_buffer_shutdown(); \r
+}\r
+\r
+static struct platform_driver rknand_driver = {\r
+ .probe = rknand_probe,\r
+ .suspend = rknand_suspend,\r
+ .resume = rknand_resume,\r
+ .shutdown = rknand_shutdown,\r
+ .driver = {\r
+ .name = DRIVER_NAME,\r
+ .owner = THIS_MODULE,\r
+ },\r
+};\r
+\r
+\r
+MODULE_ALIAS(DRIVER_NAME);\r
+\r
+static int __init rknand_init(void)\r
+{\r
+ int ret;\r
+ NAND_DEBUG(NAND_DEBUG_LEVEL0,"rknand_init: \n");\r
+ ret = platform_driver_register(&rknand_driver);\r
+ NAND_DEBUG(NAND_DEBUG_LEVEL0,"platform_driver_register:ret = %x \n",ret);\r
+ return ret;\r
+}\r
+\r
+static void __exit rknand_exit(void)\r
+{\r
+ platform_driver_unregister(&rknand_driver);\r
+}\r
+\r
+module_init(rknand_init);\r
+module_exit(rknand_exit);\r
+\r
+MODULE_LICENSE("GPL");\r
+MODULE_AUTHOR("ZYF <zyf@rock-chips.com>");\r
+MODULE_DESCRIPTION("rknand driver.");\r
+\r
+\r