展讯LCD浏览之前记

基于展讯sc7731 - Android 5.1 代码分析浏览。将屏蔽细节,把握整体,并且不涉及其他设备和LCD的交互。

以下对sc7731 lcd大体流程进行简要说明。

第一,lcd 的两个阶段
1. 在uboot引起系统阶段,大约1~5秒左右,需要打印一个厂商log。这里对驱动要求非常简单,只要能打印log即可. (下面皆以lcd_ili9486s1_mipi.c为例)
  驱动文件放置路径: u-boot64/drivers/video/sprdfb/lcd/

添加新屏时需要修改的文件分别为:
(1) u-boot64/drivers/video/sprdfb/lcd/Makefile 在该文件中添加编译该屏驱动的宏控

1 obj-$(CONFIG_FB_LCD_ILI9806E_MIPI)  += lcd_ili9806e_mipi.o 

(2) u-boot64/drivers/video/sprdfb/sprdfb_panel.c 在该文件中的 static struct panel_cfg panel_cfg[] 表中,注册该LCD 驱动里面的句柄

1 extern struct panel_spec lcd_ili9806e_mipi_spec;
2 static struct panel_cfg panel_cfg[] = {
3 #if defined(CONFIG_FB_LCD_ILI9806E_MIPI)
4     {
5     .lcd_id = 0x04,
6     .panel = &lcd_ili9806e_mipi_spec,
7     }
8 #endif
9 }        

(3) special/u-boot64/include/configs/sp7731gea.h 在该文件中 #define 对应的宏控 --> 该处表示,该设备uboot 可以使用该LCD

1 #define CONFIG_FB_LCD_ILI9806E_MIPI

2. 系统启动完毕后,lcd 将担负着人机对话的接口。这里的驱动代码以及处理机制,较之uboot目录里的要复杂许多,也精细许多。一切的故事将由此展开。
驱动文件放置路径: kernel/drivers/video/sprdfb/lcd/
添加新屏时需要修改的文件分别为:
(1) kernel/drivers/video/sprdfb/lcd/Makefile 在该文件中添加编译该屏驱动的宏控

1 obj-$(CONFIG_FB_LCD_ILI9806E_MIPI) += lcd_ili9806e_mipi.o

(2) kernel/drivers/video/sprdfb/Kconfig 在该文件中把新屏链接到相关panel(该处修改时,注意语法层次缩进,否则会报错)

1     config FB_LCD_ILI9806E_MIPI
2          boolean "support ili9806e mipi panel"
3          depends on FB_SC8825 || FB_SCX35 || FB_SCX30G || FB_SCX35L
4          default n

(3)special/kernel/arch/arm/configs/sp7731gea-dt_defconfig 在该文件中定义相关宏控("#" 表示注释,宏控定义必须顶最左边写)

1 CONFIG_FB_LCD_ILI9806E_MIPI=y

说明: 如果一份代码下有多个工程甚至是多个工单的话,可能会产生不同的配置,这个时候就需要做一个所谓的差异化special 配置。展讯就这样做的。

第二,LCD 驱动框架流程
1. uboot 代码流程

1      stdio_init()                         @u-boot64/common/stdio.c
2      drv_lcd_init()                       @u-boot64/common/lcd.c
3      lcd_init()                           @u-boot64/common/lcd.c
4      lcd_ctrl_init()                      @u-boot64/drivers/video/sprdfb/sprdfb_main.c
5      sprdfb_probe()                       @u-boot64/drivers/video/sprdfb/sprdfb_panel.c
6      sprdfb_panel_probe()                 @u-boot64/drivers/video/sprdfb/sprdfb_panel.c
7      adapt_panel_from_readid()            @u-boot64/drivers/video/sprdfb/sprdfb_panel.c
8      struct panel_cfg panel_cfg[]         @u-boot64/drivers/video/sprdfb/sprdfb_panel.c

说明: 在uboot里面,lcd 驱动会把自己的句柄注册到 sprdfb_panel 的 panel_cfg[]表中,然后uboot启动的时候,会通过以上流程去读取LCD ID,并传送给kernel。

2. kernel 代码结构(不涉及代码详细流程)
按照比较统一的观点是,lcd 在kernel里面的处理分为 framebuffer file ops 、framebuffer driver、lcd driver。这三部分依次形成调用关系。
但是按照个人观点,在以上三部分中,应该还有个panel,它介于framebuffer 和 具体lcd驱动代码之间,属于一个接口过渡层。

