您的位置:首页 > 运维架构 > Linux

移植较新(Linux3.19)内核至mini2440开发板(二)——LCD的移植

2015-04-26 18:32 393 查看
在这篇文章中我们将移植LCD驱动,因为博主的屏是P35,所有以下的讲解主要建立在P35屏的基础上,其他的屏理论上移植过程也是一样的,只需要按照数据手册对个别参数进行修改即可。1在Linux3.19内核中,已经对s3c2440的lcd控制器进行了很完善的支持,我们在移植时只需要对相关的结构体赋值,然后调用初始化函数进行初始化即可。首先,针对不同的lcd屏,主要的区别有如下几个参数:VBP(vertical back porch):表示在一帧图像开始时,垂直同步信号以后的无效的行数,对应驱动中的upper_margin;  VFB(vertical front porch):表示在一帧图像结束后,垂直同步信号以前的无效的行数,对应驱动中的lower_margin;  VSPW(vertical sync pulse width):表示垂直同步脉冲的宽度,用行数计算,对应驱动中的vsync_len;  HBP(horizontal back porch):表示从水平同步信号开始到一行的有效数据开始之间的VCLK的个数,对应驱动中的left_margin;  HFP(horizontal front porth):表示一行的有效数据结束到下一个水平同步信号开始之间的VCLK的个数,对应驱动中的right_margin;HSPW(horizontal sync pulse width):表示水平同步信号的宽度,用VCLK计算,对应驱动中的hsync_len;具体可参考这篇博客:http://blog.csdn.net/l627859442/article/details/7699560从数据手册中我们可以得到这些数据的典型值。首先,我们可以可为这些数据定义如下宏,并计算出pixclock的值
/*
* This macro simplifies the table bellow
*/
#define _LCD_DECLARE(_clock,_xres,margin_left,margin_right,hsync, \
_yres,margin_top,margin_bottom,vsync, refresh) \
.width = _xres, \
.xres = _xres, \
.height = _yres, \
.yres = _yres, \
.left_margin	= margin_left,	\
.right_margin	= margin_right,	\
.upper_margin	= margin_top,	\
.lower_margin	= margin_bottom,	\
.hsync_len	= hsync,	\
.vsync_len	= vsync,	\
.pixclock	= ((_clock*100000000000LL) /	\
((refresh) * \
(hsync + margin_left + _xres + margin_right) * \
(vsync + margin_top + _yres + margin_bottom))), \
.bpp		= 16,\
.type		= (S3C2410_LCDCON1_TFT16BPP |\
S3C2410_LCDCON1_TFT)
然后我们需要根据屏的数据手册增加如下函数:
static struct s3c2410fb_display mini2440_lcd_cfg[] __initdata = {
/* mini2440 + 3.5" TFT (LCD-P35,  ZQ3506_V0  + touchscreen*/
[0] = {
_LCD_DECLARE(
/* clock */
6,
/* xres, margin_right, margin_left, hsync */
320, 2, 8, 1,
/* yres, margin_top, margin_bottom, vsync */
240, 12, 4, 1,
/* refresh rate */
60),
.lcdcon5	= (S3C2410_LCDCON5_FRM565 |
S3C2410_LCDCON5_INVVCLK |
S3C2410_LCDCON5_INVVFRAME |
S3C2410_LCDCON5_INVVLINE |
S3C2410_LCDCON5_HWSWP ),
},
};
其中_LCD_DECLARE宏定义中的相关数据来自数据手册给的典型值,然后进行微调试凑所得。其中,lcdcon5寄存器的设置可参考如下说明:LCDCON5寄存器:VSTATUS :当前VSYNC信号扫描状态,指明当前VSYNC同步信号处于何种扫描阶段。HSTATUS :当前HSYNC信号扫描状态,指明当前HSYNC同步信号处于何种扫描阶段。BPP24BL :设定24bpp显示模式时,视频资料在显示缓冲区中的排列顺序(即低位有效还是高位有效)。对于16bpp的 64K色显示模式,该设置位无意义。FRM565 :对于16bpp显示模式,有2中形式,一种是RGB=5:5:5:1,另一种是5:6:5。后一 种模式最为常用,它的含义是表示64K种色彩的16bit RGB资料中,红色(R)占了5bit,绿色(G)占了6bit,兰色(B)占了5bit。INVVCLK 、INVLINE 、INVFRAME 、INVVD :通过前面提到的‘Figure 15-6’的时序图,我们知道,CPU的LCD控制器输出的时序默认是正脉冲,而LCD需要VSYNC(VFRAME)、VLINE(HSYNC)均为负脉冲,因此 INVLINE 和 INVFRAME 必须设为“1 ”,即选择反相输出。 INVVDEN , INVPWREN , INVLEND 的功能同前面的类似。PWREN :LCD电源使能控制。在CPU LCD控制器的输出信号中,有一个电源使能管脚LCD_PWREN,用来做为LCD屏电源的开关信号。ENLEND :对普通的TFT屏无效,可以不考虑。INVVDEN、INVPWREN、INVLEND:是否翻转这些信号,一般为正常,不需要翻转。BSWP 、HWSWP : 为字节(Byte)或半字(Half-Word)交换使能。由于不同的GUI对FrameBuffer(显示缓冲区)的管理不同,必要时需要通过调整 BSWP 和 HWSWP来适应GUI。之后,我们需要根据具体的硬件连接对连接到lcd的相关的管脚进行复用功能的设置,具体连接方式可参考开发板的原理图,代码如下:
/* todo - put into gpio header */

