#include <linux/interrupt.h>\r
#include <linux/bootmem.h>\r
#include <asm/io.h>\r
+#include <asm/cacheflush.h>\r
#include <linux/platform_device.h>\r
#include <linux/semaphore.h>\r
+#include <linux/clk.h>\r
\r
+#define RKNAND_VERSION_AND_DATE "rknandbase v1.0 2014-03-31"\r
\r
#ifdef CONFIG_OF\r
#include <linux/of.h>\r
struct rknand_info {\r
int tag;\r
int enable;\r
+ int clk_rate[2];\r
+ int nand_suspend_state;\r
+ int nand_shutdown_state;\r
int reserved0[6];\r
\r
void (*rknand_suspend)(void);\r
int reserved1[16];\r
};\r
\r
+struct rk_nandc_info \r
+{\r
+ int id;\r
+ void __iomem * reg_base ;\r
+ int irq;\r
+ int clk_rate;\r
+ struct clk *clk; // flash clk\r
+ struct clk *hclk; // nandc clk\r
+ struct clk *gclk; // flash clk gate\r
+};\r
+\r
struct rknand_info * gpNandInfo = NULL;\r
+static struct rk_nandc_info g_nandc_info[2];\r
+\r
static char *cmdline=NULL;\r
int rknand_get_part_info(char **s)\r
{\r
}\r
EXPORT_SYMBOL(rknand_get_part_info); \r
\r
-static char sn_data[512];\r
-static char vendor0[512];\r
-\r
+static char nand_idb_data[2048];\r
char GetSNSectorInfo(char * pbuf)\r
{\r
- memcpy(pbuf,sn_data,0x200);\r
+ memcpy(pbuf,&nand_idb_data[0x600],0x200);\r
return 0;\r
}\r
\r
char GetSNSectorInfoBeforeNandInit(char * pbuf)\r
{\r
- memcpy(pbuf,sn_data,0x200);\r
+ memcpy(pbuf,&nand_idb_data[0x600],0x200);\r
return 0;\r
} \r
\r
char GetVendor0InfoBeforeNandInit(char * pbuf)\r
{\r
- memcpy(pbuf,vendor0 + 8,504);\r
+ memcpy(pbuf,&nand_idb_data[0x400+8],504);\r
return 0;\r
}\r
\r
+char* rknand_get_idb_data(void)\r
+{\r
+ return nand_idb_data;\r
+}\r
+EXPORT_SYMBOL(rknand_get_idb_data);\r
+\r
int GetParamterInfo(char * pbuf , int len)\r
{\r
int ret = -1;\r
EXPORT_SYMBOL(rknand_device_unlock);\r
\r
\r
-int rknand_get_device(struct rknand_info ** prknand_Info)\r
+int rk_nand_get_device(struct rknand_info ** prknand_Info)\r
{\r
*prknand_Info = gpNandInfo;\r
- return 0; \r
+ return 0; \r
}\r
-EXPORT_SYMBOL(rknand_get_device);\r
+EXPORT_SYMBOL(rk_nand_get_device);\r
\r
-int rknand_dma_map_single(unsigned long ptr,int size,int dir)\r
+unsigned long rknand_dma_flush_dcache(unsigned long ptr,int size,int dir)\r
{\r
- return dma_map_single(NULL, ptr,size, dir?DMA_TO_DEVICE:DMA_FROM_DEVICE);\r
+#ifdef CONFIG_ARM64\r
+ __flush_dcache_area((void *)ptr, size + 63);\r
+#else\r
+ __cpuc_flush_dcache_area((void*)ptr, size + 63);\r
+#endif\r
+ return ((unsigned long )virt_to_phys((void *)ptr));\r
+}\r
+EXPORT_SYMBOL(rknand_dma_flush_dcache);\r
+\r
+unsigned long rknand_dma_map_single(unsigned long ptr,int size,int dir)\r
+{\r
+ return dma_map_single(NULL,(void*)ptr,size, dir?DMA_TO_DEVICE:DMA_FROM_DEVICE);\r
}\r
EXPORT_SYMBOL(rknand_dma_map_single);\r
\r
void rknand_dma_unmap_single(unsigned long ptr,int size,int dir)\r
{\r
- dma_unmap_single(NULL, ptr,size, dir?DMA_TO_DEVICE:DMA_FROM_DEVICE);\r
+ dma_unmap_single(NULL, (dma_addr_t)ptr,size, dir?DMA_TO_DEVICE:DMA_FROM_DEVICE);\r
}\r
EXPORT_SYMBOL(rknand_dma_unmap_single);\r
\r
-int rknand_flash_cs_init(void)\r
+int rknand_flash_cs_init(int id)\r
{\r
-\r
+ return 0;\r
}\r
EXPORT_SYMBOL(rknand_flash_cs_init);\r
\r
-int rknand_get_reg_addr(int *pNandc0,int *pNandc1,int *pSDMMC0,int *pSDMMC1,int *pSDMMC2)\r
+int rknand_get_reg_addr(unsigned long *pNandc0,unsigned long *pNandc1,unsigned long *pSDMMC0,unsigned long *pSDMMC1,unsigned long *pSDMMC2)\r
{\r
- //*pNandc = ioremap(RK30_NANDC_PHYS,RK30_NANDC_SIZE);\r
- //*pSDMMC0 = ioremap(SDMMC0_BASE_ADDR, 0x4000);\r
- //*pSDMMC1 = ioremap(SDMMC1_BASE_ADDR, 0x4000);\r
- //*pSDMMC2 = ioremap(EMMC_BASE_ADDR, 0x4000);\r
- *pNandc0 = ioremap(0x10500000,0x4000);\r
- //*pNandc1 = NULL;\r
+ *pNandc0 = (unsigned long)g_nandc_info[0].reg_base;\r
+ *pNandc1 = (unsigned long)g_nandc_info[1].reg_base;\r
+ return 0;\r
}\r
-\r
EXPORT_SYMBOL(rknand_get_reg_addr);\r
\r
-static int g_nandc_irq = 59;\r
-int rknand_nandc_irq_init(int mode,void * pfun)\r
+int rknand_nandc_irq_init(int id,int mode,void * pfun)\r
{\r
int ret = 0;\r
- if(mode) //init\r
+ int irq= g_nandc_info[id].irq;\r
+\r
+ if(mode)\r
{\r
- ret = request_irq(g_nandc_irq, pfun, 0, "nandc", NULL);\r
- if(ret)\r
- printk("request IRQ_NANDC irq , ret=%x.........\n", ret);\r
+ ret = request_irq(irq, pfun, 0, "nandc", g_nandc_info[id].reg_base);\r
+ //if(ret)\r
+ //printk("request IRQ_NANDC %x irq %x, ret=%x.........\n",id,irq, ret);\r
}\r
else //deinit\r
{\r
- free_irq(g_nandc_irq, NULL);\r
+ free_irq(irq, NULL);\r
}\r
return ret;\r
}\r
EXPORT_SYMBOL(rknand_nandc_irq_init);\r
+\r
static int rknand_probe(struct platform_device *pdev)\r
{\r
- g_nandc_irq = platform_get_irq(pdev, 0);\r
- printk("g_nandc_irq: %d\n",g_nandc_irq);\r
- if (g_nandc_irq < 0) {\r
+ unsigned int id = 0;\r
+ int irq ;\r
+ struct resource *mem;\r
+ void __iomem *membase;\r
+\r
+ if(gpNandInfo == NULL)\r
+ {\r
+ gpNandInfo = kzalloc(sizeof(struct rknand_info), GFP_KERNEL);\r
+ if (!gpNandInfo)\r
+ return -ENOMEM;\r
+ gpNandInfo->nand_suspend_state = 0;\r
+ gpNandInfo->nand_shutdown_state = 0;\r
+ }\r
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
+ membase = devm_request_and_ioremap(&pdev->dev, mem);\r
+ if (membase == 0) \r
+ {\r
+ dev_err(&pdev->dev, "no reg resource?\n");\r
+ return -1;\r
+ }\r
+ //printk("rknand_probe %d %x %x\n", pdev->id,(int)mem,(int)membase);\r
+#ifdef CONFIG_OF\r
+ if(0==of_property_read_u32(pdev->dev.of_node, "nandc_id", &id))\r
+ {\r
+ ;\r
+ }\r
+ pdev->id = id;\r
+#endif\r
+ if(id == 0)\r
+ {\r
+ memcpy(nand_idb_data,membase+0x1000,0x800);\r
+ }\r
+ else if(id >= 2)\r
+ {\r
+ dev_err(&pdev->dev, "nandc id = %d error!\n",id);\r
+ }\r
+\r
+ irq = platform_get_irq(pdev, 0);\r
+ //printk("nand irq: %d\n",irq);\r
+ if (irq < 0) {\r
dev_err(&pdev->dev, "no irq resource?\n");\r
- return g_nandc_irq;\r
+ return irq;\r
}\r
+ g_nandc_info[id].id = id;\r
+ g_nandc_info[id].irq = irq;\r
+ g_nandc_info[id].reg_base = membase;\r
+\r
+ g_nandc_info[id].hclk = devm_clk_get(&pdev->dev, "hclk_nandc");\r
+ g_nandc_info[id].clk = devm_clk_get(&pdev->dev, "clk_nandc");\r
+ g_nandc_info[id].gclk = devm_clk_get(&pdev->dev, "g_clk_nandc");\r
+\r
+ if (unlikely(IS_ERR(g_nandc_info[id].clk)) || unlikely(IS_ERR(g_nandc_info[id].hclk))\r
+ || unlikely(IS_ERR(g_nandc_info[id].gclk))) {\r
+ printk("rknand_probe get clk error\n");\r
+ return -1;\r
+ }\r
+\r
+ clk_set_rate(g_nandc_info[id].clk,150*1000*1000);\r
+ g_nandc_info[id].clk_rate = clk_get_rate(g_nandc_info[id].clk );\r
+ printk("rknand_probe clk rate = %d\n",g_nandc_info[id].clk_rate);\r
+ gpNandInfo->clk_rate[id] = g_nandc_info[id].clk_rate;\r
+ \r
+ clk_prepare_enable( g_nandc_info[id].clk );\r
+ clk_prepare_enable( g_nandc_info[id].hclk);\r
+ clk_prepare_enable( g_nandc_info[id].gclk);\r
return 0;\r
}\r
\r
static int rknand_suspend(struct platform_device *pdev, pm_message_t state)\r
{\r
- if(gpNandInfo->rknand_suspend)\r
- gpNandInfo->rknand_suspend(); \r
+ if(gpNandInfo->rknand_suspend && gpNandInfo->nand_suspend_state == 0){\r
+ gpNandInfo->nand_suspend_state = 1;\r
+ gpNandInfo->rknand_suspend();\r
+ //TODO:nandc clk disable\r
+ }\r
return 0;\r
}\r
\r
static int rknand_resume(struct platform_device *pdev)\r
{\r
- if(gpNandInfo->rknand_resume)\r
+ if(gpNandInfo->rknand_resume && gpNandInfo->nand_suspend_state == 1){\r
+ gpNandInfo->nand_suspend_state = 0;\r
+ //TODO:nandc clk enable\r
gpNandInfo->rknand_resume(); \r
+ }\r
return 0;\r
}\r
\r
static void rknand_shutdown(struct platform_device *pdev)\r
{\r
- if(gpNandInfo->rknand_buffer_shutdown)\r
- gpNandInfo->rknand_buffer_shutdown(); \r
+ if(gpNandInfo->rknand_buffer_shutdown && gpNandInfo->nand_shutdown_state == 0){\r
+ gpNandInfo->nand_shutdown_state = 1;\r
+ gpNandInfo->rknand_buffer_shutdown();\r
+ }\r
}\r
\r
void rknand_dev_cache_flush(void)\r
static int __init rknand_part_init(void)\r
{\r
int ret = 0;\r
- char * pbuf = ioremap(0x10501400,0x400);\r
- memcpy(vendor0,pbuf,0x200);\r
- memcpy(sn_data,pbuf+0x200,0x200);\r
- iounmap(pbuf);\r
+ printk("%s\n", RKNAND_VERSION_AND_DATE);\r
+\r
cmdline = strstr(saved_command_line, "mtdparts=") + 9;\r
- gpNandInfo = kzalloc(sizeof(struct rknand_info), GFP_KERNEL);\r
- if (!gpNandInfo)\r
- return -ENOMEM;\r
- memset(gpNandInfo,0,sizeof(struct rknand_info));\r
+\r
+ gpNandInfo = NULL;\r
+ memset(g_nandc_info,0,sizeof(g_nandc_info));\r
+\r
ret = platform_driver_register(&rknand_driver);\r
printk("rknand_driver:ret = %x \n",ret);\r
return ret;\r