Linux内核LCD驱动分析与换屏方法(Tiny4412)

Posted DS小龙哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux内核LCD驱动分析与换屏方法(Tiny4412)相关的知识,希望对你有一定的参考价值。

Linux内核中换屏技术​

21.5.1 u-boot中的参数bootargs实现换屏

在uboot中有一个 bootargs环境变量,这个参数就是传递数据给内核的。

对tiny4412提供的内核,可以通过修改 bootargs 实现驱动不同的LCD屏。


21.5.2 分析bootargs中的lcd参数

再启动uboot的时候会有如下的环境参数:

bootargs=noinitrd root=/dev/nfs nfsroot=192.168.10.106:/home/xyd/rootfs/

ip=192.168.10.123:192.168.10.106:192.168.10.1:255.255.255.0::eth0:off init=/linuxrc console=ttySAC0 coherent_pool=2M lcd=S702


每个参数之间都是空格分开。

可以看到上面传递了2,启动内核之后就可以驱动S702屏。

在内核启动阶段,内核会根据lcd=S720这个信息,在注册平台设备/驱动前LCD平台数据修改了。

21.5.3 分析在注册平台设备/驱动前修改lcd平台数据过程

首先从板级文件Mach-tiny4412.c中开始看。在这个文件中我们会看到一个机器初始化函数

(1) 机器初始化函数中多平台设备注册代码段

代码段如下,在02299行可以看到:

static void __init smdk4x12_machine_init(void)

……

//注册多平台设备

platform_add_devices(smdk4x12_devices, //包含LCD平台设备结构指针

ARRAY_SIZE(smdk4x12_devices));//数组元素个数,即平台设备个数

……


注册平台设备函数原型:

int platform_add_devices(struct platform_device **devs, int num)


LCD平台设备层结构指针就是存放在 smdk4x12_devices的,以上函数注册包含LCD平台设备。所以,我们可以推出修改平台数据的地方应该在 platform_add_devices 函数前


问题:在哪里修改lcd平台数据?


在platform_add_devices之前,有和lcd相关代码,下面的调用是在有触摸屏的时候才调用。我们只是把它作为例子来找到能识别s702屏的地方。

后边会讲到真正调用识别S702屏的地方。

代码如下:

static void __init smdk4x12_machine_init(void)

……

#ifdef CONFIG_TOUCHSCREEN_FT5X0X//配置FT5X0X触摸屏的宏

struct s3cfb_lcd *lcd = tiny4412_get_lcd();

ft5x0x_pdata.screen_max_x = lcd->width;

ft5x0x_pdata.screen_max_y = lcd->height;

#endif

……

platform_add_devices(smdk4x12_devices, ARRAY_SIZE(smdk4x12_devices));

……



其实真正的获得lcd参数结构是在tiny4412_fb_init_pdata函数里边调用,后面会有分析。


问题:现在我们分析如何通过bootargc传参获得lcd平台数据?


(2) 机器初始化函数中调用一个和lcd相关的tiny4412_get_lcd函数

SI里边调转,此函数在Tiny4412-lcds.c (linux-3.5\\arch\\arm\\mach-exynos)文件下。

代码如下:

struct s3cfb_lcd *tiny4412_get_lcd(void)

return tiny4412_lcd_config[lcd_idx].lcd;


这个函数只返回一个数组元素,此数组定义和初始化如下:

在文件Tiny4412-lcds.c (linux-3.5\\arch\\arm\\mach-exynos) 中。

代码如下:是一个结构体数组。

static struct

char *name;

struct s3cfb_lcd *lcd;

int ctp;

tiny4412_lcd_config[] =

"HD700",&wxga_hd700, 1 ,

"S70",&wvga_s70, 1 ,

"S702",&wvga_s70, 3 ,

"W50",&wvga_w50, 0 ,

"W101",&wsvga_w101, 1 ,

"A97",&xga_a97, 0 ,

"LQ150",&xga_lq150, 1 ,

"L80",&vga_l80, 1 ,

"HD101",&wxga_hd101, 1 ,

"BP101",&wxga_bp101, 1 ,

"HDM",&hdmi_def, 0 ,/* Pls keep it at last */

;



所以我们就要关注lcd_idx值,在哪里设置这个值。

SI跳转得到如下:

static int lcd_idx = 0; //在本文件中定义为静态变量


(3) 在哪里得到lcd_idx的值

我们采用搜索的方式查找lcd_idx,可以找到以下:

Tiny4412-lcds.c (arch\\arm\\mach-exynos):lcd_idx = i;


进入查看搜索语句所在代码:

static int __inittiny4412_setup_lcd(char *str)