#define S3C2410_GPCCON_MASK(x)	(3 << ((x) * 2))
#define S3C2410_GPDCON_MASK(x)	(3 << ((x) * 2))

static struct s3c2410fb_mach_info mini2440_fb_info __initdata = {
.displays	 = &mini2440_lcd_cfg[0], /* not constant! see init */
.num_displays	 = 1,
.default_display = 0,

/* Enable VD[2..7], VD[10..15], VD[18..23] and VCLK, syncs, VDEN
* and disable the pull down resistors on pins we are using for LCD
* data. */

.gpcup		= (0xf << 1) | (0x3f << 10),

.gpccon		= (S3C2410_GPC1_VCLK   | S3C2410_GPC2_VLINE |
S3C2410_GPC3_VFRAME | S3C2410_GPC4_VM |
S3C2410_GPC10_VD2   | S3C2410_GPC11_VD3 |
S3C2410_GPC12_VD4   | S3C2410_GPC13_VD5 |
S3C2410_GPC14_VD6   | S3C2410_GPC15_VD7),

.gpccon_mask	= (S3C2410_GPCCON_MASK(1)  | S3C2410_GPCCON_MASK(2)  |
S3C2410_GPCCON_MASK(3)  | S3C2410_GPCCON_MASK(4)  |
S3C2410_GPCCON_MASK(10) | S3C2410_GPCCON_MASK(11) |
S3C2410_GPCCON_MASK(12) | S3C2410_GPCCON_MASK(13) |
S3C2410_GPCCON_MASK(14) | S3C2410_GPCCON_MASK(15)),

.gpdup		= (0x3f << 2) | (0x3f << 10),

.gpdcon		= (S3C2410_GPD2_VD10  | S3C2410_GPD3_VD11 |
S3C2410_GPD4_VD12  | S3C2410_GPD5_VD13 |
S3C2410_GPD6_VD14  | S3C2410_GPD7_VD15 |
S3C2410_GPD10_VD18 | S3C2410_GPD11_VD19 |
S3C2410_GPD12_VD20 | S3C2410_GPD13_VD21 |
S3C2410_GPD14_VD22 | S3C2410_GPD15_VD23),

.gpdcon_mask	= (S3C2410_GPDCON_MASK(2)  | S3C2410_GPDCON_MASK(3) |
S3C2410_GPDCON_MASK(4)  | S3C2410_GPDCON_MASK(5) |
S3C2410_GPDCON_MASK(6)  | S3C2410_GPDCON_MASK(7) |
S3C2410_GPDCON_MASK(10) | S3C2410_GPDCON_MASK(11)|
S3C2410_GPDCON_MASK(12) | S3C2410_GPDCON_MASK(13)|
S3C2410_GPDCON_MASK(14) | S3C2410_GPDCON_MASK(15)),
};
以上已经完成了对lcd的信息配置,然后增加以下函数,以选择我们刚添加的那个lcd配置:
<pre name="code" class="cpp">/*
* mini2440_features string
*
* t = Touchscreen present
* c = camera [TODO]
* 0-9 LCD configuration
*
*/
static char mini2440_features_str[12] __initdata = "0t";

