Merge branch develop-3.10
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-rockchip / rknandbase.c
index 7db78f19ca4d8751fbd0ecfebc9850ec214fb580..887fe973f4cbcd856f0d063d53750b300c18af76 100755 (executable)
@@ -7,9 +7,12 @@
 #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
@@ -18,6 +21,9 @@
 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
@@ -33,7 +39,20 @@ struct rknand_info {
     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
@@ -42,27 +61,31 @@ int rknand_get_part_info(char **s)
 }\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
@@ -113,89 +136,165 @@ void rknand_device_unlock (void)
 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
@@ -239,15 +338,13 @@ MODULE_ALIAS(DRIVER_NAME);
 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