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
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
15 #define RKNAND_VERSION_AND_DATE "rknandbase v1.0 2014-03-31"
\r
18 #include <linux/of.h>
\r
21 struct rknand_info {
\r
25 int nand_suspend_state;
\r
26 int nand_shutdown_state;
\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
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
42 struct rk_nandc_info
\r
45 void __iomem * reg_base ;
\r
48 struct clk *clk; // flash clk
\r
49 struct clk *hclk; // nandc clk
\r
50 struct clk *gclk; // flash clk gate
\r
53 struct rknand_info * gpNandInfo = NULL;
\r
54 static struct rk_nandc_info g_nandc_info[2];
\r
56 static char *cmdline=NULL;
\r
57 int rknand_get_part_info(char **s)
\r
62 EXPORT_SYMBOL(rknand_get_part_info);
\r
64 static char nand_idb_data[2048];
\r
65 char GetSNSectorInfo(char * pbuf)
\r
67 memcpy(pbuf,&nand_idb_data[0x600],0x200);
\r
71 char GetSNSectorInfoBeforeNandInit(char * pbuf)
\r
73 memcpy(pbuf,&nand_idb_data[0x600],0x200);
\r
77 char GetVendor0InfoBeforeNandInit(char * pbuf)
\r
79 memcpy(pbuf,&nand_idb_data[0x400+8],504);
\r
83 char* rknand_get_idb_data(void)
\r
85 return nand_idb_data;
\r
87 EXPORT_SYMBOL(rknand_get_idb_data);
\r
89 int GetParamterInfo(char * pbuf , int len)
\r
95 void rknand_spin_lock_init(spinlock_t * p_lock)
\r
97 spin_lock_init(p_lock);
\r
99 EXPORT_SYMBOL(rknand_spin_lock_init);
\r
101 void rknand_spin_lock(spinlock_t * p_lock)
\r
103 spin_lock_irq(p_lock);
\r
105 EXPORT_SYMBOL(rknand_spin_lock);
\r
107 void rknand_spin_unlock(spinlock_t * p_lock)
\r
109 spin_unlock_irq(p_lock);
\r
111 EXPORT_SYMBOL(rknand_spin_unlock);
\r
114 struct semaphore g_rk_nand_ops_mutex;
\r
115 void rknand_device_lock_init(void)
\r
117 sema_init(&g_rk_nand_ops_mutex, 1);
\r
119 EXPORT_SYMBOL(rknand_device_lock_init);
\r
120 void rknand_device_lock (void)
\r
122 down(&g_rk_nand_ops_mutex);
\r
124 EXPORT_SYMBOL(rknand_device_lock);
\r
126 int rknand_device_trylock (void)
\r
128 return down_trylock(&g_rk_nand_ops_mutex);
\r
130 EXPORT_SYMBOL(rknand_device_trylock);
\r
132 void rknand_device_unlock (void)
\r
134 up(&g_rk_nand_ops_mutex);
\r
136 EXPORT_SYMBOL(rknand_device_unlock);
\r
139 int rk_nand_get_device(struct rknand_info ** prknand_Info)
\r
141 *prknand_Info = gpNandInfo;
\r
144 EXPORT_SYMBOL(rk_nand_get_device);
\r
146 unsigned long rknand_dma_flush_dcache(unsigned long ptr,int size,int dir)
\r
148 #ifdef CONFIG_ARM64
\r
149 __flush_dcache_area((void *)ptr, size + 63);
\r
151 __cpuc_flush_dcache_area((void*)ptr, size + 63);
\r
153 return ((unsigned long )virt_to_phys((void *)ptr));
\r
155 EXPORT_SYMBOL(rknand_dma_flush_dcache);
\r
157 unsigned long rknand_dma_map_single(unsigned long ptr,int size,int dir)
\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
163 return dma_map_single(NULL,(void*)ptr,size, dir?DMA_TO_DEVICE:DMA_FROM_DEVICE);
\r
166 EXPORT_SYMBOL(rknand_dma_map_single);
\r
168 void rknand_dma_unmap_single(unsigned long ptr,int size,int dir)
\r
170 #ifdef CONFIG_ARM64
\r
171 __dma_unmap_area(phys_to_virt(ptr), size, dir);
\r
173 dma_unmap_single(NULL, (dma_addr_t)ptr,size, dir?DMA_TO_DEVICE:DMA_FROM_DEVICE);
\r
176 EXPORT_SYMBOL(rknand_dma_unmap_single);
\r
178 int rknand_flash_cs_init(int id)
\r
182 EXPORT_SYMBOL(rknand_flash_cs_init);
\r
184 int rknand_get_reg_addr(unsigned long *pNandc0,unsigned long *pNandc1,unsigned long *pSDMMC0,unsigned long *pSDMMC1,unsigned long *pSDMMC2)
\r
186 *pNandc0 = (unsigned long)g_nandc_info[0].reg_base;
\r
187 *pNandc1 = (unsigned long)g_nandc_info[1].reg_base;
\r
190 EXPORT_SYMBOL(rknand_get_reg_addr);
\r
192 int rknand_nandc_irq_init(int id,int mode,void * pfun)
\r
195 int irq= g_nandc_info[id].irq;
\r
199 ret = request_irq(irq, pfun, 0, "nandc", g_nandc_info[id].reg_base);
\r
201 //printk("request IRQ_NANDC %x irq %x, ret=%x.........\n",id,irq, ret);
\r
205 free_irq(irq, NULL);
\r
209 EXPORT_SYMBOL(rknand_nandc_irq_init);
\r
211 /*1:flash 2:emmc 4:sdcard0 8:sdcard1*/
212 static int rknand_boot_media = 2;
213 int rknand_get_boot_media(void)
215 return rknand_boot_media;
217 EXPORT_SYMBOL(rknand_get_boot_media);
219 static int rknand_probe(struct platform_device *pdev)
\r
221 unsigned int id = 0;
\r
223 struct resource *mem;
\r
224 void __iomem *membase;
\r
226 if(gpNandInfo == NULL)
\r
228 gpNandInfo = kzalloc(sizeof(struct rknand_info), GFP_KERNEL);
\r
231 gpNandInfo->nand_suspend_state = 0;
\r
232 gpNandInfo->nand_shutdown_state = 0;
\r
234 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
\r
235 membase = devm_request_and_ioremap(&pdev->dev, mem);
\r
238 dev_err(&pdev->dev, "no reg resource?\n");
\r
241 //printk("rknand_probe %d %x %x\n", pdev->id,(int)mem,(int)membase);
\r
243 if(0==of_property_read_u32(pdev->dev.of_node, "nandc_id", &id))
\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*/
260 dev_err(&pdev->dev, "nandc id = %d error!\n",id);
\r
263 irq = platform_get_irq(pdev, 0);
\r
264 //printk("nand irq: %d\n",irq);
\r
266 dev_err(&pdev->dev, "no irq resource?\n");
\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
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
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
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
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
294 static int rknand_suspend(struct platform_device *pdev, pm_message_t state)
\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
304 static int rknand_resume(struct platform_device *pdev)
\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
314 static void rknand_shutdown(struct platform_device *pdev)
\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
322 void rknand_dev_cache_flush(void)
\r
324 if(gpNandInfo->rknand_dev_cache_flush)
\r
325 gpNandInfo->rknand_dev_cache_flush();
\r
329 static const struct of_device_id of_rk_nandc_match[] = {
\r
330 { .compatible = "rockchip,rk-nandc" },
\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
343 .of_match_table = of_rk_nandc_match,
\r
345 .owner = THIS_MODULE,
\r
349 static void __exit rknand_part_exit(void)
\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
359 MODULE_ALIAS(DRIVER_NAME);
\r
360 static int __init rknand_part_init(void)
\r
363 printk("%s\n", RKNAND_VERSION_AND_DATE);
\r
365 cmdline = strstr(saved_command_line, "mtdparts=") + 9;
\r
368 memset(g_nandc_info,0,sizeof(g_nandc_info));
\r
370 ret = platform_driver_register(&rknand_driver);
\r
371 printk("rknand_driver:ret = %x \n",ret);
\r
375 module_init(rknand_part_init);
\r
376 module_exit(rknand_part_exit);
\r