static int __init mini2440_features_setup(char *str)
{
if (str)
strlcpy(mini2440_features_str, str, sizeof(mini2440_features_str));
return 1;
}
__setup("mini2440=", mini2440_features_setup);

#define FEATURE_SCREEN (1 << 0)
#define FEATURE_BACKLIGHT (1 << 1)
#define FEATURE_TOUCH (1 << 2)
#define FEATURE_CAMERA (1 << 3)

struct mini2440_features_t {
<span style="white-space:pre">	</span>int count;
<span style="white-space:pre">	</span>int done;
<span style="white-space:pre">	</span>int lcd_index;
<span style="white-space:pre">	</span>struct platform_device *optional[8];
};

static void __init mini2440_parse_features(
<span style="white-space:pre">		</span>struct mini2440_features_t * features,
<span style="white-space:pre">		</span>const char * features_str )
{
<span style="white-space:pre">	</span>const char * fp = features_str;

<span style="white-space:pre">	</span>features->count = 0;
<span style="white-space:pre">	</span>features->done = 0;
<span style="white-space:pre">	</span>features->lcd_index = -1;

<span style="white-space:pre">	</span>while (*fp) {
<span style="white-space:pre">		</span>char f = *fp++;

<span style="white-space:pre">		</span>switch (f) {
<span style="white-space:pre">		</span>case '0'...'9':<span style="white-space:pre">	</span>/* tft screen */
<span style="white-space:pre">			</span>if (features->done & FEATURE_SCREEN) {
<span style="white-space:pre">				</span>printk(KERN_INFO "MINI2440: '%c' ignored, "
<span style="white-space:pre">					</span>"screen type already set\n", f);
<span style="white-space:pre">			</span>} else {
<span style="white-space:pre">				</span>int li = f - '0';
<span style="white-space:pre">				</span>if (li >= ARRAY_SIZE(mini2440_lcd_cfg))
<span style="white-space:pre">					</span>printk(KERN_INFO "MINI2440: "
<span style="white-space:pre">						</span>"'%c' out of range LCD mode\n", f);
<span style="white-space:pre">				</span>else {
<span style="white-space:pre">					</span>features->optional[features->count++] =
<span style="white-space:pre">							</span>&s3c_device_lcd;
<span style="white-space:pre">					</span>features->lcd_index = li;
<span style="white-space:pre">				</span>}
<span style="white-space:pre">			</span>}
<span style="white-space:pre">			</span>features->done |= FEATURE_SCREEN;
<span style="white-space:pre">			</span>break;
<span style="white-space:pre">		</span>/*case 'b':
<span style="white-space:pre">			</span>if (features->done & FEATURE_BACKLIGHT)
<span style="white-space:pre">				</span>printk(KERN_INFO "MINI2440: '%c' ignored, "
<span style="white-space:pre">					</span>"backlight already set\n", f);
<span style="white-space:pre">			</span>else {
<span style="white-space:pre">				</span>features->optional[features->count++] =
<span style="white-space:pre">						</span>&mini2440_led_backlight;
<span style="white-space:pre">			</span>}
<span style="white-space:pre">			</span>features->done |= FEATURE_BACKLIGHT;
<span style="white-space:pre">			</span>break;<span style="font-family: Arial, Helvetica, sans-serif;">*/</span>
<pre name="code" class="cpp"><span style="white-space:pre">		</span>case 't':
<span style="white-space:pre">			</span>printk(KERN_INFO "MINI2440: '%c' ignored, "
<span style="white-space:pre">				</span>"touchscreen not compiled in\n", f);
<span style="white-space:pre">			</span>break;
<span style="white-space:pre">		</span>case 'c':
<span style="white-space:pre">			</span>if (features->done & FEATURE_CAMERA)
<span style="white-space:pre">				</span>printk(KERN_INFO "MINI2440: '%c' ignored, "
<span style="white-space:pre">					</span>"camera already registered\n", f);
<span style="white-space:pre">			</span>else
<span style="white-space:pre">				</span>features->optional[features->count++] =
<span style="white-space:pre">					</span>&s3c_device_camif;
<span style="white-space:pre">			</span>features->done |= FEATURE_CAMERA;
<span style="white-space:pre">			</span>break;
<span style="white-space:pre">		</span>}
<span style="white-space:pre">	</span>}
}
其中的<span style="font-family: Arial, Helvetica, sans-serif;">static char mini2440_features_str[12] __initdata = "0t";</span><span style="font-family: Arial, Helvetica, sans-serif;">0是因为在结构体数组</span><span style="font-family: Arial, Helvetica, sans-serif;">static struct s3c2410fb_display mini2440_lcd_cfg[] __initdata中我们的屏P35是第0个,读者可根据具体情况填入相应的数字。</span>
添加如下头文件:#include <mach/gpio-samsung.h>#include <linux/gpio.h>#include <plat/gpio-cfg.h>将 函数进行如下修改:
static void __init mini2440_machine_init(void){struct mini2440_features_t features = { 0 };int i;printk(KERN_INFO "MINI2440: Option string mini2440=%s\n",mini2440_features_str);/* Parse the feature string */mini2440_parse_features(&features, mini2440_features_str);/* turn LCD on */s3c_gpio_cfgpin(S3C2410_GPC(0), S3C2410_GPC0_LEND);/* Turn the backlight early on */WARN_ON(gpio_request_one(S3C2410_GPG(4), GPIOF_OUT_INIT_HIGH, NULL));gpio_free(S3C2410_GPG(4));/* remove pullup on optional PWM backlight -- unused on 3.5 and 7"s */gpio_request_one(S3C2410_GPB(1), GPIOF_IN, NULL);s3c_gpio_setpull(S3C2410_GPB(1), S3C_GPIO_PULL_UP);gpio_free(S3C2410_GPB(1));if (features.lcd_index != -1) {int li;mini2440_fb_info.displays =&mini2440_lcd_cfg[features.lcd_index];printk(KERN_INFO "MINI2440: LCD");for (li = 0; li < ARRAY_SIZE(mini2440_lcd_cfg); li++)if (li == features.lcd_index)printk(" [%d:%dx%d]", li,mini2440_lcd_cfg[li].width,mini2440_lcd_cfg[li].height);elseprintk(" %d:%dx%d", li,mini2440_lcd_cfg[li].width,mini2440_lcd_cfg[li].height);printk("\n");s3c24xx_fb_set_platdata(&mini2440_fb_info);}s3c_i2c0_set_platdata(NULL);s3c_nand_set_platdata(&mini2440_nand_info);platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));if (features.count)	/* the optional features */platform_add_devices(features.optional, features.count);}
重新编译烧录到板子上后重启,此时我们我们已经可以看到那个经典的小企鹅了。关于触摸屏的一直将在以后的文章中进行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: