1、资料快车
1)正点原子(framebuffer):
https://doc.embedfire.com/linux/imx6/driver/zh/latest/linux_driver/framebuffer_sub_system.html
2)Framebuff结构体 :
https://www.cnblogs.com/lifexy/p/7604011.html
3)正点原子嵌入式linux驱动开发——Linux LCD驱动
https://zhuanlan.zhihu.com/p/663352463
4)Linux驱动开发之LCD显示驱动调试-TCON
https://blog.csdn.net/weixin_45244289/article/details/119924258
5) Linux驱动开发: FrameBuffe(LCD)驱动开发(FrameBuffer帧原理、MMAP驱动、OLED驱动)
https://cloud.tencent.com/developer/article/1933138
5)IMX6ULL-LCD-韦东山
2、preface
1、LCD驱动程序属于字符设备
2、为什么用户的FB需要向内核申请内存?
因为FB最终是给内核使用的,因此需要内核分配好,再mmap给用户使用
3、timming是指哪些?在代码层面,就是描述一帧图片的各个规格(分辨率、时钟频率);
>>总的来说就是告诉处理器,以怎样的速度传输(使用时钟频率来表示),在显示屏什么位置进行显示(使用分辨率等术语来表示,屏参/设备树中给出各个点的坐标 width/height/边框)
3、Panel-LCD硬件原理
1)preface
1、Panel硬件所需要的信号和接口纷繁复杂,这也是硬件发展的更新迭代的结果,种类和细节很多,每个主题需要额外的资料深入;
2、理解Panel的众多参数和结构,是分析驱动程序的基础,务必背下来;
3、屏幕种类:
https://blog.csdn.net/azj2019/article/details/107845843
https://zhuanlan.zhihu.com/p/465894506
1)低端产品使用LED;高端产品手机电视常用LCD;高端产品曲面屏,柔性场景使用OLED;
2)这里讨论最常见的LCD, TFT-LCD;

接下来从微观到宏观的方式来说明一帧画面的显示过程
2)屏幕显示的原理
1、一帧画面的显示组成

1)对于1920×1080分辨率的TFT LCD来说, 共需要1920×1080×3个这样的点组合而成;
2)一帧电子画面本质上就是通过不同的颜色 构成表达;
2、一个像素pixel的显示原理

一个像素的颜色由三原色(RGB)混合而成

3、灰阶(色深)
1)单靠RGB三种颜色组合出来的颜色是有限的,那如何是好?
2)通过变化三原色亮度,转化为器件的工作原理就是一个发红色/蓝色/绿色的器件,控制其透光程度 来控制亮暗程度,就可以产生不同“层次”的红色/蓝色/绿色,那样组合出来的颜色就十分丰富了,术语称为灰阶,使用色深 来描述亮暗程度范围;

一种颜色的色深位数越高,色彩越丰富,常见有8bit、10bit,图示为一个亚像素使用10bit来表示
4、一个像素点的数据如何表示?
颜色模型相当于用不同的格式来描述一个颜色。常见的有RGB、YUV、HSV、HSI等。最常用的为RGB,我们从RGB入手。
1)数据单位
bpp(bits per pixel),每个像素用多少数据位来表示
2)三种常见的RGB888/RGB565/RGB555像素表示法
可以用24位数据来表示红绿蓝,也可以用16位(还有其他),比如:
24bpp:RGB888实际上会用到32位,其中8位未使用,其余24位中分别用8位表示红®、绿(G)、蓝(B)
16bpp:有RGB565,RGB555
RGB565:用5位表示红、6位表示绿、5位表示蓝
RGB555:16位数据中用5位表示红、5位表示绿、5位表示蓝,浪费一位

主控 根据屏幕设计选择合适的像素格式数据;
3)TFT-LCD电路驱动逻辑框图

1、电路线路主要分为三类,数据线路、控制线路、电源线路(Vcom、Gamma);软件重点关注数据线路、控制线路;
2、屏端部件介绍:
1)Timing Controller 根据TTL/LVDS等信号 自动产生时序控制信号(STV/CPV等),并转化Source driver所支持的协议数据,比如常见的miniLVDs(常见于标清、高清屏)、P2P(常见于4K屏),该器件可以分布在屏端、主板端或独立一个TCON小板;
2)Source driver IC 负责接收数据信号,不同屏厂设计不同,决定接收处理哪种协议的信号,如果不支持SOC送出的数据格式,则需要额外增加转换器件,比如TCON;组合虽然很多,但在某一类产品上设计会相对固定,先掌握原理,用到时再去深入了解其协议内容;
3、数据接口总多,RGB-TTL、LVDS、VB1、miniLVDS、P2P等等,传送数据格式是不同的;
1)在硬件设计初期根据产品特性选定;
2)根据屏幕尺寸、连接距离、传输数据量、抗干扰能力、成本、片上资源等维度来选定;
4)TFT-LCD, Display timming control

