关于framebuffer(帧缓冲设备)的架构这里就不多罗嗦了,不会的可以去网上百度,这个很多的 1.代码架构 drivers/video/rockchip/transmitter/ |_ rk32_mipi_dsi.c /* MIPI 驱动主体文件 */ |_ rk32_mipi_dsi.h /* 寄存器以及结构体的定义 */ |_ mipi_dsi.c /* 封装的函数指针接口函数, 供 lcd_mipi.c 调用, 函数的具体实现 在 rk32_mipi_dsi.c 中 */ |_ mipi_dsi.h /* mipi 协议相关的宏定义以及函数指针结构体定义 */ drivers/video/rockchip/screen/ |_ lcd_mipi.c /* 屏参 dtsi 文件的解析 */ 由于rk3128平台使用了3.10以后的内核,所以采用了dts的形式来管理驱动,刚开始的时候会觉得不顺手,用多了还是相当方便的 2.代码架构图 无论是正常的开机流程以及休眠唤醒的流程,显示相关的模块都是要和 fb 以及 vop(lcdc)交互的。rk32_dsi_enable()和 rk32_dsi_disable()函数作为 MIPI 和 vop 之 间 的 交 互 的 总 入 口 函 数 。 另 外 还 有 一 对 rk32_mipi_power_up_DDR() 和 rk32_mipi_power_down_DDR()函数是单独供 ddr 变频的时候使用, 正常的开机以及休 眠唤醒流程不走这两个函数。开机流程图如下图所示: dsi_init() : 该函数主要实现 mipi host 和 phy 的上电以及初始化工作。 rk_mipi_screen_standby() : 屏的供电以及屏的初始化工作(屏初始化命令的发送) dsi_enable_video_mode() : command 模式和 video 模式的切换,发送命令一般是在 command 模式下,正常数据传输是在 video 模下。 dsi_is_enable() : mipi host 的关闭与开启。 3.移植过程 a.配置menuconfig b.添加关于lcd的dtsi文件(屏参文件) 在kernel/arch/arm/boot/dts中随便找一个其他mipi屏的dtsi文件参考其写法(3.10内核的新变化,也可以不用) 屏参文件包含四个部分:mipi host 配置、屏电源控制配置、屏初始化序列和屏参。 b.1 mipi host的配置 disp_mipi_init: mipi_dsi_init{ compatible = "rockchip,mipi_dsi_init"; rockchip,screen_init = <1>; rockchip,dsi_lane = <4>; rockchip,dsi_hs_clk = <310>; rockchip,mipi_dsi_num = <1>; }; screen_init : 表示屏是否需要初始化,如果需要则置为 1. dsi_lane : mipi 数据传输需要几条数据 lane,这个一般根据原理图和 mipi 屏的规格书来配置。这个指的是每个 mipi 的数据 lane 数。譬如如果是双 mipi,每个 mipi 为 4 lane。那么此处仍然设置为 4。 dsi_hs_clk : 屏 ddr clk,表示一条数据 lane 的传输速率,单位为 Mbits/s。有个大概的计算公式:100+H_total*V_total*fps*3*8/lanes。H_total,V_total 包括 active,bp,fp 和 sync-len 的和;fps 为帧率,刚调试一款屏时,fps 为 50 多帧就好,然后慢慢抬高;3 为一个像素点为 rgb 3 个字节;8 为 8 bits;lanes 为(dsi_lane*mipi_dsi_num) ;100 为实际的结果要比理论值大 100M 左右。上面计算得到的值只是大概值并非精确的值,但是对于一般的屏都适用,对于部分屏需要微调该值。 mipi_dsi_num : 单 mipi 还是双 mipi,也是根据原理图和屏幕规格书来配置的。如果是双 mipi 则置为 2。单 MIPI 的屏 SDK 代码默认设置的是 MIPI_TX,所以单 MIPI 是接MIPI_TX 这一路,双 MIPI 接法:MIPI_TX 这路接左屏,MIPI_TX/RX 这一路接右屏。 b.2 屏电源的配置 &lcdc { status = "okay"; backlight = <&backlight>; pinctrl-names = "default", "gpio"; pinctrl-0 = <&lcdc0_lcdc>; pinctrl-1 = <&lcdc0_gpio>; rockchip,fb-win-map = ; power_ctr: power_ctr { rockchip,debug = <0>; lcd_cs: lcd_cs { rockchip,power_type = ; gpios = <&gpio1 GPIO_B4 GPIO_ACTIVE_HIGH>; rockchip,delay = <10>; }; lcd_rst:lcd_rst{ rockchip,power_type = ; gpios = <&gpio0 GPIO_D0 GPIO_ACTIVE_LOW>; rockchip,delay = <20>; }; lcd_en:lcd_en { rockchip,power_type = ; gpios = <&gpio0 GPIO_B0 GPIO_ACTIVE_LOW>; rockchip,delay = <20>; }; }; }; 电源配置的 gpios 需要根据原理图来配置 lcd_en 等各对应哪路 gpio b.3 屏的初始化序列 disp_mipi_init_cmds: screen-on-cmds { compatible = "rockchip,screen-on-cmds"; rockchip,cmd_debug = <1>; rockchip,on-cmds1 { compatible = "rockchip,on-cmds"; rockchip,cmd_type = ; rockchip,dsi_id = <0>; rockchip,cmd = <0x15 0x80 0xAC>; rockchip,cmd_delay = <0>; }; rockchip,on-cmds2 { compatible = "rockchip,on-cmds"; rockchip,cmd_type = ; rockchip,dsi_id = <0>; rockchip,cmd = <0x15 0x81 0xB8>; rockchip,cmd_delay = <0>; }; 。 。 。 rockchip,on-cmds8 { compatible = "rockchip,on-cmds"; rockchip,cmd_type = ; rockchip,dsi_id = <0>; rockchip,cmd = <0x05 0x11>; rockchip,cmd_delay = <10>; }; rockchip,on-cmds9 { compatible = "rockchip,on-cmds"; rockchip,cmd_type = ; rockchip,dsi_id = <0>; rockchip,cmd = <0x05 0x29>; rockchip,cmd_delay = <10>; }; }; cmd_type : 命令是在 low power(LPDT)还是 high speed(HSDT)下发送。 dsi_id : 命令通过哪个 mipi 发送。0 表示在 mipi0 发送,1 表示在 mipi1 发送,2 表示双 mipi 同时发送。因为很少出现单独使用 mipi1 的情况,所以对于单 mipi,这个值默认是 0;对于双 mipi,这个值 是 2。 cmd : 初始化命令。格式:命令类型(如 0x05/0x15/0x39)+命令+参数。具体细节见 mipi 协议文档。 注:最后两条命令是mipi协议规定的,一定要加的0x11: Exit_sleep_mode,0x29:Set_display_on 表示告诉显示设备(屏)可以开始显示图像数据了。 b.4 屏的参数 disp_timings: display-timings { native-mode = <&timing0>; compatible = "rockchip,display-timings"; timing0: timing0 { screen-type = ; lvds-format = ; out-face = ; clock-frequency = <51668640>; hactive = <1024>; vactive = <600>; hback-porch = <160>; hfront-porch = <160>; vback-porch = <23>; vfront-porch = <12>; hsync-len = <10>; vsync-len = <1>; hsync-active = <0>; vsync-active = <0>; de-active = <0>; pixelclk-active = <0>; swap-rb = <0>; swap-rg = <0>; swap-gb = <0>; }; }; screen-type : 屏幕类型,对于 mipi 屏来说有两种选择:单 mipi(SCREEN_MIPI);双 mipi(SCREEN_DUAL_MIPI); lvds-format : lvds 数据格式。对于 mipi 来说是无效参数,不用配置 out-face : 屏幕接线格式 上述三个参数的取值在 include/dt-bindings/rkfb/rk_fb.h 中定义。 clock-frequency : dclk 频率,单位为 HZ,一般屏的规格书中有,如果没有可以通过公式计算:H*V(包括同步信号)*fps Hactive : 水平有效像素 Vactive : 垂直有效像素 hback-porch/hfront-porch/hsync-len : 水平同步信号 vback-porch/vfront-porch/vsync-len : 垂直同步信号 hsync-active 、 vsync-active 、 de-active 、 pixelclk-active :分 别 为 hync,vsync,DEN,dclk 的极性控制。置 1 将对极性进行翻转。 swap-rb、swap-rg、swap-gb : 设 1 将对对应的颜色进行翻转。 b.5 板级文件配置 屏参文件配置好以后,需要在板级文件中包含这个屏参文件: #include "lcd-xxxxx-mipi.dtsi" 因为在芯片 dtsi 中默认是关闭的,所以需要在板级板级文件中开启 mipi host &dsihost0 { status = "okay"; }; 因为是单mipi,只要配置一个就可以了 4.调试遇到的问题与总结 1.开机后lcd屏闪 问题定位:修改代码,提高dclk到一个较高的频率; (1)若提高pclk后,屏闪现象消失 现象分析:说明此现象是刷新频率较低引起的; 解决方法:将dclk提高到一个合适的较高频率; (2) 若提高dclk后,屏闪现象仍然存在 现象分析:说明此现象不是刷新频率较低引起的,这种情况是LCD极性设置不正确造成的; 解决方法:在dtsi文件中修改LCD的极性; 2.休眠唤醒,只有背光亮,屏不亮 问题定位:查看唤醒时的log,代码跑崩了,重新上电,屏是可以起来的,可能是唤醒屏时,en,rst的配置有问题 自己其实当时用了一个很low的方法来获取rst,en脚的管脚号,在lcd_mipi.c中通过解析dtsi的那个文件的那个函数,获得了gpio号, 然后在用gpio_direction_output的方法设置管脚号(这也是我刚开始不习惯的原因),后来在rk_fb.c的文件中发现有现成的接口,做了修改,代码倒是不崩溃了,但是屏还是不亮,通过log发现休眠唤醒时,居然没有走我的初始化序列,一看,发现少了0x11和0x29两条指令,加上后,问题解决 解决方法:修改获得pin脚号的方法,加上0x11和0x29命令
原作者:君醉为红颜
|