在imx6ull这块soc上,通过厂家提供的设备树将显示控制器注册为了platform_device
对于lcd显示屏接口,其也是MIPI接口规定中的一类
MIPI 表示Mobile Industry Processor Interface,即移动产业处理器接口。是MIPI联盟发起的为移动应用处理器制定的开放标准和一个规范。主要是手机内部的接口(摄像头、显示屏接口、射频/基带接口)等标准化,从而减少手机内部接口的复杂程度及增加设计的灵活性。
对于LCD,MIPI接口可以分为3类:
- MIPI-DBI (Display Bus Interface)
- 之所以叫这个名字,是因为mcu碍于性能原因,一般都使用外部显示模块(屏幕刷新单元+显存),其负责使用一组总线分时发送要修改的显存地址和目标像素值
- 既然是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)
- 之所以叫这个名字,是因为,mpu片上一般都内置了显示控制器(总线外设),其能在配置好后自动从DDR中通过总线地址读取DDR中的显存数据,然后自动在屏幕上进行刷新
- 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
mxsfb_drv.c
根据设备树,lcdif的驱动是被注册为了platform_driver

对于imx6ull这款不带显卡的芯片,其走的还是注册fb的那套流程
于是就查看
mxsfb.c->mxsfb_probe
第一段

这部分代码主要用于从设备树中的设备提取所需要的资源
2211行,从设备树中读取寄存器地址资源
2217行,申请的变量则是mx系列专用的mxsfb_info(主要保存硬件信息),后面在注册fb的时候会被转换为fb_info
第二段

2223行,申请了一个fb_info
2229行,2230行,把fb_info和mxsfb_info做一个双向链接,方便后面二者做转换随时可以找到
2232行,直接申请并且注册一个VSYNC中断函数,这个中断一般情况下是不开的,是在等待垂直同步的时候才会开
写 fb 的进程(通过驱动)在需要切换帧时,主动开启 VSYNC 中断并睡眠等待;硬件在 VSYNC 到来时触发中断,中断处理函数关闭该中断并唤醒进程;进程被唤醒后,才去执行 buffer 翻转(提交下一帧显示),从而保证切换发生在帧边界,避免撕裂
2241行,将当前显示控制器的寄存器地址映射到虚拟地址,以后cpu访问该虚拟地址空间就是访问的该寄存器的地址空间,操作具体寄存器带上偏移量即可
第三段

2249行,把前面申请的mxsfb_info设置为当前设备树设备对应device的私有数据drv_data

2253行,拿到pix时钟(即Pixel Clock)对象
这是给显示控制器的单独时钟,其负责驱动显示面板的像素时序,决定显示控制器取数据的周期大小,结合timing的参数可以计算出刷新率
后面会被驱动set_rate为对应timing中的clock-frequency
2260行,这个axi实际上是APB时钟对象,用于总线上数据的访问传输,默认都是开启的
2268行,这个disp_axi时钟只是一个虚拟时钟,有没有都不影响
对于获取到的时钟对象,会抽象成如下的结构体,这些由soc厂商提前往clk子系统进行了实现

第四段

2276行,从设备树获取外部稳压器对象,即有些lcd屏幕供电是外接了电源管理芯片的,有这个之后就可以通过软件控制该芯片供电与否
2282行,则是为了兼容控制台终端的颜色显示,因为传统的文本控制台只需要 16 种基础颜色,设置后会被setcolreg进行逻辑填充,将这16种颜色序号映射为真实使用的RGB888或者RGB565
2288行,初始化了一个 LCD 控制器能支持的多种分辨率和刷新率组合(每个组合在内核里叫一个 struct fb_videomode)的链表
第五段

2292行,通过mx自有驱动和内部从设备树获取的各种信息,对其fb_info进行填充,这里需要展开讲讲,先略过
2298行,获取设备树中配置的display节点句柄,display节点是nxp公司自己设计的,所以该函数里面会通过引用获取到节点display0

2306行,如果没有显示器display节点,就将引脚保持当前节点默认的复用
2316行,根据前面获取到的display节点,以及2292行对fb_info的初始化配置,在函数内部读取display配置(bpps,bus-width等)和timings时序信息,对fb_info中的参数进行补全配置,同时设置lcdif的寄存器,mxsfb_init_fbinfo内已经分配好了固定大小的32M的frame_buffer显存,所以这里面也会往对应寄存器写上该frame_buffer的物理地址
2317行,设置显示控制器lcdif中的使能位
2321行,将当前fb_info直接注册进framebuffer子系统
2327行,注册一个控制叠层显示的fb
mxsfb_init_fbinfo
这部分代码主要是初始化一下fb_info结构体
第一段

1420行-1427行,都是固定的mx显示控制器的配置
1429行,解析设备树,填充fb_info里的信息,包括了对display和display-timings子节点的解析
1438行,根据前面解析设备树得到的fb_info->modelist,选取其中的第一个mode,并且将其从fb_videomode 格式转成 fb_var_screeninfo 格式,填进 var。
fb_videomode和fb_var_screeninfo的关系是可以转换的
fb_videomode是一个候选显示模式,其内部不含像素格式等,fb_var_screeninfo是当前生效的显示参数,其包含像素格式和颜色位域
第二段

1445行-1453行,配置fb_var_screeninfo并且 校验 var 里的参数是否合法,修正不合法或未填的字段
1455行,计算一行像素占多少字节
1457行,固定分配 32MB framebuffer 内存
1460行,真正分配framebuffer 内存的地方
- 把物理地址写进 ``fb_info->fix.smem_start`
- 把内核虚拟地址写进
fb_info->screen_base
1463行,如果之前已经初始化过lcdif(比如从 bootloader 移交过来),尝试将寄存器恢复原有配置,同时将整个显存数据清零,等待后面mxsfb_set_par()中重新按照设备树的配置写寄存器