1、成功在显示器显示一个画面,需要各种信号的配合;
2、总来的来说,干一个事情,在什么位置,什么时间,显示什么数据;
3、控制信号是固定的(在产品设计之初需要按照屏规格书配置好);
4、在运行阶段 数据信号和传输速度 可变;
5、LCD的技术参数:
- 单扫、双扫:从上到下,从左到右;
- 24位显示:16M(24BPP): 16位显示:16K:565、 5551(1:Alpha) ;
- VCLK:每来一个时钟,移动一个像素;显示速度是可以控制的;
5)主控与LCD屏幕的连接

1)上图为RGB接口 ,主控给出的信号,其实不是直接就能驱动屏幕,LCD屏内还集成了时序控制器,将主控给的信号转化为TCON(Timming control)信号和各种电压,最终驱动显示屏显示;
2)我们应该理解panel的各个组成部件(内存、LCD控制器、Tcon控制器等等)的作用,因为不同平台硬件设计这些部件的位置不是固定的,不同产品设计不同,比如LCD控制器有可能直接集成在LCD面板上(比如8080并口接口);
6)LCD控制器的数据来源

1)LCD控制器会周而复始地从内存中取出一个个像素的颜色值,通过信号线发送给屏端,同时也会产生DCLK、VSYNC、HSYNC、DE信号指示LCD显示屏同步工作;
2)Framebuffer显存分配驱动负责还是应用负责?
因为LCD最终要从内核空间取数据,因此内存分配由驱动负责;应用层会去调用mmap (驱动中使用vm_iomap_memory方法将显存暴露给用户空间使用),涉及内存管理,知识点有点深,这里不去深究;
3)Framebuffer显存如何保证读写同步?
驱动或LCD控制器负责,应用层不负责!
4)Framebuffer显存可以有多个?
PC机上大型游戏就需要强大的显存,可以有多个Framebuffer(需要更多的显存,硬件要支持),驱动负责分配,然后通知应用;
7)引脚介绍(RGB-TTL-LCD)

1、LED背光一般给的是高压,由专门的电源芯片负责驱动!主控将BL_ON和PWM给到电源芯片
2、两类信号线:数据线、控制信号线、各类电压
1)panel相对其它模块跟多一些,屏驱接口属于高速信号,多用串行差分技术;
2)软件负责数据信号、控制信号的正确性;
3)硬件负责各类电压正确性;
8)接口方案
1、显示屏的接口可谓是ARM模块之最,一个模块竟有十多种!
2、不同产品所用的硬件设计千差万别,这也是嵌入式的特性所在,本质原理不变,以不变应万变!
3、我们从低端到高端的维度进行梳理;
1、接口总览

1)ADAS:Advanced Driving Assistance System
2)MIPI:Mobile Industry Processor Interface
3)MIPI-DBI (Display Bus Interface)
4)MIPI-DPI (Display Pixel Interface)
5)MIPI-DSI (Display Serial Interface)
6)GMSL:Gigabit Multimedia Serial Link - 多屏应用
7)FPD-Link :Flat Panel Display Link - 车载摄像头
2、8080接口
集成LCD控制器的屏幕称为LCM,MCU使用8080接口与此类屏幕通信,对于LCM的接口8080非常简单,就和内存差不多。
需要读数据,所以有一个读信号RD;
需要写数据,所以有一个写信号WR;
需要分辨这个模组和其他东西,所以有一个片选信号CS;
需要传输数据,需要数据线DB0-DB15,
需要分辨传输的地址,所以需要地址线,但是地址线和数据线共用,通过RS信号来分辨DB0-DB15上传输的是地址还是数据。

应用场景:由于MCU没有LCD控制器,IO数量也有限,因此MCU常用的8080接口LCD模组,这是妥协的选择;
3、RGB-TTL接口


1)TTL:Transistor Transistor Logic的缩写,译为晶体管-晶体管逻辑,TTL电平信号由TTL器件产生;
2)采用TTL接口电路的大多是小尺寸液晶彩电或低分辨率的液晶彩电,旧产品产物,已逐渐被淘汰;
4、LVDS
1)介绍
由于TTL的局限性,迫切需要新的技术,LVDS应运而生,LVDS(Low Voltage Differential Signaling)是一种低摆幅的差分信号技术,它使得信号能在差分PCB 线对或平衡电缆上以几百Mbps(Mbit/s)的速率传输,一般大约77.5M。该接口使用1.2V偏置提供400mV摆幅的信号,低压幅和低电流驱动输出实现了低噪声和低功耗。
LVDS信号包括图像的RGB 基色信号、行同步、场同步信号及时钟信号
2)8Bit LVDS_MAP 连接框图

