注:文章都是通过阅读 Android && Linux 平台源码、各位前辈总结的资料、加上自己的思考分析总结出来的,其中难免有理不对的地方,欢迎大家批评指正。文章为个人学习、研究、欣赏之用。图文内容、源码整理自互联网,如有侵权,请联系删除(◕‿◕),转载请注明出处( ©Android @Linux 版权所有),谢谢(๑乛◡乛๑) 、( ͡° ͜ʖ ͡°)、(ಡωಡ)!!!。
(==文章基于 Kernel-3.0.86==)&&(==文章基于 Android 5.0.2==)
【开发板 - 友善之臂 FriendlyARM Cortex-A9 Tiny4412 ADK Exynos4412 ( Android 5.0.2)HD702高清电容屏 扩展套餐】
【开发板 Android 5.0.2 && Kernel 3.0.86 源码链接: https://pan.baidu.com/s/1jJHm74q 密码:yfih】
正是由于前人的分析和总结,帮助我节约了大量的时间和精力,特别感谢!!!
(1)【LCD设备驱动框架分析(数据结构)】
(2)【framebuffer之s3cfb_probe分析】
(3)【LCD驱动框架】
==源码(部分)==:
linux-3.0.86(Kernel 层): FrameBuffer 核心层
- G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\drivers\video\fbmem.c
- G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\include\linux\fb.h
设备驱动层:
- G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\drivers\video\samsung\s3cfb_main.c
- G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\drivers\video\samsung\s3cfb_ops.c
- G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\drivers\video\samsung\s3cfb_fimd6x.c
- G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\drivers\video\cfbimgblt.c
设备平台相关:
- G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\arch\arm\plat-s5p\include\plat\regs-fb-s5p.h
- G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\arch\arm\plat-s5p\include\plat\fb-s5p.h
- G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\arch\arm\mach-exynos\setup-fb-s5p.c
- G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\arch\arm\mach-exynos\tiny4412-lcds.c
- G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\arch\arm\mach-exynos\mach-tiny4412.c
(一)、LCD设备驱动框架图
- 核心层是通用的,不需要任何修改。驱动开发者只需要实现硬件设备驱动层
- 帧缓冲设备可以看做是一个完整的子系统,主要由核心层的fbmem.c和硬件设备驱动层构成
- 核心层代码fnmem.c向上提供了完整的字符设备操作接口,也就是实现注册字符设备,提供通用的open,read,write,ioctl,mmap等接口;向下给硬件设备驱动层提供标准的驱动编程接口;
- 在linux系统中,一个硬件控制器(显卡)抽象为一个fb_info结构,要实现一个LCD驱动就是要实现这个结构,并且使用核心层提供的注册函数注册
- fb_info中通过其中的fb_ops结构指针提供了实际硬件操作方法
- fb_info中通过其中的fb_var_screeninfo结构和fb_fix_screeninfo结构提供了具体lcd屏基本信息
- 注册:register_framebuffer
- 注销:unregister_framebuffer
(1)、Framebuffer之fbmem.c概括
LCD框架的fbmem.c已经帮我们完成了日常驱动程序的工作,如:注册字符设备、分配设备号、创建类等。
也有了操作函数fb_fops,但它只是一个框架,在具体执行的时候需要知道硬件具体的一些参数,比如分辨率、数据基地址等信息。
因此,我们要利用这一框架,就得构造一个fb_info结构体,完成硬件初始化,设置相关参数等操作,再使用register_framebuffer()将fb_info向上注册。
这样,fbmem.c就可以从registered_fb[]这个数组获得fb_info参数,进行相关的硬件操作。
比如:应用层app想read(),就会调用fbmem.c的fb_read(),在fb_read里面会先尝试使用xxfb.c提供的read()操作函数,如果没有,再根据fb_info
信息得到数据基地址,将基地址开始的数据,返回给应用层,实现读操作。
(二)、platform_device && platform_driver分析
(1)、platform_device分析
Log:
<4>[ 0.180000] zjj.android.display.sys tiny4412_get_lcd() march-tiny4412.c
<4>[ 0.180000] zjj.android.display.sys s3cfb_set_platdata() march-tiny4412.c
1 | G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\arch\arm\mach-exynos\mach-tiny4412.c |
根据打印Log,可以知道刚开机选择了LCD HD702
Log:
<4>[ 0.000000] Machine: TINY4412
<4>[ 0.000000] TINY4412: HD702 selected
通过s3cfb_set_platdata这个函数来单独设置platdata。因为内核中实现了多个LCD设备的platdata,用户可通过相应的宏定义来选择设置。它在启动时通过smdk4x12_machine_init()函数加载,保证platdata在内核启动时就已经设置好。
1 | G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\arch\arm\plat-s5p\dev-fimd-s5p.c |
s3c_device_fb的设备信息如下:
1 | G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\arch\arm\plat-s5p\dev-fimd-s5p.c |
(2)、platform_driver分析
tiny4412-lcds.c :设备参数相关文件
s3cfb_fimd6x.c:具体平台硬件相关文件
s3cfb_ops.c:fb操作集合
s3cfb_main.c :驱动框架
s3cfb_main.c中的s3cfb_probe设备探测,是驱动注册的主要函数
2.1、s3cfb驱动注册
1 | G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\drivers\video\samsung\s3cfb_main.c |
(三)、s3cfb_probe函数分析
先通过Log整体看看流程:
Log:
Line 215: <4>[ 0.180000] zjj.android.display.sys tiny4412_get_lcd() march-tiny4412.c
Line 217: <4>[ 0.180000] zjj.android.display.sys s3cfb_set_platdata() march-tiny4412.c
Line 389: <4>[ 0.432365] zjj.android.display.sys cfg_gpio() s3cfb_probe s3cfb_main.c
Line 391: <6>[ 0.432476] s3cfb s3cfb.0: src_clk=800000000, vclk=67184640, div=12(11), rate=72727272
Line 393: <6>[ 0.432488] s3cfb s3cfb.0: fimd sclk rate 66666666, clkdiv 0xfffffb
Line 395: <4>[ 0.432576] zjj.android.display.sys s3cfb_init_global() s3cfb_probe s3cfb_main.c
Line 397: <4>[ 0.432583] zjj.android.display.sys s3cfb_set_output s3cfb_fimd6x.c
Line 399: <4>[ 0.432589] zjj.android.display.sys s3cfb_set_output s3cfb_fimd6x.c S3C_VIDCON0 = 0
Line 401: <4>[ 0.432595] zjj.android.display.sys s3cfb_set_output s3cfb_fimd6x.c S3C_VIDCON2 = 0
Line 403: <4>[ 0.432600] zjj.android.display.sys s3cfb_set_display_mode s3cfb_fimd6x.c
Line 405: <4>[ 0.432606] zjj.android.display.sys s3cfb_set_display_mode s3cfb_fimd6x.c S3C_VIDCON0 = 0
Line 407: <4>[ 0.432611] zjj.android.display.sys s3cfb_set_polarity s3cfb_fimd6x.c
Line 409: <4>[ 0.432617] zjj.android.display.sys s3cfb_set_polarity s3cfb_fimd6x.c S3C_VIDCON1 = 680
Line 411: <4>[ 0.432622] zjj.android.display.sys s3cfb_set_timing s3cfb_fimd6x.c
Line 413: <4>[ 0.432627] zjj.android.display.sys s3cfb_set_timing s3cfb_fimd6x.c S3C_VIDTCON0 = 30307
Line 415: <4>[ 0.432634] zjj.android.display.sys s3cfb_set_timing s3cfb_fimd6x.c S3C_VIDTCON1 = 131317
Line 417: <4>[ 0.432639] zjj.android.display.sys s3cfb_set_lcd_size s3cfb_fimd6x.c S3C_VIDTCON2 = 27fb1f
Line 419: <4>[ 0.432645] zjj.android.display.sys s3cfb_alloc_framebuffer() s3cfb_probe s3cfb_main.c
Line 421: <4>[ 0.432651] zjj.android.display.sys s3cfb_alloc_framebuffer() s3cfb_ops.c
Line 423: <6>[ 0.432860] s3cfb s3cfb.0: [fb0] win2: dma: 0x60ad8000, cpu: 0xe4879000, size: 0x00bb8000
Line 425: <4>[ 0.448361] zjj.android.display.sys s3cfb_register_framebuffer() s3cfb_probe s3cfb_main.c
Line 425: <4>[ 0.448361] zjj.android.display.sys s3cfb_register_framebuffer() s3cfb_probe s3cfb_main.c
Line 427: <4>[ 0.448606] zjj.android.display.sys s3cfb_draw_logo() s3cfb_ops.c
Line 439: <4>[ 0.449600] zjj.android.display.sys s3cfb_set_clock() s3cfb_probe s3cfb_main.c
Line 441: <4>[ 0.449607] zjj.android.display.sys s3cfb_set_clock s3cfb_fimd6x.c
Line 443: <6>[ 0.449616] s3cfb s3cfb.0: FIMD src sclk = 66666666
Line 445: <4>[ 0.449622] zjj.android.display.sys s3cfb_set_clock s3cfb_fimd6x.c S3C_VIDCON0 = 20
Line 447: <6>[ 0.449629] s3cfb s3cfb.0: parent clock: 66666666, vclk: 67186000, vclk div: 1
Line 449: <4>[ 0.449635] zjj.android.display.sys s3cfb_enable_window() s3cfb_probe s3cfb_main.c
Line 451: <4>[ 0.449641] zjj.android.display.sys s3cfb_window_on s3cfb_fimd6x.c
Line 453: <6>[ 0.449647] s3cfb s3cfb.0: [win2] turn on
Line 455: <4>[ 0.449651] zjj.android.display.sys s3cfb_update_power_state() s3cfb_probe s3cfb_main.c
Line 457: <4>[ 0.449657] zjj.android.display.sys s3cfb_display_on s3cfb_fimd6x.c
Line 459: <4>[ 0.449662] zjj.android.display.sys s3cfb_set_display_on s3cfb_fimd6x.c S3C_VIDCON0 = 23
Line 461: <6>[ 0.449668] s3cfb s3cfb.0: global display is on
Line 463: <6>[ 0.449741] s3cfb s3cfb.0: registered successfully
Line 465: <6>[ 0.450044] s3cfb_extdsp s3cfb_extdsp.0: registered successfully
Line 1959: <4>[ 9.365483] zjj.android.display.sys s3cfb_open() s3cfb_ops.c
Line 1961: <4>[ 9.365606] zjj.android.display.sys s3cfb_open() s3cfb_ops.c
Line 1979: <4>[ 9.555995] zjj.android.display.sys s3cfb_open() s3cfb_ops.c
s3cfb_probe()函数如下:
1 | G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\drivers\video\samsung\s3cfb_main.c |
(1)、pdata->cfg_gpio(pdev)
1 | G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\arch\arm\plat-s5p\include\plat\fb-s5p.h |
(2)、pdata->clk_on(pdev, &fbdev[i]->clock)
Log:
<6>[ 0.432476] s3cfb s3cfb.0: src_clk=800000000, vclk=67184640, div=12(11), rate=72727272
<6>[ 0.432488] s3cfb s3cfb.0: fimd sclk rate 66666666, clkdiv 0xfffffb
1 | static unsigned int get_clk_rate(struct platform_device *pdev, struct clk *sclk) |
(3)、s3cfb_init_global(fbdev[i])
1 | G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\drivers\video\samsung\s3cfb_ops.c |
3.1、s3cfb_set_output()
fbdev->output = OUTPUT_RGB;// OUTPUT_RGB == 0 fbdev->rgb_mode = MODE_RGB_P;// MODE_RGB_P == 0 Line 399: <4>[ 0.432589] zjj.android.display.sys s3cfb_set_output s3cfb_fimd6x.c S3C_VIDCON0 = 0 Line 401: <4>[ 0.432595] zjj.android.display.sys s3cfb_set_output s3cfb_fimd6x.c S3C_VIDCON2 = 0
1 | G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\drivers\video\samsung\s3cfb_fimd6x.c |
3.2、s3cfb_set_display_mode()
Line 403: <4>[ 0.432600] zjj.android.display.sys s3cfb_set_display_mode s3cfb_fimd6x.c
Line 405: <4>[ 0.432606] zjj.android.display.sys s3cfb_set_display_mode s3cfb_fimd6x.c S3C_VIDCON0 = 0
1 | G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\drivers\video\samsung\s3cfb_fimd6x.c |
3.3、s3cfb_set_polarity(fbdev)
Line 407: <4>[ 0.432611] zjj.android.display.sys s3cfb_set_polarity s3cfb_fimd6x.c
Line 409: <4>[ 0.432617] zjj.android.display.sys s3cfb_set_polarity s3cfb_fimd6x.c S3C_VIDCON1 = 680 //二进制:1101.0000000
G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\arch\arm\plat-s5p\include\plat\regs-fb-s5p.h
#define S3C_VIDCON1_FIXVCLK_VCLK_RUN_VDEN_DIS (3 << 9)
#define S3C_VIDCON1_IVCLK_RISING_EDGE (1 << 7)
1<<7 || 11<<9 == 1101.0000000
1 | int s3cfb_set_polarity(struct s3cfb_global *ctrl) |
3.4、s3cfb_set_timing(fbdev)
1 | int s3cfb_set_timing(struct s3cfb_global *ctrl) |
1 | /* s3cfb configs for supported LCD */ |
3.5、s3cfb_set_lcd_size(fbdev)
1 | Line 417: <4>[ 0.432639] zjj.android.display.sys s3cfb_set_lcd_size s3cfb_fimd6x.c S3C_VIDTCON2 = 27fb1f //二进制: 1001111111101100011111 |
(4)、s3cfb_alloc_framebuffer(fbdev[i], i)
1 | G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\drivers\video\samsung\s3cfb_ops.c |
4.1、framebuffer_alloc()
1 | G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\drivers\video\fbsysfs.c |
4.2、s3cfb_init_fbinfo()
1 | int s3cfb_init_fbinfo(struct s3cfb_global *fbdev, int id) |
4.3、s3cfb_map_default_video_memory()
1 | int s3cfb_map_default_video_memory(struct s3cfb_global *fbdev, |
(5)、s3cfb_register_framebuffer(fbdev[i])
1 | G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\drivers\video\samsung\s3cfb_main.c |
(6)、s3cfb_set_clock(fbdev[i])
Line 439: <4>[ 0.449600] zjj.android.display.sys s3cfb_set_clock() s3cfb_probe s3cfb_main.c Line 441: <4>[ 0.449607] zjj.android.display.sys s3cfb_set_clock s3cfb_fimd6x.c Line 443: <6>[ 0.449616] s3cfb s3cfb.0: FIMD src sclk = 66666666 Line 445: <4>[ 0.449622] zjj.android.display.sys s3cfb_set_clock s3cfb_fimd6x.c S3C_VIDCON0 = 20 //1000.00
S3C_VIDCON0_CLKVAL_F(x) (((x) & 0xff) << 6)
ENVID_F 0
ENVID 0
1 | G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\drivers\video\samsung\s3cfb_fimd6x.c |
(7)、s3cfb_enable_window(fbdev[0], pdata->default_win)
1 | Line 449: <4>[ 0.449635] zjj.android.display.sys s3cfb_enable_window() s3cfb_probe s3cfb_main.c |
(8)、s3cfb_display_on(fbdev[i])
1 |
|
然后开启背光,LCD就开始显示画面了。
1 | G:\Android-5.0.2\linux-3.0.86-20170221\linux-3.0.86\drivers\video\samsung\s3cfb_main.c |
(四)、参考文档:
(1)【LCD设备驱动框架分析(数据结构)】
(2)【framebuffer之s3cfb_probe分析】
(3)【LCD驱动框架】