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 sn_data[512];
\r
65 static char vendor0[512];
\r
67 char GetSNSectorInfo(char * pbuf)
\r
69 memcpy(pbuf,sn_data,0x200);
\r
73 char GetSNSectorInfoBeforeNandInit(char * pbuf)
\r
75 memcpy(pbuf,sn_data,0x200);
\r
79 char GetVendor0InfoBeforeNandInit(char * pbuf)
\r
81 memcpy(pbuf,vendor0 + 8,504);
\r
85 int GetParamterInfo(char * pbuf , int len)
\r
91 void rknand_spin_lock_init(spinlock_t * p_lock)
\r
93 spin_lock_init(p_lock);
\r
95 EXPORT_SYMBOL(rknand_spin_lock_init);
\r
97 void rknand_spin_lock(spinlock_t * p_lock)
\r
99 spin_lock_irq(p_lock);
\r
101 EXPORT_SYMBOL(rknand_spin_lock);
\r
103 void rknand_spin_unlock(spinlock_t * p_lock)
\r
105 spin_unlock_irq(p_lock);
\r
107 EXPORT_SYMBOL(rknand_spin_unlock);
\r
110 struct semaphore g_rk_nand_ops_mutex;
\r
111 void rknand_device_lock_init(void)
\r
113 sema_init(&g_rk_nand_ops_mutex, 1);
\r
115 EXPORT_SYMBOL(rknand_device_lock_init);
\r
116 void rknand_device_lock (void)
\r
118 down(&g_rk_nand_ops_mutex);
\r
120 EXPORT_SYMBOL(rknand_device_lock);
\r
122 int rknand_device_trylock (void)
\r
124 return down_trylock(&g_rk_nand_ops_mutex);
\r
126 EXPORT_SYMBOL(rknand_device_trylock);
\r
128 void rknand_device_unlock (void)
\r
130 up(&g_rk_nand_ops_mutex);
\r
132 EXPORT_SYMBOL(rknand_device_unlock);
\r
135 int rk_nand_get_device(struct rknand_info ** prknand_Info)
\r
137 *prknand_Info = gpNandInfo;
\r
140 EXPORT_SYMBOL(rk_nand_get_device);
\r
142 unsigned long rknand_dma_flush_dcache(unsigned long ptr,int size,int dir)
\r
144 #ifdef CONFIG_ARM64
\r
145 __flush_dcache_area((void *)ptr, size + 63);
\r
147 __cpuc_flush_dcache_area((void*)ptr, size + 63);
\r
149 return ((unsigned long )virt_to_phys((void *)ptr));
\r
151 EXPORT_SYMBOL(rknand_dma_flush_dcache);
\r
153 unsigned long rknand_dma_map_single(unsigned long ptr,int size,int dir)
\r
155 return dma_map_single(NULL,(void*)ptr,size, dir?DMA_TO_DEVICE:DMA_FROM_DEVICE);
\r
157 EXPORT_SYMBOL(rknand_dma_map_single);
\r
159 void rknand_dma_unmap_single(unsigned long ptr,int size,int dir)
\r
161 dma_unmap_single(NULL, (dma_addr_t)ptr,size, dir?DMA_TO_DEVICE:DMA_FROM_DEVICE);
\r
163 EXPORT_SYMBOL(rknand_dma_unmap_single);
\r
165 int rknand_flash_cs_init(int id)
\r
169 EXPORT_SYMBOL(rknand_flash_cs_init);
\r
171 int rknand_get_reg_addr(int *pNandc0,int *pNandc1,int *pSDMMC0,int *pSDMMC1,int *pSDMMC2)
\r
173 *pNandc0 = (int)g_nandc_info[0].reg_base;
\r
174 *pNandc1 = (int)g_nandc_info[1].reg_base;
\r
177 EXPORT_SYMBOL(rknand_get_reg_addr);
\r
179 int rknand_nandc_irq_init(int id,int mode,void * pfun)
\r
182 int irq= g_nandc_info[id].irq;
\r
186 ret = request_irq(irq, pfun, 0, "nandc", g_nandc_info[id].reg_base);
\r
188 //printk("request IRQ_NANDC %x irq %x, ret=%x.........\n",id,irq, ret);
\r
192 free_irq(irq, NULL);
\r
196 EXPORT_SYMBOL(rknand_nandc_irq_init);
\r
198 static int rknand_probe(struct platform_device *pdev)
\r
200 unsigned int id = 0;
\r
202 struct resource *mem;
\r
203 void __iomem *membase;
\r
205 if(gpNandInfo == NULL)
\r
207 gpNandInfo = kzalloc(sizeof(struct rknand_info), GFP_KERNEL);
\r
210 gpNandInfo->nand_suspend_state = 0;
\r
211 gpNandInfo->nand_shutdown_state = 0;
\r
213 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
\r
214 membase = devm_request_and_ioremap(&pdev->dev, mem);
\r
217 dev_err(&pdev->dev, "no reg resource?\n");
\r
220 //printk("rknand_probe %d %x %x\n", pdev->id,(int)mem,(int)membase);
\r
222 if(0==of_property_read_u32(pdev->dev.of_node, "nandc_id", &id))
\r
230 memcpy(vendor0,membase+0x1400,0x200);
\r
231 memcpy(sn_data,membase+0x1600,0x200);
\r
235 dev_err(&pdev->dev, "nandc id = %d error!\n",id);
\r
238 irq = platform_get_irq(pdev, 0);
\r
239 //printk("nand irq: %d\n",irq);
\r
241 dev_err(&pdev->dev, "no irq resource?\n");
\r
244 g_nandc_info[id].id = id;
\r
245 g_nandc_info[id].irq = irq;
\r
246 g_nandc_info[id].reg_base = membase;
\r
248 g_nandc_info[id].hclk = devm_clk_get(&pdev->dev, "hclk_nandc");
\r
249 g_nandc_info[id].clk = devm_clk_get(&pdev->dev, "clk_nandc");
\r
250 g_nandc_info[id].gclk = devm_clk_get(&pdev->dev, "g_clk_nandc");
\r
252 if (unlikely(IS_ERR(g_nandc_info[id].clk)) || unlikely(IS_ERR(g_nandc_info[id].hclk))
\r
253 || unlikely(IS_ERR(g_nandc_info[id].gclk))) {
\r
254 printk("rknand_probe get clk error\n");
\r
258 clk_set_rate(g_nandc_info[id].clk,150*1000*1000);
\r
259 g_nandc_info[id].clk_rate = clk_get_rate(g_nandc_info[id].clk );
\r
260 printk("rknand_probe clk rate = %d\n",g_nandc_info[id].clk_rate);
\r
261 gpNandInfo->clk_rate[id] = g_nandc_info[id].clk_rate;
\r
263 clk_prepare_enable( g_nandc_info[id].clk );
\r
264 clk_prepare_enable( g_nandc_info[id].hclk);
\r
265 clk_prepare_enable( g_nandc_info[id].gclk);
\r
269 static int rknand_suspend(struct platform_device *pdev, pm_message_t state)
\r
271 if(gpNandInfo->rknand_suspend && gpNandInfo->nand_suspend_state == 0){
\r
272 gpNandInfo->nand_suspend_state = 1;
\r
273 gpNandInfo->rknand_suspend();
\r
274 //TODO:nandc clk disable
\r
279 static int rknand_resume(struct platform_device *pdev)
\r
281 if(gpNandInfo->rknand_resume && gpNandInfo->nand_suspend_state == 1){
\r
282 gpNandInfo->nand_suspend_state = 0;
\r
283 //TODO:nandc clk enable
\r
284 gpNandInfo->rknand_resume();
\r
289 static void rknand_shutdown(struct platform_device *pdev)
\r
291 if(gpNandInfo->rknand_buffer_shutdown && gpNandInfo->nand_shutdown_state == 0){
\r
292 gpNandInfo->nand_shutdown_state = 1;
\r
293 gpNandInfo->rknand_buffer_shutdown();
\r
297 void rknand_dev_cache_flush(void)
\r
299 if(gpNandInfo->rknand_dev_cache_flush)
\r
300 gpNandInfo->rknand_dev_cache_flush();
\r
304 static const struct of_device_id of_rk_nandc_match[] = {
\r
305 { .compatible = "rockchip,rk-nandc" },
\r
310 static struct platform_driver rknand_driver = {
\r
311 .probe = rknand_probe,
\r
312 .suspend = rknand_suspend,
\r
313 .resume = rknand_resume,
\r
314 .shutdown = rknand_shutdown,
\r
318 .of_match_table = of_rk_nandc_match,
\r
320 .owner = THIS_MODULE,
\r
324 static void __exit rknand_part_exit(void)
\r
326 printk("rknand_part_exit: \n");
\r
327 platform_driver_unregister(&rknand_driver);
\r
328 if(gpNandInfo->rknand_exit)
\r
329 gpNandInfo->rknand_exit();
\r
334 MODULE_ALIAS(DRIVER_NAME);
\r
335 static int __init rknand_part_init(void)
\r
338 printk("%s\n", RKNAND_VERSION_AND_DATE);
\r
340 cmdline = strstr(saved_command_line, "mtdparts=") + 9;
\r
343 memset(g_nandc_info,0,sizeof(g_nandc_info));
\r
345 ret = platform_driver_register(&rknand_driver);
\r
346 printk("rknand_driver:ret = %x \n",ret);
\r
350 module_init(rknand_part_init);
\r
351 module_exit(rknand_part_exit);
\r