3)LVDS的几种接口连线设计

1、根据应用场景的传输数据量可以增删差分数据线
1)比如标清屏使用6Bit/8Bit LVDS_MAP,高清屏使用8Bit/10Bit LVDS_MAP;
2、LVDS是将RGB数据打包,串行地发送,这就涉及RGB打包的格式,目前有VESA 或 JEIDA两种格式
不同的显示屏支持VESA 或 JEIDA格式,主控需要设置于屏一样的数据格式;
3、一对差分线也称为1 lane;
4、8Bit LVDS_MAP座子设计

4)LVDS常见接口


5)车载应用场景下两种LVDS接口
深入探索LVDS、GMSL与FPD-Link的数据传输革命
https://blog.csdn.net/weixin_43199439/article/details/141642870
https://blog.csdn.net/u010783226/article/details/120492306
5、MiniLvds
1)mini-LVDS(mini Low Voltage Differential Signaling) 接口与LVDS接口相似,数据信号也是由差分信号线对进行传输;
2)SOC芯片的LVDS和mini-LVDS信号引脚是可以复用的,但电气特性不完全一样,共模电压和差分摆幅更小,一次传输的数据小于LVDS;
3)主要用于驱动Tconless屏,TCON器件集成在SOC中,直接输出TCON信号给屏,即TCON到源驱动器(source板)的传输,一般时钟频率小于330MHZ;
4)mini-LVDS 接口技术是在高分辨率、高色深和高帧速的显示应用中,RSDS接口受限于带宽(数据传输速率170MHZ)的限制而发展起来的;
5)MiniLvds信号接口定义

5)MiniLvds座子

6、VB1
1)随着近些年来电视画面向着高分辨率,高色彩深度,高刷新率的发展,特别是超高清晰度电视、3D电视、240Hz 运动补偿技术的推动,传输速度的高速化以及传输线之间信号的时滞问题愈发显著。大量的LVDS 数据通道增加了厂商的制造成本,同时占用的空间也影响着整机向进一步轻薄化发展。此外,因为LVDS 需要专门的时钟通道,更高的数据带宽可能导致时钟偏移给系统带来不稳定,也会产生严重的电磁干扰,要利用现有技术来提升性能及降低成本已经很难,LVDS 的局限性越发明显,成本压力和技术限制迫使电视制造商寻求替代的解决方案,V-by-One技术应运而生。
对于我们目前较常见的全高清晰度信号1920 x 1080@120Hz 10-bit达到10Gbps 以上数据量。在实际应用中,LVDS 需要24 个数据/时钟通道,而V-by-One仅需要4个数据通道。目前LVDS电缆和信号传输芯片,在整机成本中占很大的比重。而新接口能极有效降低线材成本、简化芯片设计以及节省系统占用空间。此外,由于传输速度可变,原先采用LDVS 技术的设计不需要经过很大的改动便可无缝地过渡到V-by-One上来。
2)接口框图

座子