(1) framebuffer file ops
该部分代码位于7731_5.1/kernel/drivers/video/fbmem.c 文件中。
它的作用就是向VFS层提供文件操作接口,实现 struct file_operations 结构体。换句话说,就是向用户空间提供framebuffer 驱动操作接口。
当然,也是必须的,它肯定会调用framebuffer 驱动的一些接口。
至于怎么调,一方面是通过hook的方式,一方面也会使用 file_fb_info()这个接口

 1     static const struct file_operations fb_fops = {
 2     .owner =    THIS_MODULE,
 3     .read =        fb_read,
 4     .write =    fb_write,
 5     .unlocked_ioctl = fb_ioctl,
 6     #ifdef CONFIG_COMPAT
 7     .compat_ioctl = fb_compat_ioctl,
 8     #endif
 9     .mmap =        fb_mmap,
10     .open =        fb_open,
11     .release =    fb_release,
12     #ifdef HAVE_ARCH_FB_UNMAPPED_AREA
13     .get_unmapped_area = get_fb_unmapped_area,
14     #endif
15     #ifdef CONFIG_FB_DEFERRED_IO
16     .fsync =    fb_deferred_io_fsync,
17     #endif
18     .llseek =    default_llseek,
19     };

(2) framebuffer 驱动
该部分代码位于7731_5.1/kernel/drivers/video/sprdfb/sprdfb_main.c文件中,其中 sprdfb_probe() 探针函数是最关键的。
这是LCD 的一个核心,一切的实现都在这里开始。向上,给fb_fops提供调用,以便实现用户接口;向下,通过lcd panel,操作具体的硬件。
总结下展讯该探针函数大概的处理:

 1 static int sprdfb_probe(struct platform_device *pdev)
 2 {
 3     struct fb_info *fb = NULL;
 4
 5     //分配帧缓冲使用的内存空间
 6     fb = framebuffer_alloc(sizeof(struct sprdfb_device), &pdev->dev);
 7
 8     //...
 9
10     //检查设备ID
11     if((SPRDFB_MAINLCD_ID != dev->dev_id) &&(SPRDFB_SUBLCD_ID != dev->dev_id)){
12         //...
13     }
14
15     //LCD 硬件主控制操作函数 control ops
16     if(SPRDFB_MAINLCD_ID == dev->dev_id) {
17         dev->ctrl = &sprdfb_dispc_ctrl;
18     }else {
19         dev->ctrl = &sprdfb_lcdc_ctrl;
20     }
21
22     //设置/获取 帧缓冲区mem各种参数 --LCD 硬件上固定的参数 ?
23     ret = setup_fb_mem(dev, pdev);
24
25     //帧缓冲区显示参数的设置 ---用户可修改的参数 ?
26     setup_fb_info(dev);
27
28     //注册帧缓冲区到系统
29     ret = register_framebuffer(fb);
30
31     //利用帧缓冲的资源初始化平台驱动结构体
32     platform_set_drvdata(pdev, dev);
33
34     //创建sysfs 文件系统
35     sprdfb_create_sysfs(dev);
36
37     //对LCD控制器硬件的初始化
38     dev->ctrl->init(dev);
39
40     //注册睡眠唤醒机制
41     register_early_suspend(&dev->early_suspend);
42
43     //....
44
45     return 0;
46 }

以上需要关注的是:
Control ops: 会牵涉到底层硬件操作接口的调用(想了想,硬件操作接口操作和硬件操作,还是选择了前者。硬件的的操作,是lcd 驱动去做的)
lcd 硬件固定参数: 这个是lcd的物理尺寸,无法更改的。
lcd 可修改参数: 这个可修改是在硬件物理尺寸的基础上来操作的。比如一张图片的大小,或者显示的范围(不一定准确,大概意思差不多).