int i;

……

/* 这里想通过名字查找对应的lcd配置参数,返回下标号lcd_idx */

for (i = 0; i < ARRAY_SIZE(tiny4412_lcd_config); i++)

if (!strcascmp(tiny4412_lcd_config[i].name, str))

lcd_idx = i;

break;

__ret:

printk("TINY4412: %s selected\\n", tiny4412_lcd_config[lcd_idx].name);

return 0;


这个是static静态函数,在本文件中有效。

这里我们可以知道tiny4412_lcd_config是一个数组,它就是存放所有支持的LCD屏信息。 通过比较数组成员nametiny4412_setup_lcd参数str决定lcd_idx的值。​

到这里就有疑问了:tiny4412_setup_lcd在哪里被调用?​

(4) 补充知识:字符串比较函数。

int strcasecmp(const char *s1, const char *s2)

int c1, c2;


do

c1 = tolower(*s1++); //转换小写

c2 = tolower(*s2++); //转换小写

while (c1 == c2 && c1 != 0);

return c1 - c2;

这个函数是不区分大小写比较


21.5.4 几个重要结构

(1) 结构定义即初始化

这个结构体是当前板子所支持的lcd屏列表。

/* 定义lcd屏支持列表 */

static struct

char *name;

struct s3cfb_lcd *lcd;

int ctp;

tiny4412_lcd_config[] =

"HD700",&wxga_hd700, 1 ,

"S70",&wvga_s70, 1 ,//我们当前板子上所使用的屏

"W50",&wvga_w50, 0 ,

"W101",&wsvga_w101, 1 ,

"A97",&xga_a97, 0 ,

"HDM",&hdmi_def, 0 ,/* Pls keep it at last */

;


里边struct s3cfb_lcd *lcd;结构成员是存放lcd屏的工作时序参数。

(2)结构体定义

如下:这个结构已经包含LCD驱动所需要的平台数据信息。

/*

* @width:horizontal resolution---水平分辨率

* @height:vertical resolution---垂直分辨率

* @p_width:width of lcd in mm---屏物理尺寸(宽,mm单位)

* @p_height:height of lcd in mm---屏物理尺寸(高,mm单位)

* @bpp:bits per pixel

* @freq:vframe frequency---刷屏频率

* @timing:timing values--时序参数

* @polarity:polarity settings---极性参数

*/

struct s3cfb_lcd

intwidth;

intheight;

intp_width;

intp_height;

intbpp;

intfreq;

structs3cfb_lcd_timing timing;

structs3cfb_lcd_polarity polarity;

;


(3) s3cfb_lcd_timing屏的时序参数结构

/*

* @h_fp:horizontal front porch

* @h_bp:horizontal back porch

* @h_sw:horizontal sync width

* @v_fp:vertical front porch

* @v_fpe:vertical front porch for even field

* @v_bp:vertical back porch

* @v_bpe:vertical back porch for even field

*/

struct s3cfb_lcd_timing

inth_fp;

inth_bp;

inth_sw;

intv_fp;

intv_fpe;

intv_bp;

intv_bpe;

intv_sw;

;



(4) 屏的时序极性配置

/*

* @rise_vclk:if 1, video data is fetched at rising edge

* @inv_hsync:if HSYNC polarity is inversed

* @inv_vsync:if VSYNC polarity is inversed

* @inv_vden:if VDEN polarity is inversed

*/

struct s3cfb_lcd_polarity

intrise_vclk;

intinv_hsync;

intinv_vsync;

intinv_vden;

;



21.5.5 以bootargc传入lcd=S70为例子填充s3cfb_lcd结构

定义struct s3cfb_lcd结构变量wvga_s70 ,并初始化屏参数;

在文件Tiny4412-lcds.c (arch\\arm\\Mach-exynos)下实现。

//以下信息是根据LCD屏的手册得到的

static struct s3cfb_lcdwvga_s70=

.width = 800,

.height = 480,

.p_width = 155,

.p_height = 93,

.bpp = 24,

.freq = 63,

以上是关于Linux内核LCD驱动分析与换屏方法(Tiny4412)的主要内容,如果未能解决你的问题,请参考以下文章

LCD驱动端与设备端名称匹配过程分析(Tiny4412)

4 linux lcd驱动框架分析

LCD驱动源码分析(s3cfb.c)

Linux 帧缓冲子系统详解:LCD介绍framebuffer驱动框架LCD驱动源码分析

分析内核自带的LCD驱动程序\_基于IMX6ULL

iTOP-4412开发板驱动lcd显卡以及linux开机log的修改方法

(c)2006-2024 SYSTEM All Rights Reserved IT常识