RK fb源码分析(转载)

RK fb源码分析(转)
转载地址:https://blog.csdn.net/u014770862/article/details/65442066?fps=1&locationNum=6

前言
学习,学而时习之。在工作中,利用闲暇时光简单分析下RK平台下fb源码部分,本人才疏学浅,很多地方理解的也不到位,只是简单的分析下代码流程,搞明白驱动调试过程中需要注意的地方。现将自己的一些理解与建议总结下来,如有错误之处,还望指正。

RK的LCD这块,亮点也就在于双屏异显,才开始搞驱动时,感觉这就是个高大上的东西,一脸懵逼,不知所措。随着后来慢慢深入才发现,原理和单屏也是差不多的。


分析之前,我将RK LCD这块首先分为四大块:fb、lcdc、screen、screen_type.这四部分相互依赖,首先从我们最容易入手的地方开始:rk_screen.c

 
 
 
 
  • 1

一、函数调用关系
rk_screen.c函数调用关系如下:
这里写图片描述

二、probe()分析

毫无疑问,驱动的重点就是probe()函数,驱动在匹配到compatible = “rockchip,screen”后进入probe()函数,rk_screen_probe():
在probe函数中获取”screen_prop”、”native-mode”等属性,在这里有个重要的结构体:prmry_screen会被初始化,prmry_screen 定义如下:
static struct rk_screen *prmry_screen
还有一个结构体:struct rk_screen *rk_screen,rk_screen贯串上下文,并将prmry_screen指向rk_screen,prmry_screen之所以重要,是因为之后screen_type(例如LVDS,EDP,MIPI等)需要获取screen参数,就是获取prmry_screen的值,而这里prmry_screen就是rk_screen。
进入probe函数有两个函数比较重要:rk_fb_prase_timing_dt()和rk_disp_pwr_ctr_parse_dt。
首先会根据device_node中”screen_prop”的值,来决定rk_screen的”归属”:
这里写图片描述
代码中,dts的”screen_prop”的值决定了屏参文件传递进来后赋值给了谁:prmry_screen或者extend_screen.(NOTE:只有在DUAL_LCD时,screen节点下才会有”screen_prop”属性,单屏,由LCDC部分判断”screen_prop”)
rk_fb_prase_timing_dt()
这里写图片描述
通过of_get_display_timings(np)解析device_node中的所有display_timing条目,然后调用
display_timings_get()从结构体display_timing中得到入口地址,最后调用了rk_fb_video_mode_from_timing(dt, screen)从display_timing中获取screen的详细信息,并将其赋值给rk_screen结构体(即prmry_screen).

  1. rk_disp_pwr_ctr_parse_dt()
    该函数主要是从dts中解析power control节点。其中,又引出来一个比较重要的结构体:struct rk_disp_pwr_ctr_list *pwr_ctr;该结构体也是一个双向链表。然后,初始化了一个双向链表rk_screen->pwrlist_head,最终会将pwr_ctr挂到rk_screen->pwrlist_head链表下:
    list_add_tail(&pwr_ctr->list, rk_screen->pwrlist_head);
    这里写图片描述

for_each_child_of_node(root, child)循环解析每个子节点,例如:
这里写图片描述
首先为每个子节点(如lcd_en,lcd_cs,lcd_rst等)kmalloc一段空间, 解析dts中”rockchip,power_type”的值,rockchip,power_type = GPIO,分别获取其GPIO存至各自的pwr_ctr->pwr_ctr.gpio中,然后申请GPIO。这里,还有一个值:rockchip,delay,可以控制上电时序的延时操作,这个值在后面用到时再讲。
这里写图片描述
2. rk_fb_video_mode_from_timing()
这里写图片描述
该函数获取dts中display_timing各个子节点的值,其中有我们熟悉的VBP,VFP,HBP,HFP等可变参数,最终将获取到的值写入变量screen中,这样screen就被初始化完。
至此,screen部分probe()函数完结,现在总结下:
Screen的probe()函数主要干了两件事:
解析dts中的display_timing,获取屏幕信息
解析dts中的power control,获取LCD的使能脚、片选脚、复位脚
最终,这些信息都存在了struct rk_screen *rk_screen这个结构体中,也就是prmry_screen这个结构体。那么,prmry_screen这个结构体在什么地方会用到呢?答案也是在rk_screen.c中:
这里写图片描述
调用rk_fb_get_screen()这个函数来取得screen的信息。该函数在哪被调用,后续会碰到,暂且不讨论。