(3) lcd panel过渡层
该部分代码位于7731_5.1/kernel/drivers/video/sprdfb/sprdfb_panel.c 文件中。
主要介于framebuffer 和 具体的lcd 具体驱动之间。可以简单的看做,是具体lcd 驱动的一个封装,然后把这些封装提供给framebuffer层使用。
我之所以叫它为过渡层,是因为这里纯粹就是一些函数接口的封装,不涉及kernel的模块机制。也就是不会modue_init到编译链接脚本。
以下是该过渡层提供给lcd驱动和framebuffer驱动的接口列表:

 1 //每一个LCD 驱动,都通过该接口加入到一个驱动链表里(这里是仅仅向系统加入一个驱动,不会去匹配硬件的,匹配硬件的操作是在framebuffer 驱动里面完成的)
 2 //换句话说,该接口就是具体的LCD 驱动调用,比如在 ili9806e 的lcd 驱动文件 lcd_ili9806e_mipi.c 会调用该接口
 3 int sprdfb_panel_register(struct panel_cfg *cfg);
 4
 5 //移除一个lcd 驱动
 6 //这里的移除,并非是把一个LCD驱动从链表移除,而是进行一种disable的操作
 7 //该接口将被 sprdfb_remove @drivers/video/sprdfb/sprdfb_main.c 调用
 8 void sprdfb_panel_remove(struct sprdfb_device *dev);
 9
10
11
12 //唤醒接口,与lcd 睡眠唤醒机制相关
13 //在 [email protected]/video/sprdfb/Sprdfb_dispc.c 以及 [email protected]/video/sprdfb/Sprdfb_lcdc.c 里被调用
14 void sprdfb_panel_resume(struct sprdfb_device *dev, bool from_deep_sleep);
15
16 //睡眠接口,与lcd 睡眠唤醒机制相关
17 //在[email protected]/video/sprdfb/Sprdfb_dispc.c 以及 [email protected]/video/sprdfb/Sprdfb_lcdc.c 里被调用
18 void sprdfb_panel_suspend(struct sprdfb_device *dev);
19
20
21 //检查ESD硬件接口, 在framebuffer 里使用, @drivers/video/sprdfb/sprdfb_main.c
22 uint32_t sprdfb_panel_ESD_check(struct sprdfb_device *dev);
23
24 //改变fps,在[email protected]/video/sprdfb/Sprdfb_dispc.c 里使用
25 void sprdfb_panel_change_fps(struct sprdfb_device *dev, int fps_level);
26
27
28 //以下4个接口与图形刷新有关系,在drivers/video/sprdfb/Sprdfb_dispc.c 和 drivers/video/sprdfb/Sprdfb_lcdc.c 都会使用到
29 void sprdfb_panel_after_refresh(struct sprdfb_device *dev);
30 void sprdfb_panel_before_refresh(struct sprdfb_device *dev);
31 void sprdfb_panel_invalidate(struct panel_spec *self);
32 void sprdfb_panel_invalidate_rect(struct panel_spec *self,uint16_t left, uint16_t top, uint16_t right, uint16_t bottom);
33
34
35 //注册framebuffer驱动之前,会检查kernel里面的device ID 和 uboot里面传上来的device ID 是否相同。若不相同,则需要调用该接口,重新准备lcd panel 层
36 //[email protected]/video/sprdfb/sprdfb_main.c 调用
37 bool sprdfb_panel_probe(struct sprdfb_device *dev); //static struct panel_spec *adapt_panel_from_readid(struct sprdfb_device *dev);
38 //匹配kernel中device ID 和 uboot里面传上来的device ID。如果匹配失败,则会导致前面 sprdfb_panel_probe() 接口被调用
39 //[email protected]/video/sprdfb/sprdfb_main.c 调用
40 bool sprdfb_panel_get(struct sprdfb_device *dev);  //static struct panel_spec *adapt_panel_from_uboot(uint16_t dev_id);
41
42
43 //检查lcd panel 是否有效
44 int panel_ready(struct sprdfb_device *dev);

(4) lcd 驱动
这一层,就完全是同lcd硬件打交道了。那么,不同厂商不同型号的lcd,其驱动代码处理细节都是不同的。当然,处理流程肯定是一样的。
这些代码展讯都放在了 7731_5.1/kernel/drivers/video/sprdfb/lcd/ 的目录下。至于如何添加新屏,前面已经详细写过。
每个lcd的驱动,都会通过lcd panel层提供的sprdfb_panel_register()接口,把自己添加到一个panel_list_main 或者 panel_list_sub链表中去。至于细节,暂未分析。