3)信号线
| 8对差分信号 | 传输图像信号,主板端芯片输出端约有1.1V直流偏置电压,但传输给屏时会经隔离电容进行隔直。 |
|---|---|
| HTPDN | 热拔插识别脚,主板端芯片IO口设置为开漏状态,由于上拉电阻作用,在未连接屏时电压在3.3V,但连接屏后会被屏拉致低电平,用于主板检测是否有连接屏,一般SOC引脚连接 悬空不用。 |
| LOCKN | 用于指示CDR PLL 是否处于锁定状态,未连接屏时被上拉到3.3V,在连接屏后,屏会对输入信号进行时钟和数据还原,而当还原出来的时钟信号锁定后,屏会将LOCKN拉低,一般SOC引脚连接 悬空不用。 |
| Data format 0、Data format 1 | 部分屏用于选择图像分区,如1分区、2分区、4分区、8分区。 |
| IIC:SDA、SCL | IIC接口,可用于设置屏的工作状态,部分屏不接IIC会导致花屏或黑屏。 |
| Bit_sel | 用于设置屏处于10bit工作模式还是8bit工作模式,具体状态可参考屏规格书 |
| L-DIM Enable | 内部调光时能信号,可参考屏规格书,如高电平是外部PWM调光,低电平是内部自动调光。 |
7、MIPI
MIPI表示Mobile Industry Processor Interface,即移动产业处理器接口。是MIPI联盟发起的为移动应用处理器制定的开放标准和一个规范。主要是手机内部的接口(摄像头、显示屏接口、射频/基带接口)等标准化,从而减少手机内部接口的复杂程度及增加设计的灵活性。
对于LCD,MIPI接口可以分为3类:
-
MIPI-DBI (Display Bus Interface)
-
既然是Bus(总线),就是既能发送数据,也能发送命令,常用的8080接口就属于DBI接口。
-
Type B (i-80 system), 8-/9-/16-/18-/24-bit bus
-
Type C (Serial data transfer interface, 3/4-line SPI)
-
-
MIPI-DPI (Display Pixel Interface)
-
Pixel(像素),强调的是操作单个像素,在MPU上的LCD控制器就是这种接口
-
Supports 24 bit/pixel (R: 8-bit, G: 8-bit, B: 8-bit)
-
Supports 18 bit/pixel (R: 6-bit, G: 6-bit, B: 6-bit)
-
Supports 16 bit/pixel (R: 5-bit, G: 6-bit, B: 5-bit)
-
-
MIPI-DSI (Display Serial Interface)
- Serial,相比于DBI、DPI需要使用很多接口线,DSI需要的接口线大为减少
- Supports one data lane/maximum speed 500Mbps
- Supports DSI version 1.01
- Supports D-PHY version 1.00

4、APP访问LCD驱动Driver过程
1)总体流程如下

1.open("/dev/fb0", ...) 主设备号: 29, 次设备号: 0
2.ioctl(fd, FBIOGET_VSCREENINFO, &fb_info->var); //获得可变信息(含有分辨率等)
3.ioctl(fd, FBIOGET_FSCREENINFO, &fb_info->fix); //获得固定信息(含有显存信息)
4.void *ptr = mmap(0,
fb_info->var.yres_virtual * fb_info->fix.line_length,
PROT_WRITE | PROT_READ,
MAP_SHARED, fd, 0); //获得Framebuffer映射到用户空间的地址
5.往ptr地址写数据,LCD会周而复始读取并显示;
其中:通过mmap(系统调用,fbdev子系统实现)映射内核内存到用户内存,用户可以往此内存空间进行读写;
2)Framebuffer显示原理小结
1、framebuffer机制模仿显卡的功能,将显卡硬件结构抽象为一系列的数据结构,可以通过framebuffer的读写直接对显存进行操作。用户可以将framebuffer看成是显存的一个映像,将其映射到进程空间后,就可以直接进行读写操作,写操作会直接反映在屏幕上(LCD会周而复始地将该区域的数据送显)。
2、显示数据的流向:App -> Framebuffer(内存区域) -> display control -> LCD显示屏;
3、多个APP同时向 Framebuff传输数据,如何处理?
同一时刻,显示屏只能显示一帧数据,多个APP的数据需要合成为一帧,因此引入图像层级合成概念,软件算法可以实现?硬件或软件均可以实现,硬件实现会更快速(app1->fb1、app2->fb2、app3->fb3…)

