收藏 分销(赏)

Linux的LCD驱动源码分析及移植.doc

上传人:xrp****65 文档编号:7224000 上传时间:2024-12-28 格式:DOC 页数:30 大小:6.52MB 下载积分:10 金币
下载 相关 举报
Linux的LCD驱动源码分析及移植.doc_第1页
第1页 / 共30页
Linux的LCD驱动源码分析及移植.doc_第2页
第2页 / 共30页


点击查看更多>>
资源描述
Linux的LCD驱动源码分析及移植(三部曲) 第一部分: 基于ARM9处理器的linux-2.6.32.2操作系统内核移植手记part5.1(LCD驱动源码分析及移植之platform device) 1.与LCD控制器硬件相关的寄存器内容请参照三星S3C2440A技术手册中的第15章。 2. LCD Controller的平台设备定义如下(文件位于 linux/arch/arm/plat-s3c24xx/devs.c): 1. /* LCD Controller */ 2. 3. static struct resource s3c_lcd_resource[] = { 4.     [0] = { 5.         .start = S3C24XX_PA_LCD, 6.         .end = S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1, 7.         .flags = IORESOURCE_MEM, 8.     }, 9.     [1] = { 10.         .start = IRQ_LCD, 11.         .end = IRQ_LCD, 12.         .flags = IORESOURCE_IRQ, 13.     } 14. 15. }; 16. 17. static u64 s3c_device_lcd_dmamask = 0xffffffffUL; 18. 19. struct platform_device s3c_device_lcd = { 20.     .name         = "s3c2410-lcd", 21.     .id         = -1, 22.     .num_resources     = ARRAY_SIZE(s3c_lcd_resource), 23.     .resource     = s3c_lcd_resource, 24.     .dev = { 25.         .dma_mask        = &s3c_device_lcd_dmamask, 26.         .coherent_dma_mask    = 0xffffffffUL 27.     } 28. }; 29. 30. EXPORT_SYMBOL(s3c_device_lcd); 平台设备的结构体定义为s3c_device_lcd,该设备在平台总线中的名字取为s3c2410-lcd,该平台设备申请的两个板级资源为以S3C24XX_PA_LCD为起始的IORESOURCE_MEM资源和一个定义为IRQ_LCD的IORESOURCE_IRQ资源。 其中, 1. #define S3C24XX_PA_LCD S3C2410_PA_LCD 1. /* LCD controller */ 2. #define S3C2410_PA_LCD     (0x4D000000) 3. #define S3C24XX_SZ_LCD     SZ_1M 0x4D000000为LCDCON1寄存器的地址。 3. LCD Controller的平台设备的注册如下(文件位于linux/arch/arm/mach-s3c2440/mach-smdk2440.c): 1. static struct platform_device *smdk2440_devices[] __initdata = { 2.     &s3c_device_usb, 3. 4.     &s3c_device_lcd, 5. 6.     &s3c_device_wdt, 7.     &s3c_device_i2c0, 8.     &s3c_device_iis, 9.     &s3c_device_rtc, 10. }; 以上第4行代码将lcd平台设备注册进内核。 4.在系统初始化时将smdk2440_fb_info结构体添加进平台设备的私有结构中。具体流程如下: 4.1 1. MACHINE_START(S3C2440, "SMDK2440") 2.     /* Maintainer: Ben Dooks <ben@fluff.org> */ 3.     .phys_io    = S3C2410_PA_UART, 4.     .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, 5.     .boot_params    = S3C2410_SDRAM_PA + 0x100, 6. 7.     .init_irq    = s3c24xx_init_irq, 8.     .map_io        = smdk2440_map_io, 9.     .init_machine    = smdk2440_machine_init, 10.     .timer        = &s3c24xx_timer, 11. MACHINE_END 启动S3C2440机器,系统将通过“.init_machine    = smdk2440_machine_init,”调用smdk2440_machine_init()函数。 4.2 1. static void __init smdk2440_machine_init(void) 2. { 3.     s3c24xx_fb_set_platdata(&smdk2440_fb_info); 4.     s3c_i2c0_set_platdata(NULL); 5. 6.     platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices)); 7.     smdk_machine_init(); 8. } 在 smdk2440_machine_init函数中,通过“ s3c24xx_fb_set_platdata(&smdk2440_fb_info);”将smdk2440_fb_info添加进平台设备的私有结构中。 4.3 1. void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info *pd) 2. { 3.     struct s3c2410fb_mach_info *npd; 4. 5.     npd = kmalloc(sizeof(*npd), GFP_KERNEL); 6.     if (npd) { 7.         memcpy(npd, pd, sizeof(*npd)); 8.         s3c_device_lcd.dev.platform_data = npd; 9.     } else { 10.         printk(KERN_ERR "no memory for LCD platform data\n"); 11.     } 12. } 以上代码为smdk2440_fb_info结构的添加过程,其中“s3c_device_lcd.dev.platform_data = npd;”为核心实现部分。 4.4 1. static struct s3c2410fb_mach_info smdk2440_fb_info __initdata = { 2.     .displays    = &smdk2440_lcd_cfg, 3.     .num_displays    = 1, 4.     .default_display = 0, 5. 6. #if 0 7.     /* currently setup by downloader */ 8.     .gpccon        = 0xaa940659, 9.     .gpccon_mask    = 0xffffffff, 10.     .gpcup        = 0x0000ffff, 11.     .gpcup_mask    = 0xffffffff, 12.     .gpdcon        = 0xaa84aaa0, 13.     .gpdcon_mask    = 0xffffffff, 14.     .gpdup        = 0x0000faff, 15.     .gpdup_mask    = 0xffffffff, 16. #endif 17. 18.     //.lpcsel        = ((0xCE6) & ~7) | 1<<4, 19. }; 以上为smdk2440_fb_info结构体定义。在此需要注释掉源码中的“.lpcsel        = ((0xCE6) & ~7) | 1<<4”!本结构中的关键为“ .displays    = &smdk2440_lcd_cfg,”,即LCD的硬件参数,需要根据具体的LCD屏幕来确定,小生使用的是天嵌3.5寸屏幕,所以该结构体的赋值如下: 4.5 1. static struct s3c2410fb_display smdk2440_lcd_cfg __initdata = { 2. 3.     .lcdcon5    = S3C2410_LCDCON5_FRM565 | 4.              S3C2410_LCDCON5_INVVLINE | 5.              S3C2410_LCDCON5_INVVFRAME | 6.              S3C2410_LCDCON5_PWREN | 7.              S3C2410_LCDCON5_HWSWP, 8. 9.     .type        = S3C2410_LCDCON1_TFT, 10. 11.     .width        = 320, 12.     .height        = 240, 13. 14.     .pixclock    = 80000, /* HCLK 100 MHz, divisor 3 */ 15.     .xres        = 320, 16.     .yres        = 240, 17.     .bpp        = 16, 18. 19.     .setclkval    = 0x3, 20.     .left_margin    = 28,    /* for HFPD*/ 21.     .right_margin    = 24,    /* for HBPD*/ 22.     .hsync_len    = 42,    /* for HSPW*/ 23.     .upper_margin    = 6,    /* for VFPD*/ 24.     .lower_margin    = 2,    /* for VBPD*/ 25.     .vsync_len    = 12,    /* for VSPW*/ 26.      27. }; 以上位LCD屏幕硬件参数。 注: a.本文旨在将与友善之臂开发板配套的的linux-2.6.32.2内核移植到天嵌科技的TQ2440开发板上。 b. 硬件平台:天嵌科技TQ2440开发板(标配) c. 软件平台:linux-2.6.32.2内核源码 第二部分: 基于ARM9处理器的linux-2.6.32.2操作系统内核移植手记part5.2(LCD驱动源码分析及移植之platform driver)  5.LCD驱动模块的注册与注销: 2. int __init s3c2410fb_init(void) 3. { 4.     int ret = platform_driver_register(&s3c2410fb_driver); 5. 6.     if (ret == 0) 7.         ret = platform_driver_register(&s3c2412fb_driver); 8. 9.     return ret; 10. } 11. 12. static void __exit s3c2410fb_cleanup(void) 13. { 14.     platform_driver_unregister(&s3c2410fb_driver); 15.     platform_driver_unregister(&s3c2412fb_driver); 16. } 17. 18. module_init(s3c2410fb_init); 19. module_exit(s3c2410fb_cleanup); 注册与注销模块由module_init宏与module_exit宏指定。 6.LCD平台设备驱动s3c2410fb_driver。 1. static struct platform_driver s3c2410fb_driver = { 2.     .probe        = s3c2410fb_probe, 3.     .remove        = s3c2410fb_remove, 4.     .suspend    = s3c2410fb_suspend, 5.     .resume        = s3c2410fb_resume, 6.     .driver        = { 7.         .name    = "s3c2410-lcd", 8.         .owner    = THIS_MODULE, 9.     }, 10. }; 11. 12. static struct platform_driver s3c2412fb_driver = { 13.     .probe        = s3c2412fb_probe, 14.     .remove        = s3c2410fb_remove, 15.     .suspend    = s3c2410fb_suspend, 16.     .resume        = s3c2410fb_resume, 17.     .driver        = { 18.         .name    = "s3c2412-lcd", 19.         .owner    = THIS_MODULE, 20.     }, 21. }; 该结构定义了LCD驱动程序的名字: "s3c2410-lcd",以及探测函数probe,移除函数remove,电源挂起函数suspend和电源恢复函数resume。 7.探测函数s3c2410fb_probe分析。 1. static int __init s3c2410fb_probe(struct platform_device *pdev) 2. { 3.     return s3c24xxfb_probe(pdev, DRV_S3C2410); 4. } 5. 6. static int __init s3c2412fb_probe(struct platform_device *pdev) 7. { 8.     return s3c24xxfb_probe(pdev, DRV_S3C2412); 9. } 由此可见,真正的探测函数为 s3c24xxfb_probe。 1. static int __init s3c24xxfb_probe(struct platform_device *pdev, 2.                  enum s3c_drv_type drv_type) 3. { 4.     struct s3c2410fb_info *info; 5.     struct s3c2410fb_display *display; 6.     struct fb_info *fbinfo; 7.     struct s3c2410fb_mach_info *mach_info; 8.     struct resource *res; 9.     int ret; 10.     int irq; 11.     int i; 12.     int size; 13.     u32 lcdcon1; 14. 15.     mach_info = pdev->dev.platform_data; 16.     if (mach_info == NULL) { 17.         dev_err(&pdev->dev, 18.             "no platform data for lcd, cannot attach\n"); 19.         return -EINVAL; 20.     } 21. 22.     if (mach_info->default_display >= mach_info->num_displays) { 23.         dev_err(&pdev->dev, "default is %d but only %d displays\n", 24.             mach_info->default_display, mach_info->num_displays); 25.         return -EINVAL; 26.     } 27. 28.     display = mach_info->displays + mach_info->default_display; 29. 30.     irq = platform_get_irq(pdev, 0); 31.     if (irq < 0) { 32.         dev_err(&pdev->dev, "no irq for device\n"); 33.         return -ENOENT; 34.     } 35. 36.     fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev); 37.     if (!fbinfo) 38.         return -ENOMEM; 39. 40.     platform_set_drvdata(pdev, fbinfo); 41. 42.     info = fbinfo->par; 43.     info->dev = &pdev->dev; 44.     info->drv_type = drv_type; 45. 46.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 47.     if (res == NULL) { 48.         dev_err(&pdev->dev, "failed to get memory registers\n"); 49.         ret = -ENXIO; 50.         goto dealloc_fb; 51.     } 52. 53.     size = (res->end - res->start) + 1; 54.     info->mem = request_mem_region(res->start, size, pdev->name); 55.     if (info->mem == NULL) { 56.         dev_err(&pdev->dev, "failed to get memory region\n"); 57.         ret = -ENOENT; 58.         goto dealloc_fb; 59.     } 60. 61.     info->io = ioremap(res->start, size); 62.     if (info->io == NULL) { 63.         dev_err(&pdev->dev, "ioremap() of registers failed\n"); 64.         ret = -ENXIO; 65.         goto release_mem; 66.     } 67. 68.     info->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBASE); 69. 70.     dprintk("devinit\n"); 71. 72.     strcpy(fbinfo->fix.id, driver_name); 73. 74.     /* Stop the video */ 75.     lcdcon1 = readl(info->io + S3C2410_LCDCON1); 76.     writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1); 77. 78.     fbinfo->fix.type     = FB_TYPE_PACKED_PIXELS; 79.     fbinfo->fix.type_aux     = 0; 80.     fbinfo->fix.xpanstep     = 0; 81.     fbinfo->fix.ypanstep     = 0; 82.     fbinfo->fix.ywrapstep     = 0; 83.     fbinfo->fix.accel     = FB_ACCEL_NONE; 84. 85.     fbinfo->var.nonstd     = 0; 86.     fbinfo->var.activate     = FB_ACTIVATE_NOW; 87.     fbinfo->var.accel_flags = 0; 88.     fbinfo->var.vmode     = FB_VMODE_NONINTERLACED; 89. 90.     fbinfo->fbops         = &s3c2410fb_ops; 91.     fbinfo->flags         = FBINFO_FLAG_DEFAULT; 92.     fbinfo->pseudo_palette = &info->pseudo_pal; 93. 94.     for (i = 0; i < 256; i++) 95.         info->palette_buffer[i] = PALETTE_BUFF_CLEAR; 96. 97.     ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info); 98.     if (ret) { 99.         dev_err(&pdev->dev, "cannot get irq %d - err %d\n", irq, ret); 100.         ret = -EBUSY; 101.         goto release_regs; 102.     } 103. 104.     info->clk = clk_get(NULL, "lcd"); 105.     if (!info->clk || IS_ERR(info->clk)) { 106.         printk(KERN_ERR "failed to get lcd clock source\n"); 107.         ret = -ENOENT; 108.         goto release_irq; 109.     } 110. 111.     clk_enable(info->clk); 112.     dprintk("got and enabled clock\n"); 113. 114.     msleep(1); 115. 116.     info->clk_rate = clk_get_rate(info->clk); 117. 118.     /* find maximum required memory size for display */ 119.     for (i = 0; i < mach_info->num_displays; i++) { 120.         unsigned long smem_len = mach_info->displays[i].xres; 121. 122.         smem_len *= mach_info->displays[i].yres; 123.         smem_len *= mach_info->displays[i].bpp; 124.         smem_len >>= 3; 125.         if (fbinfo->fix.smem_len < smem_len) 126.             fbinfo->fix.smem_len = smem_len; 127.     } 128. 129.     /* Initialize video memory */ 130.     ret = s3c2410fb_map_video_memory(fbinfo); 131.     if (ret) { 132.         printk(KERN_ERR "Failed to allocate video RAM: %d\n", ret); 133.         ret = -ENOMEM; 134.         goto release_clock; 135.     } 136. 137.     dprintk("got video memory\n"); 138. 139.     fbinfo->var.xres = display->xres; 140.     fbinfo->var.yres = display->yres; 141.     fbinfo->var.bits_per_pixel = display->bpp; 142. 143.     s3c2410fb_init_registers(fbinfo); 144. 145.     s3c2410fb_check_var(&fbinfo->var, fbinfo); 146. 147.     ret = s3c2410fb_cpufreq_register(info); 148.     if (ret < 0) { 149.         dev_err(&pdev->dev, "Failed to register cpufreq\n"); 150.         goto free_video_memory; 151.     } 152. 153.     ret = register_framebuffer(fbinfo); 154.     if (ret < 0) { 155.         printk(KERN_ERR "Failed to register framebuffer device: %d\n", 156.             ret); 157.         goto free_cpufreq; 158.     } 159. 160.     /* create device files */ 161.     ret = device_create_file(&pdev->dev, &dev_attr_debug); 162.     if (ret) { 163.         printk(KERN_ERR "failed to add debug attribute\n"); 164.     } 165. 166.     printk(KERN_INFO "fb%d: %s frame buffer device\n", 167.         fbinfo->node, fbinfo->fix.id); 168. 169.     return 0; 170. 171.  free_cpufreq: 172.     s3c2410fb_cpufreq_deregister(info); 173. free_video_memory: 174.     s3c2410fb_unmap_video_memory(fbinfo); 175. release_clock: 176.     clk_disable(info->clk); 177.     clk_put(info->clk); 178. release_irq: 179.     free_irq(irq, info); 180. release_regs: 181.     iounmap(info->io); 182. release_mem: 183.     release_resource(info->mem); 184.     kfree(info->mem); 185. dealloc_fb: 186.     platform_set_drvdata(pdev, NULL); 187.     framebuffer_release(fbinfo); 188.     return ret; 189. } 7.1 1. mach_info = pdev->dev.platform_data; 2.     if (mach_info == NULL) { 3.         dev_err(&pdev->dev, 4.             "no platform data for lcd, cannot attach\n"); 5.         return -EINVAL; 6.     } 7. 8.     if (mach_info->default_display >= mach_info->num_displays) { 9.         dev_err(&pdev->dev, "default is %d but only %d displays\n", 10.             mach_info->default_display, mach_info->num_displays); 11.         return -EINVAL; 12.     } 13. 14.     display = mach_info->displays + mach_info->default_display; 第一行用于获取platform device中定义的平台数据(已经在本博客的上一篇文章中提及)。其中的mach_info定义如下: 1. struct s3c2410fb_mach_info *mach_info; 1. struct s3c2410fb_mach_info { 2. 3.     struct s3c2410fb_display *displays;    /* attached diplays info */ 4.     unsigned num_displays;            /* number of defined displays */ 5.     unsigned default_display; 6. 7.     /* GPIOs */ 8. 9.     unsigned long    gpcup; 10.     unsigned long    gpcup_mask; 11.     unsigned long    gpccon; 12.     unsigned long    gpccon_mask; 13.     unsigned long    gpdup; 14.     unsigned long    gpdup_mask; 15.     unsigned long    gpdcon; 16.     unsigned long    gpdcon_mask; 17. 18.     /* lpc3600 control register */ 19.     unsigned long    lpcsel; 20. }; 主要是记录LCD的一些属性,包括与显示参数相关的“ struct s3c2410fb_display *displays; ”及使用的GPIO引脚。而 ”if (mach_info->default_display >=mach_info->num_displays) {...}“用来查看显示屏幕的具体规格。 7.2 1. irq = platform_get_irq(pdev, 0); 2.     if (irq < 0) { 3.         dev_err(&pdev->dev, "no irq for device\n"); 4.         return -ENOENT; 5.     } 获取设备中断号(定义于mach-smdk2440.c中)。 7.3 1. fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev); 2.     if (!fbinfo) 3.         return -ENOMEM; 4. 5.     platform_set_drvdata(pdev, fbinfo); 在内存中申请sizeof(struct s3c2410fb_info)+sizeof(struct fb_info)大小的空间,然后将获得的fbinfo设置为平台设备的驱动数据。其中framebuffer_alloc源码如下: 1. /** 2.  * framebuffer_alloc - c
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 百科休闲 > 其他

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服