第三,用户空间对framebuffer 驱动的调用
framebuffer驱动已经通过fb_ops 向用户空间提供了文件操作接口。
如果愿意,可以直接使用UNIX的文件编程接口 open/read/write/ioctl也行。当然,对于android这样如此复杂的系统,简单的这样操作,就只有实验价值而已。并且,这里的接口还涉及到c/c++与java的本地交互。实现一个操作库的可行性更高。
在Android里面,提供了一个操作framebuffer 驱动的库,名字叫 gralloc。其最终实现,当然还是会使用open等基础接口,不过其架构、效率、机制都非常的优秀。
在这里,有一个高大上的名字:HAL层。

1. gralloc 库
(1) 基础说明
该部分文件一般放在了 7731_5.1/hardware/libhardware/modules/gralloc/ 目录下。不过展讯在 vendor/sprd/open-source/libs/gralloc/ 目录下又搞了一份。
该库经过编译后,会生成一个动态的 gralloc.default.so 库文件,该库文件会放在 system/lib/hw/ 目录下,系统会通过特定的函数去读取该.so 并提出相应的信息。展讯的名字叫: gralloc.sc8830.so
以上.so文件放置的路径以及.so文件的名字,都可以通过 7731_5.1/hardware/libhardware/modules/gralloc/Android.mk (展讯: 7731_5.1/vendor/sprd/open-source/libs/gralloc/utgard/Android.mk)进行修改。

1 #指定.so 放置的路径
2 LOCAL_MODULE_RELATIVE_PATH := hw
3
4 #生成.so模块的名字
5 LOCAL_MODULE := gralloc.default

(2) gralloc 代码入口:
7731_5.1/hardware/libhardware/modules/gralloc/gralloc.cpp 是gralloc 库的核心文件。
入口: HAL_MODULE_INFO_SYM 是每个HAL模块都必须实现的一个宏,其中最重要的就是base成员。在这里定义了获取module、注册、注销、锁定缓冲区的操作接口。
模块ID: GRALLOC_HARDWARE_MODULE_ID 通过此ID来标示该模块.
关键性的函数接口: gralloc_device_open();

2. 调用 gralloc 模块
调用gralloc 库的地方比较多:

1 7731_5.1/frameworks/native/libs/ui/GraphicBufferAllocator.cpp
2 7731_5.1/frameworks/native/libs/ui/GraphicBufferMapper.cpp
3 7731_5.1/frameworks/native/libs/ui/FramebufferNativeWindow.cpp
4 7731_5.1/frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.cpp
5 7731_5.1/frameworks/native/opengl/libagl/egl.cpp
6 7731_5.1/frameworks/native/opengl/libagl/texture.cpp
7 ....

但是都会通过一个统一的接口来调用: hw_get_module()@hardware/libhardware/hardware.c
所有的HAL调用,应该都是使用该接口。而对于各模块的区别,就是使用模块ID来区别的,比如: GRALLOC_HARDWARE_MODULE_ID

(over)
2015-12-31

时间: 2024-10-16 02:38:02

展讯LCD浏览之前记的相关文章

展讯sc7731 LCD驱动简明笔记之三

此篇笔记基于sc7731 - android 5.1,对lcd的gralloc库做一个简明笔记. 第一部分 调用gralloc.sc8830.so所谓的Gralloc模块,它就是一个模块,一个操作kernel层framebuffer驱动的动态库模块,它属于大名鼎鼎的HAL层.用的时候就加载到内存空间,不用的时候就从内存空间中卸载掉.下面看下系统如何将该模块加载到内存空间的.在Android系统中,所有访问HAL层模块的应用,都需要通过一个叫 hw_get_module() 的方法去获得需要的HA

展讯sc7731 LCD驱动简明笔记之二

此篇笔记基于sc7731 - android 5.1,对lcd的framebuffer做一个简明笔记. 一共分为两大部分:第一部分,关于LCD的硬件方面的:第二部分,关于lcd核心处理(framebuffer)部分的. 第一部分,LCD硬件相关的 一.液晶 液晶是一种高分子有机材料.当给它加上直流电场后,原本有序的分子排列被打乱,一部分液晶变得不透明,颜色加深,便因此显示出字符和图形. 液晶的光电效应:干涉.散射.衍射.旋光.吸收等. 二.LCD种类 1. 构造: 使用两块玻璃板夹着一块液晶:一