4、静止画面和动态画面显示有区别?
无论是哪一种,对于panel底层来说,没有任何区别;
静止画面 -> framebuffer不刷新,反之动态画面需要按照一定的速度进行刷新;
5、总之底层负责拿数据显示,上层需要构造数据
1)UI界面操作:滑动等效果由用户层调用库绘制,再传递给FB;
2)视频:将视频帧按照一定的速度传递给FB;
5、fbdev驱动源码分析
1)panel驱动架构
不同项目使用的panel架构也不同,常见三种
1、基于fbdev
android/common/common14-5.15/common/drivers/video/fbdev
2、基于media子系统
/android/common/common14-5.15/common/common_drivers/drivers/media/vout/lcd
3、基于DRM
/android/common/common14-5.15/common/common_drivers/drivers/drm
实际项目上如何选用?优劣如何?
1)FB是基础,DRM/media只是对FB架构的进一步封装,DRM/media 可以互相搭配使用;
2)先了解fbdev,再过渡到DRM/media子系统;
Media子系统是一个用于处理多媒体设备的框架,他提供的一组API和驱动程序,用于管理和控制视频、音频和其他多媒体设备;
2)panel - boot
1、Boot部分负责什么?
从kernel移植过来的驱动,做一些必要的初始化,以便在boot阶段能播放开机LOGO;
2、Tcon.bin/PQ.bin等的烧录,后续kernel还会设置?
不会重复烧录,在boot阶段完成即可
3)panel - kernel
1、panel驱动属于 字符类设备
在Linux中,“Framebuffer”或者“fb”都指的是framebuffer设备(与其说是设备,更不如说是一种机制),Linux内核将所有和显示有关的软件和硬件集成到一起,虚拟出来了一个fb设备,在LCD能够正常驱动以后就会有一个/dev/fbn(n从0开始的任意数)设备文件,这个fb有些时候还被称作“帧缓存”。
2、fbdev例子:
s3c2410 LCD frame buffer device
/android/vendor/amlogic/common/kernel/common_5.4/drivers/video/fbdev/s3c2410fb.c
NXP官方编写的Linux下的LCD驱动mxsfb.c
内核4.19在fbdev下,内核5.4移植到DRM架构
3、背光控制
/android/vendor/amlogic/common/kernel/common_5.4/drivers/video/backlight
4、引脚控制使用GPIO子系统和pinctrl子系统
5、fb设备节点
console:/dev/graphics # ls
fb0 fb1 fb2
console:/sys/class/graphics # ls
fb0 fb1 fb2
在TV领域中,只有一个显示屏,多个fb,表明使用三个Framebuffer
7、LCD驱动就是一堆参数的设置!
1)先从驱动中读取fb_info;
2)获取一帧数据 fb×的大小,并映射mmap出来;
3)操作这次内存,填充数据,送到屏幕端;
同一块内存,如何处理消费者-生产者同步的?使用VSYNC机制
4)数据结构
1.fb_info--非常多的名词
/android/vendor/amlogic/common/kernel/common_4.9/include/linux/fb.h
struct fb_info {
atomic_t count; //引用计数,跟踪有多少个用户(进程)打开了此设备
int node; // 设备编号,对应 /dev/fbX 中的 X
struct fb_var_screeninfo var; //variable 可变屏幕参数(可由应用程序更改):分辨率、色深、刷新率等
struct fb_fix_screeninfo fix; //fixable 固定屏幕参数(由驱动设定,应用程序只读):帧缓冲内存的物理地址、长度等。
struct fb_monspecs monspecs; //显示器规格,支持的模式、频率范围
struct fb_pixmap pixmap; // 图像硬件映射器。用于加速绘图操作。
struct fb_pixmap sprite; // 光标硬件映射器。用于硬件光标支持。
struct fb_cmap cmap; // 当前的调色板(颜色映射表),对 8/16 位色深模式尤为重要。
struct fb_videomode *mode; // 当前正在使用的视频模式
struct fb_ops *fbops;
struct device *device; /* This is the parent */
struct device *dev; /* This is this fb device */
int class_flag; /* private sysfs flags */
union {
char __iomem *screen_base; //映射到内核空间的帧缓冲内存虚拟地址
char *screen_buffer;
};
unsigned long screen_size; //射的帧缓冲内存大小(字节)
void *pseudo_palette; //伪调色板,一个驱动内部使用的,用于模拟16色模式的数组
};
1) fb_var_screeninfo 、 fb_fix_screeninfo 和fb_ops是驱动与用户空间应用程序(如ffmpeg)交互最重要的三个结构体。
2) node, count, flags, dev, device 这些结构在register_framebuffer() 注册后由内核框架填充和管理。
2.fb_var_screeninfo
/android/vendor/amlogic/common/kernel/common_4.9/include/linux/fb.h
struct fb_var_screeninfo {
1.screen info
__u32 xres; /* visible resolution */
__u32 yres;
__u32 xres_virtual; /* virtual resolution */ --内核使用此变量表示分配多少个framebuffer内存
__u32 yres_virtual;
__u32 xoffset;
__u32 yoffset;
__u32 bits_per_pixel;
2.Timing
__u32 pixclock;
__u32 left_margin;
}
3.display_timing
/android/vendor/amlogic/common/kernel/common_5.4/include/video/display_timing.h
struct display_timing {
struct timing_entry pixelclock;
struct timing_entry hactive; /* hor. active video */
struct timing_entry hfront_porch; /* hor. front porch */
struct timing_entry hback_porch; /* hor. back porch */
struct timing_entry hsync_len; /* hor. sync len */
struct timing_entry vactive; /* ver. active video */
struct timing_entry vfront_porch; /* ver. front porch */
struct timing_entry vback_porch; /* ver. back porch */
struct timing_entry vsync_len; /* ver. sync len */
enum display_flags flags; /* display flags */ -- pin polarity 引脚极性
}
4.fb_videomode
/android/vendor/amlogic/common/kernel/common_5.4/include/linux/fb.h
struct fb_videomode {
const char *name; /* optional */
u32 refresh; /* optional */
u32 xres;
u32 yres;
u32 pixclock;
u32 left_margin;
u32 right_margin;
u32 upper_margin;
u32 lower_margin;
u32 hsync_len;
u32 vsync_len;
u32 sync;
u32 vmode;
u32 flag;
};
5)fbdev子系统
fbdev子系统的作用,fbmem提供统一的驱动框架和接口,开发者仅需编写s3c2440fb.c即可
1.子系统源码目录
/android/vendor/amlogic/common/kernel/common_4.9/drivers/video/fbdev/core
/android/vendor/amlogic/common/kernel/common_4.9/drivers/video/of_display_timing.c
/android/vendor/amlogic/common/kernel/common_4.9/drivers/video/display_timing.c
2.注册fb设备
/android/vendor/amlogic/common/kernel/common_4.9/drivers/video/fbdev/core/fbmem.c
register_framebuffer(fb_info);
--do_register_framebuffer(fb_info);
----registered_fb[i] = fb_info; //将fb_info放到全局数组里
3.file_operations
static const struct file_operations fb_fops = {
.owner = THIS_MODULE,
.read = fb_read,
.write = fb_write,
.unlocked_ioctl = fb_ioctl, //ioctl实现
.mmap = fb_mmap, //mmap映射内核内存到用户空间,供应用程序使用
.open = fb_open,
};
4.fb_mmap(复杂的内存管理知识域)
用户调用mmap
fb_base = (unsigned char *)mmap(NULL , fix.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
--fb_mmap()
----return vm_iomap_memory(vma, start, len); //将映射好的内存信息返回给用户
5.fb_open
info = get_fb_info(fbidx);
file->private_data = info;
6.fb_ioctl
--do_fb_ioctl(info, cmd, arg);
----case FBIOGET_VSCREENINFO: //获取可变的屏幕信息
----case FBIOGET_FSCREENINFO: //获取固定的屏幕信息
----case FBIOPAN_DISPLAY:
7.从设备树中获取display_timing
/android/vendor/amlogic/common/kernel/common_4.9/drivers/video/of_display_timing.c
of_get_display_timings(struct device_node *np)
--of_parse_display_timing(entry, dt);
----parse_timing_property(np, "hactive", &dt->hactive);
6)fb设备源码分析
LCD驱动程序的核心:
1)分配fb_info;
2)设置fb_info;
3)注册fb_info;
4)硬件相关的设置(1、引脚设置;2、时钟设置;LCD控制器设置;)
1、IMX6ULL fbdev驱动程序
1)LCD控制介绍
IMX6ULL的LCD控制器名称为eLCDIF(Enhanced LCD Interface,增强型LCD接口),主要特性如下:
* 支持MPU模式:有些显示屏自带显存,只需要把命令、数据发送给显示屏即可;即8080接口
* VSYNC模式:跟MPU模式类似,多了VSYNC信号。针对高速数据传输(行场信号)
* 支持DOTCLK模式:RGB接口,就是前面讲的TFT-RGB接口
* 支持ITU-R BT.656接口,可以把4:2:2 YcbCr格式的数据转换为模拟电视信号
* 8/16/18/24/32 bit 的bpp数据都支持,取决于IO的复用设置及寄存器配置
* MPU模式,VSYNC模式,DOTCLK模式,都可以配置时序参数。
2)LCD控制器的数据传输与处理