以上部分,是双屏时screen部分的流程,事实上,单屏的代码更为简单。就是在probe()直接调用rk_fb_prase_timing_dt(np, rk_screen)来获取LCD屏信息,获取screen:
这里写图片描述
区别在于display_timings_get()的第二形参不同

但是,有些人又有疑问了?那双屏时会去获取power control节点的信息,单屏时为什么不用获取呢?其实也不是没有获取,只不过处理的地方不一样。双屏时,在screen部分获取power control,因为有两个LCD屏,有各自的使能脚、背光脚等等,所以引入链表保存至rk_screen结构体中,待将来使用。而单屏只有一组控制脚,只要在需要的地方获取使用就可以了。后续,只分析单屏的,理清思路即可。

最后,我们再来总结下probe()的功能:
1.如果是双屏,解析dts中screen节点下的power_ctl节点,单屏的power_ctl节点在别的地方(后续讲述)处理
2.从dts中获取LCD各个参数(VFP,VBP,HBP,HFP,W,H,CLOCK等等)
3.单屏保存至全局静态变量rk_screen,双屏时分别保存至prmry_screen和extend_screen以区别主副屏

SCREEN部分是整个fb调试过程中,需要更改参数最多的,通常LCD调试只需要调整screen的dts各个参数即可。LCD调试部分请参考另外一篇博文【Rk平台LCD调试说明】

三、struct rk_screen

struct rk_screen {
#ifdef CONFIG_DUAL_LCD
struct device *dev;
int prop;
struct list_head *pwrlist_head; //power ctl链表,保存power ctl gpio
int native_mode;
#endif
u16 type;
u16 lvds_format; //LVDS数据格式
u16 face; //display out face,18bit,24bit
u16 color_mode;
u8 lcdc_id; //dual lcd时用于区分LCD
u8 screen_id;

struct fb_videomode mode;   //important
u32 post_dsp_stx;
u32 post_dsp_sty;
u32 post_xsize;
u32 post_ysize;
u16 x_mirror;
u16 y_mirror;
int interlace;
int pixelrepeat; //For 480i/576i format, pixel is repeated twice.
u16 width;
u16 height;
u8  ft;
int *dsp_lut;
int *cabc_lut;
int *cabc_gamma_base;

#if defined(CONFIG_MFD_RK616) || defined(CONFIG_LCDC_RK312X)
u32 pll_cfg_val; //bellow are for jettaB
u32 frac;
u16 scl_vst;
u16 scl_hst;
u16 vif_vst;
u16 vif_hst;
#endif
u8 hdmi_resolution;
u8 mcu_wrperiod;
u8 mcu_usefmk;
u8 mcu_frmrate;

u8 pin_hsync;
u8 pin_vsync;
u8 pin_den;
u8 pin_dclk;

/* Swap rule */
u8 swap_gb;
u8 swap_rg;
u8 swap_rb;
u8 swap_delta;
u8 swap_dumy;

#if defined(CONFIG_MIPI_DSI)
/* MIPI DSI */
u8 dsi_lane;
u8 dsi_video_mode;
u32 hs_tx_clk;
#endif

int xpos;  //horizontal display start position on the sceen ,then can be changed by application
int ypos;
int xsize; //horizontal and vertical display size on he screen,they can be changed by application
int ysize;
struct overscan overscan;
struct rk_screen *ext_screen;
/* Operation function*/
int (*init)(void);
int (*standby)(u8 enable);
int (*refresh)(u8 arg);
int (*scandir)(u16 dir);
int (*disparea)(u8 area);
int (*sscreen_get)(struct rk_screen *screen, u8 resolution);
int (*sscreen_set)(struct rk_screen *screen, bool type);// 1: use scaler 0:bypass

};

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;
};

SCREEN主要填充rk_screen结构体的各个字段,这个结构体将由SCREEN_TYPE和fb来获取使用。

后记

<还记得初学linux驱动时,老版本的内核大量充斥于arch/arm/mach-xxxx下的board文件,相对于现在的dts机制,此时我们是幸福的,也是悲哀的。”我们不是配置工程师!”>

Email:hellobirthdayzhao@gmail.com
————————————————
版权声明:本文为CSDN博主「HelloBirthday」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u014770862/article/details/65442066

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值