ARM: rockchip: rk3228: implement function rk3228_restart
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-rockchip / rknandbase.c
1 \r
2 #include <linux/module.h>\r
3 #include <linux/kernel.h>\r
4 #include <linux/slab.h>\r
5 #include <linux/dma-mapping.h>\r
6 #include <linux/irq.h>\r
7 #include <linux/interrupt.h>\r
8 #include <linux/bootmem.h>\r
9 #include <asm/io.h>\r
10 #include <asm/cacheflush.h>\r
11 #include <linux/platform_device.h>\r
12 #include <linux/semaphore.h>\r
13 #include <linux/clk.h>\r
14 \r
15 #define RKNAND_VERSION_AND_DATE  "rknandbase v1.0 2014-03-31"\r
16 \r
17 #ifdef CONFIG_OF\r
18 #include <linux/of.h>\r
19 #endif\r
20 \r
21 struct rknand_info {\r
22     int tag;\r
23     int enable;\r
24     int clk_rate[2];\r
25     int nand_suspend_state;\r
26     int nand_shutdown_state;\r
27     int reserved0[6];\r
28     \r
29     void (*rknand_suspend)(void);\r
30     void (*rknand_resume)(void);\r
31     void (*rknand_buffer_shutdown)(void);\r
32     int (*rknand_exit)(void);\r
33     \r
34     int (*ftl_read) (int lun,int Index, int nSec, void *buf);  \r
35     int (*ftl_write) (int lun,int Index, int nSec, void *buf);\r
36     void (*nand_timing_config)(unsigned long AHBnKHz);\r
37     void (*rknand_dev_cache_flush)(void);\r
38     \r
39     int reserved1[16];\r
40 };\r
41 \r
42 struct rk_nandc_info \r
43 {\r
44     int             id;\r
45     void __iomem    * reg_base ;\r
46     int             irq;\r
47     int             clk_rate;\r
48         struct clk          *clk;  // flash clk\r
49         struct clk          *hclk; // nandc clk\r
50         struct clk          *gclk; // flash clk gate\r
51 };\r
52 \r
53 struct rknand_info * gpNandInfo = NULL;\r
54 static struct rk_nandc_info  g_nandc_info[2];\r
55 \r
56 static char *cmdline=NULL;\r
57 int rknand_get_part_info(char **s)\r
58 {\r
59         *s = cmdline;\r
60     return 0;\r
61 }\r
62 EXPORT_SYMBOL(rknand_get_part_info); \r
63 \r
64 static char nand_idb_data[2048];\r
65 char GetSNSectorInfo(char * pbuf)\r
66 {\r
67     memcpy(pbuf,&nand_idb_data[0x600],0x200);\r
68     return 0;\r
69 }\r
70 \r
71 char GetSNSectorInfoBeforeNandInit(char * pbuf)\r
72 {\r
73     memcpy(pbuf,&nand_idb_data[0x600],0x200);\r
74     return 0;\r
75\r
76 \r
77 char GetVendor0InfoBeforeNandInit(char * pbuf)\r
78 {\r
79     memcpy(pbuf,&nand_idb_data[0x400+8],504);\r
80     return 0;\r
81 }\r
82 \r
83 char* rknand_get_idb_data(void)\r
84 {\r
85     return nand_idb_data;\r
86 }\r
87 EXPORT_SYMBOL(rknand_get_idb_data);\r
88 \r
89 int  GetParamterInfo(char * pbuf , int len)\r
90 {\r
91     int ret = -1;\r
92         return ret;\r
93 }\r
94 \r
95 void rknand_spin_lock_init(spinlock_t * p_lock)\r
96 {\r
97     spin_lock_init(p_lock);\r
98 }\r
99 EXPORT_SYMBOL(rknand_spin_lock_init);\r
100 \r
101 void rknand_spin_lock(spinlock_t * p_lock)\r
102 {\r
103     spin_lock_irq(p_lock);\r
104 }\r
105 EXPORT_SYMBOL(rknand_spin_lock);\r
106 \r
107 void rknand_spin_unlock(spinlock_t * p_lock)\r
108 {\r
109     spin_unlock_irq(p_lock);\r
110 }\r
111 EXPORT_SYMBOL(rknand_spin_unlock);\r
112 \r
113 \r
114 struct semaphore  g_rk_nand_ops_mutex;\r
115 void rknand_device_lock_init(void)\r
116 {\r
117         sema_init(&g_rk_nand_ops_mutex, 1);\r
118 }\r
119 EXPORT_SYMBOL(rknand_device_lock_init);\r
120 void rknand_device_lock (void)\r
121 {\r
122      down(&g_rk_nand_ops_mutex);\r
123 }\r
124 EXPORT_SYMBOL(rknand_device_lock);\r
125 \r
126 int rknand_device_trylock (void)\r
127 {\r
128     return down_trylock(&g_rk_nand_ops_mutex);\r
129 }\r
130 EXPORT_SYMBOL(rknand_device_trylock);\r
131 \r
132 void rknand_device_unlock (void)\r
133 {\r
134     up(&g_rk_nand_ops_mutex);\r
135 }\r
136 EXPORT_SYMBOL(rknand_device_unlock);\r
137 \r
138 \r
139 int rk_nand_get_device(struct rknand_info ** prknand_Info)\r
140 {\r
141     *prknand_Info = gpNandInfo;\r
142     return 0;     \r
143 }\r
144 EXPORT_SYMBOL(rk_nand_get_device);\r
145 \r
146 unsigned long rknand_dma_flush_dcache(unsigned long ptr,int size,int dir)\r
147 {\r
148 #ifdef CONFIG_ARM64\r
149         __flush_dcache_area((void *)ptr, size + 63);\r
150 #else\r
151      __cpuc_flush_dcache_area((void*)ptr, size + 63);\r
152 #endif\r
153     return ((unsigned long )virt_to_phys((void *)ptr));\r
154 }\r
155 EXPORT_SYMBOL(rknand_dma_flush_dcache);\r
156 \r
157 unsigned long rknand_dma_map_single(unsigned long ptr,int size,int dir)\r
158 {\r
159 #ifdef CONFIG_ARM64\r
160     __dma_map_area((void*)ptr, size, dir);\r
161     return ((unsigned long )virt_to_phys((void *)ptr));\r
162 #else\r
163     return dma_map_single(NULL,(void*)ptr,size, dir?DMA_TO_DEVICE:DMA_FROM_DEVICE);\r
164 #endif\r
165 }\r
166 EXPORT_SYMBOL(rknand_dma_map_single);\r
167 \r
168 void rknand_dma_unmap_single(unsigned long ptr,int size,int dir)\r
169 {\r
170 #ifdef CONFIG_ARM64\r
171     __dma_unmap_area(phys_to_virt(ptr), size, dir);\r
172 #else\r
173     dma_unmap_single(NULL, (dma_addr_t)ptr,size, dir?DMA_TO_DEVICE:DMA_FROM_DEVICE);\r
174 #endif\r
175 }\r
176 EXPORT_SYMBOL(rknand_dma_unmap_single);\r
177 \r
178 int rknand_flash_cs_init(int id)\r
179 {\r
180     return 0;\r
181 }\r
182 EXPORT_SYMBOL(rknand_flash_cs_init);\r
183 \r
184 int rknand_get_reg_addr(unsigned long *pNandc0,unsigned long *pNandc1,unsigned long *pSDMMC0,unsigned long *pSDMMC1,unsigned long *pSDMMC2)\r
185 {\r
186         *pNandc0 = (unsigned long)g_nandc_info[0].reg_base;\r
187         *pNandc1 = (unsigned long)g_nandc_info[1].reg_base;\r
188         return 0;\r
189 }\r
190 EXPORT_SYMBOL(rknand_get_reg_addr);\r
191 \r
192 int rknand_nandc_irq_init(int id,int mode,void * pfun)\r
193 {\r
194     int ret = 0;\r
195     int irq= g_nandc_info[id].irq;\r
196 \r
197     if(mode)\r
198     {\r
199         ret = request_irq(irq, pfun, 0, "nandc", g_nandc_info[id].reg_base);\r
200         //if(ret)\r
201         //printk("request IRQ_NANDC %x irq %x, ret=%x.........\n",id,irq, ret);\r
202     }\r
203     else //deinit\r
204     {\r
205         free_irq(irq,  NULL);\r
206     }\r
207     return ret;\r
208 }\r
209 EXPORT_SYMBOL(rknand_nandc_irq_init);\r
210 \r
211 /*1:flash 2:emmc 4:sdcard0 8:sdcard1*/
212 static int rknand_boot_media = 2;
213 int rknand_get_boot_media(void)
214 {
215         return rknand_boot_media;
216 }
217 EXPORT_SYMBOL(rknand_get_boot_media);
218
219 static int rknand_probe(struct platform_device *pdev)\r
220 {\r
221         unsigned int id = 0;\r
222         int irq ;\r
223         struct resource         *mem;\r
224         void __iomem    *membase;\r
225 \r
226     if(gpNandInfo == NULL)\r
227     {\r
228         gpNandInfo = kzalloc(sizeof(struct rknand_info), GFP_KERNEL);\r
229         if (!gpNandInfo)\r
230             return -ENOMEM;\r
231         gpNandInfo->nand_suspend_state = 0;\r
232         gpNandInfo->nand_shutdown_state = 0;\r
233         }\r
234         mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
235         membase = devm_request_and_ioremap(&pdev->dev, mem);\r
236         if (membase == 0) \r
237         {\r
238                 dev_err(&pdev->dev, "no reg resource?\n");\r
239                 return -1;\r
240         }\r
241         //printk("rknand_probe %d %x %x\n", pdev->id,(int)mem,(int)membase);\r
242 #ifdef CONFIG_OF\r
243         if(0==of_property_read_u32(pdev->dev.of_node, "nandc_id", &id))\r
244         {\r
245             ;\r
246         }\r
247     pdev->id = id;\r
248 #endif\r
249     if(id == 0)\r
250         {\r
251         memcpy(nand_idb_data,membase+0x1000,0x800);\r
252                 if (*(int *)(&nand_idb_data[0]) == 0x44535953) {
253                         rknand_boot_media = *(int *)(&nand_idb_data[8]);
254                         if (rknand_boot_media == 2) /*boot from emmc*/
255                                 return -1;
256                 }
257         }
258         else if(id >= 2)\r
259         {\r
260                 dev_err(&pdev->dev, "nandc id = %d error!\n",id);\r
261         }\r
262 \r
263     irq = platform_get_irq(pdev, 0);\r
264         //printk("nand irq: %d\n",irq);\r
265         if (irq < 0) {\r
266                 dev_err(&pdev->dev, "no irq resource?\n");\r
267                 return irq;\r
268         }\r
269     g_nandc_info[id].id = id;\r
270     g_nandc_info[id].irq = irq;\r
271     g_nandc_info[id].reg_base = membase;\r
272 \r
273     g_nandc_info[id].hclk = devm_clk_get(&pdev->dev, "hclk_nandc");\r
274     g_nandc_info[id].clk = devm_clk_get(&pdev->dev, "clk_nandc");\r
275     g_nandc_info[id].gclk = devm_clk_get(&pdev->dev, "g_clk_nandc");\r
276 \r
277         if (unlikely(IS_ERR(g_nandc_info[id].clk)) || unlikely(IS_ERR(g_nandc_info[id].hclk))\r
278         || unlikely(IS_ERR(g_nandc_info[id].gclk))) {\r
279         printk("rknand_probe get clk error\n");\r
280         return -1;\r
281         }\r
282 \r
283     clk_set_rate(g_nandc_info[id].clk,150*1000*1000);\r
284         g_nandc_info[id].clk_rate = clk_get_rate(g_nandc_info[id].clk );\r
285     printk("rknand_probe clk rate = %d\n",g_nandc_info[id].clk_rate);\r
286     gpNandInfo->clk_rate[id] = g_nandc_info[id].clk_rate;\r
287     \r
288         clk_prepare_enable( g_nandc_info[id].clk );\r
289         clk_prepare_enable( g_nandc_info[id].hclk);\r
290         clk_prepare_enable( g_nandc_info[id].gclk);\r
291         return 0;\r
292 }\r
293 \r
294 static int rknand_suspend(struct platform_device *pdev, pm_message_t state)\r
295 {\r
296     if(gpNandInfo->rknand_suspend  && gpNandInfo->nand_suspend_state == 0){\r
297        gpNandInfo->nand_suspend_state = 1;\r
298         gpNandInfo->rknand_suspend();\r
299         //TODO:nandc clk disable\r
300         }\r
301         return 0;\r
302 }\r
303 \r
304 static int rknand_resume(struct platform_device *pdev)\r
305 {\r
306     if(gpNandInfo->rknand_resume && gpNandInfo->nand_suspend_state == 1){\r
307        gpNandInfo->nand_suspend_state = 0;\r
308        //TODO:nandc clk enable\r
309        gpNandInfo->rknand_resume();  \r
310         }\r
311         return 0;\r
312 }\r
313 \r
314 static void rknand_shutdown(struct platform_device *pdev)\r
315 {\r
316     if(gpNandInfo->rknand_buffer_shutdown && gpNandInfo->nand_shutdown_state == 0){\r
317         gpNandInfo->nand_shutdown_state = 1;\r
318         gpNandInfo->rknand_buffer_shutdown();\r
319     }\r
320 }\r
321 \r
322 void rknand_dev_cache_flush(void)\r
323 {\r
324     if(gpNandInfo->rknand_dev_cache_flush)\r
325         gpNandInfo->rknand_dev_cache_flush();\r
326 }\r
327 \r
328 #ifdef CONFIG_OF\r
329 static const struct of_device_id of_rk_nandc_match[] = {\r
330         { .compatible = "rockchip,rk-nandc" },\r
331         { /* Sentinel */ }\r
332 };\r
333 #endif\r
334 \r
335 static struct platform_driver rknand_driver = {\r
336         .probe          = rknand_probe,\r
337         .suspend        = rknand_suspend,\r
338         .resume         = rknand_resume,\r
339         .shutdown   = rknand_shutdown,\r
340         .driver         = {\r
341             .name       = "rknand",\r
342 #ifdef CONFIG_OF\r
343         .of_match_table = of_rk_nandc_match,\r
344 #endif\r
345                 .owner  = THIS_MODULE,\r
346         },\r
347 };\r
348 \r
349 static void __exit rknand_part_exit(void)\r
350 {\r
351         printk("rknand_part_exit: \n");\r
352     platform_driver_unregister(&rknand_driver);\r
353     if(gpNandInfo->rknand_exit)\r
354         gpNandInfo->rknand_exit();    \r
355         if (gpNandInfo)\r
356             kfree(gpNandInfo);\r
357 }\r
358 \r
359 MODULE_ALIAS(DRIVER_NAME);\r
360 static int __init rknand_part_init(void)\r
361 {\r
362         int ret = 0;\r
363         printk("%s\n", RKNAND_VERSION_AND_DATE);\r
364 \r
365         cmdline = strstr(saved_command_line, "mtdparts=") + 9;\r
366 \r
367         gpNandInfo = NULL;\r
368     memset(g_nandc_info,0,sizeof(g_nandc_info));\r
369 \r
370         ret = platform_driver_register(&rknand_driver);\r
371         printk("rknand_driver:ret = %x \n",ret);\r
372         return ret;\r
373 }\r
374 \r
375 module_init(rknand_part_init);\r
376 module_exit(rknand_part_exit);\r