上图是IMX6ULL的LCD控制器框图。
我们在内存中划出一块内存,称之为显存(framebuffer),软件把数据写入显存。
设置好LCD控制器之后,它会通过AXI总线协议从显存把RGB数据读入FIFO,最后到达LCD接口(LCD Interface)。
3)寄存器设置
1、查看任何芯片的LCD控制器寄存器时,记住几个要点:
1)哪些LCD的信息需要告诉LCD控制器?分辨率、行列时序、像素时钟等;
2)怎么把显存地址、像素格式告诉LCD控制器。
2、LCDIF_CTRL寄存器
[17]: DOTCLK_MODE, 使用DOTCLK模式时-RGB-TTL,设置为1;
[15:14]: INPUT_DATA_SWIZZLE, 显存中像素颜色的数据转给LCD控制器时,字节位置是否交换
[13:12]: CSC_DATA_SWIZZLE,显存中的数据被传入LCD控制器内部并被转换为24BPP后,在它被转给LCD接口之前,字节位置是否交换:
[11:10]: LCD_DATABUS_WIDTH, LCD数据总线宽度,就是对外输出的LCD数据的位宽,8位/16位/18位/24位
[9:8]: WORD_LENGTH, 输入的数据格式,即显存中每个像素占多少位, 8位/16位/18位/24位
[3]: DATA_FORMAT_16_BIT, 0:数据格式为ARGB555; 1:数据格式为RGB565
[2]: DATA_FORMAT_18_BIT, 0:低18位用来表示RGB666,高14位无效 1:高18位用来表示RGB666,低14位无效
[1]: DATA_FORMAT_24_BIT, 0:所有的24位数据都有效,格式为RGB888 1:转给LCD控制器的数据是24位的,但只用到其中的18位, 每个字节用来表示一个原色,每字节中高2位无效
[0]: run, 使能LCD控制器,开始传输数据
3、LCDIF_TRANSFER_COUNT寄存器
[31:16]:V_COUNT,一帧中,有多少行有效数据
[15:0]:H_COUNT,一行中,有多少个像素
4、电气极性寄存器
LCDIF_VDCTRL0/LCDIF_VDCTRL1/LCDIF_VDCTRL2
5. LCDIF_CUR_BUF寄存器
[31:0]:ADDR,LCD控制器正在传输的当前帧在显存中的地址
6.LCDIF_NEXT_BUF寄存器
[31:0]:ADDR,下一帧在显存中的地址
4)驱动程序
IMX6ULL fbdev驱动程序涉及3部分:
1)GPIO设置(通过pinctrl子系统设置引脚,驱动程序不需要写代码,配置设备树即可)
* LCD引脚
* 背光引脚
2)时钟设置
* 确定LCD控制器的时钟
* 根据LCD的DCLK计算相关时钟
3)LCD控制器本身的设置
* 比如设置Framebuffer的地址
* 设置Framebuffer中数据格式、LCD数据格式
* 设置时序
3.imx6ull probe操作
/android/vendor/amlogic/common/kernel/common_4.9/drivers/video/fbdev/mxsfb.c
mxsfb_probe()
1.分配fb结构体
/android/vendor/amlogic/common/kernel/common_4.9/drivers/video/fbdev/core/fbsysfs.c
--framebuffer_alloc()
--platform_get_resource(pdev, IORESOURCE_MEM, 0);
--devm_ioremap_resource(&pdev->dev, res); //映射为虚拟地址供内核使用
2.填充fb结构体、分配fb内存
--mxsfb_init_fbinfo(host, mode)
----mxsfb_init_fbinfo_dt(host, vmode); //从设备树中提取timing
------of_parse_phandle(np, "display", 0);
------of_property_read_u32(display_np, "bits-per-pixel",
&var->bits_per_pixel);
/android/vendor/amlogic/common/kernel/common_4.9/drivers/video/fbdev/core/fbmon.c
------fb_videomode_from_videomode(&vm, vmode); //构造fb_videomode
----dma_alloc_wc(dev, PAGE_ALIGN(fb_size), &fb_phys, GFP_KERNEL); /* Memory allocation for framebuffer */
3.构造fb_var_screeninfo
/android/vendor/amlogic/common/kernel/common_4.9/drivers/video/fbdev/core/modedb.c
--fb_videomode_to_var(&fb_info->var, mode)
--mxsfb_check_var(&fb_info->var, fb_info);
4.注册fb设备
/android/vendor/amlogic/common/kernel/common_4.9/drivers/video/fbdev/core/fbmem.c
--register_framebuffer(fb_info);
----do_register_framebuffer();
------fb_info->dev = device_create(fb_class, fb_info->device, MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
5.设置时钟
--mxsfb_enable_controller(fb_info);
----regulator_enable(host->reg_lcd);
----clk_set_rate() //设置时钟
----mxsfb_enable_axi_clk()
/android/vendor/amlogic/common/kernel/common_4.9/drivers/video/fbdev/mxsfb.c
struct mxsfb_info {
struct fb_info fb_info;
struct platform_device *pdev;
struct clk *clk;
struct clk *clk_axi;
struct clk *clk_disp_axi;
void __iomem *base; /* registers */
unsigned allocated_size;
int enabled;
unsigned ld_intf_width;
unsigned dotclk_delay;
const struct mxsfb_devdata *devdata;
u32 sync;
struct regulator *reg_lcd;
};
/android/vendor/amlogic/common/kernel/common_4.9/drivers/regulator/internal.h
struct regulator {
struct device *dev;
struct list_head list;
unsigned int always_on:1;
unsigned int bypass:1;
unsigned int device_link:1;
int uA_load;
unsigned int enable_count;
unsigned int deferred_disables;
struct regulator_voltage voltage[REGULATOR_STATES_NUM];
const char *supply_name;
struct device_attribute dev_attr;
struct regulator_dev *rdev;
struct dentry *debugfs;
};
static struct fb_ops mxsfb_ops = {
.owner = THIS_MODULE,
.fb_check_var = mxsfb_check_var,
.fb_set_par = mxsfb_set_par,
.fb_setcolreg = mxsfb_setcolreg,
.fb_blank = mxsfb_blank,
.fb_pan_display = mxsfb_pan_display, //切换framebuffer
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
};
2、s3c2410 fbdev驱动程序
1.s3c2410fb probe操作
/android/vendor/amlogic/common/kernel/common_4.9/drivers/video/fbdev/s3c2410fb.c
s3c2410fb_probe()
--s3c24xxfb_probe()
1.分配fb结构体
/android/vendor/amlogic/common/kernel/common_4.9/drivers/video/fbdev/core/fbsysfs.c
----framebuffer_alloc()
2.分配fb内存
----platform_get_resource(pdev, IORESOURCE_MEM, 0);
----info->mem = request_mem_region();
----info->io = ioremap();//映射为虚拟地址供内核使用
----s3c2410fb_map_video_memory(fbinfo); //根据mach_info->num_displays 分配fb内存(支持多个)
------info->screen_base = dma_alloc_wc(); //从DMA内存分配
3.硬件寄存器初始化
----s3c2410fb_init_registers(fbinfo);
----s3c2410fb_check_var(&fbinfo->var, fbinfo); //构造fb_var_screeninfo结构体
4.注册fb设备
/android/vendor/amlogic/common/kernel/common_4.9/drivers/video/fbdev/core/fbmem.c
----register_framebuffer(fbinfo);
----device_create_file(&pdev->dev, &dev_attr_debug); //创建调试节点
6、多Framebuffer架构
1、现代驱动都使用多个Framebuffer?是的
2、多Framebuffer需要硬件什么支持?
1)足够的显存空间; 有的使用普通内存、有的使用DMA内存;
2)并不是越多越好,根据平台的处理速度选择分配多少个Framebuffer;
3、应用程序怎么操作?
填充好数据,通知驱动switch,那样不会很耗费资源?现代SOC速度,可以忽略不计!
4、驱动和应用程序要配合着使用,流程如下