展讯平台 LCD(Mipi) 加载流程分析

stage1 阶段的详细分析参见 uboot 详细注释讲解 我们从 uboot 的 stage2 开始分析. 加载流程分析 首先是完成硬件的初始化. 函数调用流程为: u-boot64/arch/arm/board.c: board_init_r() u-boot64/common/stdio.c: stdio_init() u-boot64/common/lcd.c: drv_lcd_init() lcd_init() u-boot/drivers/video/sprdfb/sprdfb_ma

展讯平台 LCD(Mipi)移植步骤及问题归纳

原创文章,原文地址:http://blog.csdn.net/dearsq/article/details/51210703 欢迎转载,转载请保留地址! PortingGuide Backlight 背光的硬件设计有两种情况: 1. 内置并联背光 2. 外置串联背光 对于 1 的情况,步骤如下: 1.移植对应的 lcd 驱动. 2.设置u-boot\drivers\video\sprdfb\sprdfb_main.c中的背光为内置: void set_backlight(uint32_t val

展讯7731平台驱动调试总结-驱动配置部分

转载至:http://blog.csdn.net/bmw7bmw7/article/details/46126223 展讯7731平台驱动调试总结-驱动配置部分 1. 关键配置文件路径 1). 项目板级配置:idh.code/device/sprd/scx35_sp7731geaplus_pad_qhd/文件夹内各文件 ⑴.BoardConfig.mk---板级宏配置文件.包括设置该板(项目)所使用的uboot/kerenl全局配置宏文件,摄像头接口类型.分辨率等参数,所使用的重力加速度.光线传

展讯7731平台驱动调试总结(2)---- 驱动配置部分

1. 关键配置文件路径 1). 项目板级配置:idh.code/device/sprd/scx35_sp7731geaplus_pad_qhd/文件夹内各文件 ⑴.BoardConfig.mk---板级宏配置文件.包括设置该板(项目)所使用的uboot/kerenl全局配置宏文件,摄像头接口类型.分辨率等参数,所使用的重力加速度.光线传感器,内部存储空间大小分配等. ⑵. init.board.rc---板级自定义启动服务文件(TP,传感器等设备的启动指令放置在此文件中) ⑶.system.pr

展讯CEO:低毛利生存 由中低端转向高端

最近一两年来,芯片市场的热闹有从细分.垂直的圈子向整个大社会场景发酵的迹象. 备受各界关注的高通发垄断案,国家大基金的成立,以及展讯.锐迪科等私有化等等,都意味着这个行业的热度在快速上升.这里面既有芯片产业从欧美.日韩向中国大陆进行梯度产业转移的市场大势,也有中国信息产业界对“缺芯少屏”这一产业桎梏的突围情愫. 无论从哪个角度来看,在中国芯片业本轮纵横捭阖中,展讯都是一家值得更多笔墨的公司.它曾“以彼之道还施彼身”,让联发科的2G产品遭遇严重压力.在国家扶持集成电路发展的风口上,展讯又被紫光以私

三星为何宁选展讯而不与联发科合作

三星为何宁选展讯而不与联发科合作?这个问题一直是业界的悬案,相信很多朋友都有过这种疑问. 老杳还特意就这个问题问过李力游,不过LEO只是神秘的一笑,并没有给出具体解释. 这几年业界多次传出三星要与联发科合作,至今为止依然没有变成现实. 老杳这里只是试着给出自己的解释,当然如果有不同理解可以讨论. 展讯与三星的合作最早起源于5500万美元收购的美国射频公司Quorum,有关这笔收购到底是亏还是赚每个人有不同的看法,客观的说是Quorum的射频芯片帮展讯打开了三星合作的大门,这应当也是当年初入展讯的

展讯科技质量好速度快的香港VPS美国云主机企业免备案QQ95028265

展讯科技美国机房位于美国洛杉矶,机房配置豪华,机器速度快稳定性好, 并且机房有专门的技术人员24小时驻点服务,处理问题速度快,能够完全的应对各种突发问题. 所以想要一款价格实惠,机器质量好的美国云主机那就来展讯科技吧. 双核CPU | 512M内存 | 60G硬盘 | 10M独享带宽  1ip 月付只需40元 更多详情请咨询客服人员.一手资源.招合作商 QQ: 95028265  Tel:15638290267 官网:http://www.ewidc.com