1)驱动先分配多个buffer,表示硬件上支持,等APP查询时会获悉驱动支持多个buffer,再决定使用单buffer还是多buffer;
2)切换完成后,进入下一轮循环;
3)掌握这个基础模型,即使后面使用更复杂的子系统/中间件,封装得再严密,都离不开这个基础核心操作;
1.驱动分配多个framebuffer
/android/vendor/amlogic/common/kernel/common_4.9/drivers/video/fbdev/mxsfb.c
fb_info->fix.smem_len = SZ_32M;
fbi->screen_base = dma_alloc_writecombine(fbi->device,
fbi->fix.smem_len,
(dma_addr_t *)&fbi->fix.smem_start,
GFP_DMA | GFP_KERNEL);
fb_info->fix.smem_len // 含有总buffer大小
fb_info->var // 含有单个buffer信息
2.APP:读取buffer信息
ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix);
ioctl(fd_fb, FBIOGET_VSCREENINFO, &var);
// 计算是否支持多buffer,有多少个buffer
screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
nBuffers = fix.smem_len / screen_size;
3.APP:使能多buffer
var.yres_virtual = nBuffers * var.yres;
ioctl(fd_fb, FBIOPUT_VSCREENINFO, &var);
4.APP:获取buffer并写buffer
1)通过系统调用mmap来获取可操作的framebuffer
fb_base = (unsigned char *)mmap(NULL , fix.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
/* get buffer */
pNextBuffer = fb_base + nNextBuffer * screen_size;
/* set buffer */
lcd_draw_screen(pNextBuffer, colors[i]);
5.APP:开始切换buffer
/* switch buffer */
var.yoffset = nNextBuffer * var.yres;
ioctl(fd_fb, FBIOPAN_DISPLAY, &var);
/android/vendor/amlogic/common/kernel/common_4.9/drivers/video/fbdev/core/fbmem.c
fb_ioctl()
--do_fb_ioctl
----fb_pan_display(info, &var);
------info->fbops->fb_pan_display(var, info) // 调用硬件相关的函数
--------writel(fb_info->fix.smem_start + offset,
host->base + host->devdata->next_buf); /* update on next VSYNC */

458

被折叠的 条评论
为什么被折叠?



