u-boot-2009.08在mini2440上的移植
增加LCD显示功能
[日期:2011-05-14] 来源:Linux社区 作者:singleboy
移植环境
1,主机环境:VMare下CentOS 5.5 ,1G内存。
2,集成开发环境:Elipse IDE
3,编译编译环境:arm-linux-gcc v4.4.3,arm-none-eabi-gcc v4.5.1。
4,开发板:mini2440,2M nor flash,128M nand flash。
5,u-boot版本:u-boot-2009.08
7.1添加 LCD 显示功能
对于这个 LCD 的支持是参考Openmoko 的代码移植的。Openmoko 的GTA2 使用的是S3C2442 的CPU,在LCD 控制器上是一样的。而GTA2 在U-boot 的可以在LCD 上显示字符,而且对于软件分层的U-boot 来说,只要将底层驱动移植过来并调整好初始化参数就可以在LCD 上显示console。下图是LCD驱动软件分层执行流程示意。可以看到LCD在执行时最终调用的是底层的board_video_init()函数,其主要作用是对LCD控制寄存器进行初始化。可由用户根据实际LCD硬件编写。
由于友善之臂使用了两种屏,他们在一个参数上有很小的差别,而屏有不可以通过程序去识别,所以只能简单的通过Nand Flash 配置来区分导入的参数(64MB Nand 的板子使用的都是NEC 的,其他的都是统宝的)。这个功能的移植修改了5 个文件(包括drivers/video/Makefile,以及前面已经修改过的board/samsung/mini2440/mini2440.c 文件)。
【1】在/drivers/video/下添加一个驱动文件名为s3c2410_fb.c,将下面内容粘贴进去:
/*
* (C) Copyright 2006 by OpenMoko, Inc.
* Author: Harald Welte <[email protected]>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#if defined(CONFIG_VIDEO_S3C2410)
#include <video_fb.h>
#include "videomodes.h"
#include <s3c2410.h>
/*
* Export Graphic Device
*/
GraphicDevice smi;
#define VIDEO_MEM_SIZE 0x200000 /* 240x320x16bit = 0x25800 bytes */
extern void board_video_init(GraphicDevice *pGD);
/*******************************************************************************
*
* Init video chip with common Linux graphic modes (lilo)
*/
void *video_hw_init (void)
{
S3C24X0_LCD * const lcd = S3C24X0_GetBase_LCD();
GraphicDevice *pGD = (GraphicDevice *)&smi;
int videomode;
unsigned long t1, hsynch, vsynch;
char *penv;
int tmp, i, bits_per_pixel;
struct ctfb_res_modes *res_mode;
struct ctfb_res_modes var_mode;
// unsigned char videoout;
/* Search for video chip */
printf("Video: ");
tmp = 0;
videomode = CFG_SYS_DEFAULT_VIDEO_MODE;
/* get video mode via environment */
if ((penv = getenv ("videomode")) != NULL) {
/* deceide if it is a string */
if (penv[0] <= '9') {
videomode = (int) simple_strtoul (penv, NULL, 16);
tmp = 1;
}
} else {
tmp = 1;
}
if (tmp) {
/* parameter are vesa modes */
/* search params */
for (i = 0; i < VESA_MODES_COUNT; i++) {
if (vesa_modes[i].vesanr == videomode)
break;
}
if (i == VESA_MODES_COUNT) {
printf ("no VESA Mode found, switching to mode 0x%x ", CFG_SYS_DEFAULT_VIDEO_MODE);
i = 0;
}
res_mode =
(struct ctfb_res_modes *) &res_mode_init[vesa_modes[i].
resindex];
bits_per_pixel = vesa_modes[i].bits_per_pixel;
} else {
res_mode = (struct ctfb_res_modes *) &var_mode;
bits_per_pixel = video_get_params (res_mode, penv);
}
/* calculate hsynch and vsynch freq (info only) */
t1 = (res_mode->left_margin + res_mode->xres +
res_mode->right_margin + res_mode->hsync_len) / 8;
t1 *= 8;
t1 *= res_mode->pixclock;
t1 /= 1000;
hsynch = 1000000000L / t1;
t1 *=
(res_mode->upper_margin + res_mode->yres +
res_mode->lower_margin + res_mode->vsync_len);
t1 /= 1000;
vsynch = 1000000000L / t1;
/* fill in Graphic device struct */
sprintf (pGD->modeIdent, "%dx%dx%d %ldkHz %ldHz", res_mode->xres,
res_mode->yres, bits_per_pixel, (hsynch / 1000),
(vsynch / 1000));
printf ("%s\n", pGD->modeIdent);
pGD->winSizeX = res_mode->xres;
pGD->winSizeY = res_mode->yres;
pGD->plnSizeX = res_mode->xres;
pGD->plnSizeY = res_mode->yres;
switch (bits_per_pixel) {
case 8:
pGD->gdfBytesPP = 1;
pGD->gdfIndex = GDF__8BIT_INDEX;
break;
case 15:
pGD->gdfBytesPP = 2;
pGD->gdfIndex = GDF_15BIT_555RGB;
break;
case 16:
pGD->gdfBytesPP = 2;
pGD->gdfIndex = GDF_16BIT_565RGB;
break;
case 24:
pGD->gdfBytesPP = 3;
pGD->gdfIndex = GDF_24BIT_888RGB;
break;
}
/* statically configure settings */
pGD->winSizeX = pGD->plnSizeX = 240;
pGD->winSizeY = pGD->plnSizeY = 320;
pGD->gdfBytesPP = 2;
pGD->gdfIndex = GDF_16BIT_565RGB;
pGD->frameAdrs = LCD_VIDEO_ADDR;
pGD->memSize = VIDEO_MEM_SIZE;
board_video_init(pGD);
lcd->LCDSADDR1 = pGD->frameAdrs >> 1;
/* This marks the end of the frame buffer. */
lcd->LCDSADDR2 = (lcd->LCDSADDR1&0x1fffff) + (pGD->winSizeX+0) * pGD->winSizeY;
lcd->LCDSADDR3 = (pGD->winSizeX & 0x7ff);
/* Clear video memory */
memset((void *)pGD->frameAdrs, 0, pGD->memSize);
/* Enable Display */
lcd->LCDCON1 |= 0x01; /* ENVID = 1 */
return ((void*)&smi);
}
void
video_set_lut (unsigned int index, /* color number */
unsigned char r, /* red */
unsigned char g, /* green */
unsigned char b /* blue */
)
{
}
#endif /* CONFIG_VIDEO_S3C2410 */
【2】打开/drivers/video/Makefile,定位到
COBJS-y += videomodes.o
COBJS-y += s3c2410_fb.o
COBJS := $(COBJS-y)
【3】打开/drivers/video/cfb_console.c,定位到284行,修改如下:
#include <linux_logo.h>
#define VIDEO_LOGO_WIDTH LINUX_LOGO_WIDTH
#define VIDEO_LOGO_HEIGHT LINUX_LOGO_HEIGHT
#define VIDEO_LOGO_LUT_OFFSET LINUX_LOGO_LUT_OFFSET
#define VIDEO_LOGO_COLORS LINUX_LOGO_COLORS
#endif /* CONFIG_VIDEO_BMP_LOGO */
//#define VIDEO_INFO_X (VIDEO_LOGO_WIDTH)
//#define VIDEO_INFO_Y (VIDEO_FONT_HEIGHT/2)
#define VIDEO_INFO_X (0) //用于指明LOGO中打印在LCD上的信息的位置;
#define VIDEO_INFO_Y (VIDEO_LOGO_HEIGHT)
#else /* CONFIG_VIDEO_LOGO */
#define VIDEO_LOGO_WIDTH 0
#define VIDEO_LOGO_HEIGHT 0
#endif /* CONFIG_VIDEO_LOGO */
【4】打开/drivers/video/videomodes.c,定位到98行附近,修改如下:
{0x31A, RES_MODE_1280x1024, 16},
{0x31B, RES_MODE_1280x1024, 24},
{0x211, RES_MODE_240x320, 16},
};
const struct ctfb_res_modes res_mode_init[RES_MODES_COUNT] = {
/* x y pixclk le ri up lo hs vs s vmode */
{640, 480, 39721, 40, 24, 32, 11, 96, 2, 0, FB_VMODE_NONINTERLACED},
{800, 600, 27778, 64, 24, 22, 1, 72, 2, 0, FB_VMODE_NONINTERLACED},
{1024, 768, 15384, 168, 8, 29, 3, 144, 4, 0, FB_VMODE_NONINTERLACED},
{960, 720, 13100, 160, 40, 32, 8, 80, 4, 0, FB_VMODE_NONINTERLACED},
{1152, 864, 12004, 200, 64, 32, 16, 80, 4, 0, FB_VMODE_NONINTERLACED},
{1280, 1024, 9090, 200, 48, 26, 1, 184, 3, 0, FB_VMODE_NONINTERLACED},
{240, 320, 158025, 26, 6, 1, 11, 37, 2, 0, FB_VMODE_NONINTERLACED},
};
【5】打开/drivers/video/videomodes.h,定位到25行,修改如下:
//#ifndef CONFIG_SYS_DEFAULT_VIDEO_MODE
//#define CONFIG_SYS_DEFAULT_VIDEO_MODE 0x301
#ifndef CFG_SYS_DEFAULT_VIDEO_MODE
#define CFG_SYS_DEFAULT_VIDEO_MODE 0x211
#endif
/* Some mode definitions */
定位到83行,修改如下:
#define RES_MODE_1280x1024 5
//#define RES_MODES_COUNT 6
#define RES_MODE_240x320 6
#define RES_MODES_COUNT 7
//#define VESA_MODES_COUNT 19
#define VESA_MODES_COUNT 20
extern const struct ctfb_vesa_modes vesa_modes[];
【6】打开board/samsung/mini2440/mini2440.c,定位到30行,加入如下头文件:
#include <common.h>
#include <s3c2410.h>
#include <video_fb.h>
定位到138行附近,修改如下:
return 0;
}
#define MVAL (0)
#define MVAL_USED (0) //0=each frame 1=rate by MVAL
#define INVVDEN (1) //0=normal 1=inverted
#define BSWP (0) //Byte swap control
#define HWSWP (1) //Half word swap control
//TFT 240320
#define LCD_XSIZE_TFT_240320 (240)
#define LCD_YSIZE_TFT_240320 (320)
//TFT240320
#define HOZVAL_TFT_240320 (LCD_XSIZE_TFT_240320-1)
#define LINEVAL_TFT_240320 (LCD_YSIZE_TFT_240320-1)
//Timing parameter for NEC3.5"
#define VBPD_240320 (3)
#define VFPD_240320 (10)
#define VSPW_240320 (1)
#define HBPD_240320 (5)
#define HFPD_240320 (2)
#define HSPW_240320_NEC (36) //Adjust the horizontal displacement of the screen
#define HSPW_240320_TD (23) //64MB nand mini2440 is 36 ,128MB is 23
//+ ?--> - : <--
#define CLKVAL_TFT_240320 (3)
//FCLK=101.25MHz,HCLK=50.625MHz,VCLK=6.33MHz
void board_video_init(GraphicDevice *pGD)
{
S3C24X0_LCD * const lcd = S3C24X0_GetBase_LCD();
S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
/* FIXME: select LCM type by env variable */
/* Configuration for GTA01 LCM on QT2410 */
lcd->LCDCON1 = 0x00000378; /* CLKVAL=4, BPPMODE=16bpp, TFT, ENVID=0 */
lcd->LCDCON2 = (VBPD_240320<<24)|(LINEVAL_TFT_240320<<14)|(VFPD_240320<<6)|(VSPW_240320);
lcd->LCDCON3 = (HBPD_240320<<19)|(HOZVAL_TFT_240320<<8)|(HFPD_240320);
if ( (nand->NFCONF) & 0x08 ) {
lcd->LCDCON4 = (MVAL<<8)|(HSPW_240320_TD);
}
else {
lcd->LCDCON4 = (MVAL<<8)|(HSPW_240320_NEC);
}
lcd->LCDCON5 = 0x00000f09;
lcd->LPCSEL = 0x00000000;
}
int dram_init (void)
{
gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
return 0;
}
【7】打开/lib_arm/board.c,定位到482行附近,修改如下:
#if defined(CONFIG_CFB_CONSOLE)
printf ("%s\n", version_string);
printf ("modified by singleboy([email protected])\n"); //display on LCD
printf ("Love Linux forever!!\n");
#endif
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop ();
}
【8】自定义开机logo
(1)如果先改成自己喜欢的图片,可以tools/logos/denx.bmp图片,也可将自己喜欢的图片放在tools/logos/目录下,记住一定图片大小不要起过你的屏的大小,色彩深度不能大于256色,即8位色深的图片8bpp的bmp图。不同的logo图片的大小标准对应不同的,这里S3C2440所对应的是160*96分辨率的BMP图片。
制作方法一:
可以用任何工具把需要处理的logo图片转换成bmp格式图片,大小160*96像素,色彩深度256色,即8bpp(8位色深),然后保存为你需要的文件名字,我的是logott.bmp。
制作方法二(未测试):
在制作图片前,请您现确认您的Linux主机上安装了Netpbm 工具包,如果没有,可以在 Netpbm主页下载源代码编译安装。
将你想要的图片裁减成160*96的JPG图片,然后用以下的脚本处理一下就好了:
#!/bin/sh
#install Netpbm first
jpegtopnm $1 | ppmquant 31 | ppmtobmp -bpp 8 > $2
使用方法: (脚本名) ( 待处理的JPG图片名) (输出文件名)
(2)打开/tools/Makefile,定位到124行附近,修改如下:
# Generated LCD/video logo
LOGO_H = $(OBJTREE)/include/bmp_logo.h
LOGO-$(CONFIG_LCD_LOGO) += $(LOGO_H)
LOGO-$(CONFIG_VIDEO_LOGO) += $(LOGO_H)
ifeq ($(LOGO_BMP),)
#LOGO_BMP= logos/denx.bmp
LOGO_BMP= logos/logott.bmp
endif
ifeq ($(VENDOR),atmel)
LOGO_BMP= logos/atmel.bmp
endif
ifeq ($(VENDOR),ronetix)
LOGO_BMP= logos/ronetix.bmp
endif
如果你将自己制作的logo命名成logos目录下denx.bmp而将之前的替换掉,这里的代码就不用修改了。
然后保存。
【9】 LOGO及字体显示在LCD上
static void *video_logo (void)
{
char info[128];
extern char version_string;
int space, len, y_off = 0;
可见在LCD打印信息的语句是在这个函数里的
logo_plot (video_fb_address, VIDEO_COLS, 0, 0);
sprintf (info, " %s", &version_string);//这是在LCD上打印信息的语句
space = (VIDEO_LINE_LEN / 2 - VIDEO_INFO_X) / VIDEO_FONT_WIDTH;
len = strlen(info);
if (len > space) {
video_drawchars (VIDEO_INFO_X, VIDEO_INFO_Y,
(uchar *)info, space);
video_drawchars (VIDEO_INFO_X + VIDEO_FONT_WIDTH,
VIDEO_INFO_Y + VIDEO_FONT_HEIGHT,
(uchar *)info + space, len - space);
y_off = 1;
} else
video_drawstring (VIDEO_INFO_X, VIDEO_INFO_Y, (uchar *)info);
【10】打开include/configs/mini2440.h头文件,定位到138行附近,加入下面代码,即可将串口的打印信息显示在lcd上:
#define CONFIG_EXTRA_ENV_SETTINGS \
"stdin=serial\0" \
"stdout=vga\0" \
"stderr=serial\0" \
""
CONFIG_EXTRA_ENV_SETTINGS:系统默认的环境变量在/common/env_common.c的uchar default_environment[]中,这个数组将所有的环境变量组织起来 。而对于这个数组没有定义的环境变量可以在CONFIG_EXTRA_ENV_SETTINGS中由用户自定义。
只要让stdout等于vga就可以了。在lib_arm/board.c文件中可以看到console_init初始化两次,我们修改的影响第二次的初始化,对第一次的初始化不产生影响。
定位到定位到文件末尾处,加入下面代码:
/*
LCD video settings
*/
#define CONFIG_CFB_CONSOLE //Enables console device for a color framebuffer
#define CONFIG_SYS_VIDEO_LOGO_MAX_SIZE (240*320+1024+100) /* 100 = slack */
#define LCD_VIDEO_ADDR 0x33d00000
#define VIDEO_FB_16BPP_PIXEL_SWAP //the color palette,bpp is bits per pixel
#define CONFIG_VIDEO //Video support
#define CONFIG_VIDEO_S3C2410
#define CONFIG_VIDEO_LOGO //display Linux Logo in upper left corner
#define CONFIG_VIDEO_BMP_LOGO //use bmp_logo instead of linux_logo
#define CONFIG_CMD_BMP //BMP support
#define CONFIG_VIDEO_BMP_GZIP //Gzip compressed BMP image support
#define CONFIG_CMD_UNZIP
#define CFG_CONSOLE_INFO_QUIET //Suppress display of console information at boot.
#define CONFIG_SPLASH_SCREEN //enable splash screen support,implicitly enable U-Boot Bitmap Support.
//#define CONFIG_VIDEO_SW_CURSOR //Draws a cursor after the last character.No blinking is provided.
//Uses the macros CURSOR_SET and CURSOR_OFF.
//#define CONFIG_CONSOLE_EXTRA_INFO //Display additional board information to serial port beside the logo.
//This define requires a board specific function: video_drawstring() that fills a info buffer.
//#define CONFIG_CONSOLE_CURSOR //on/off drawing cursor is done with delay loop in VIDEO_TSTC_FCT
//#define CONFIG_CONSOLE_TIME //display time/date in upper right corner, needs CFG_CMD_DATE.
//#define VIDEO_FB_LITTLE_ENDIAN // framebuffer organisation default: big endian
/*for PC-keyboard*/
#define VIDEO_KBD_INIT_FCT 0 //init function for keyboard
#define VIDEO_TSTC_FCT serial_tstc //keyboard_tstc function
#define VIDEO_GETC_FCT serial_getc //keyboard_getc function
#endif /* __CONFIG_H */
相关配置选项说明:
CONFIG_CFB_CONSOLE:使能终端设备的彩色帧缓冲. 在/divers/video/cfb_console.c)有相关定义。
VIDEO_FB_LITTLE_ENDIAN 图像存储组织 (默认为大端序)
VIDEO_HW_RECTFILL 图像芯片支持矩形填充(rectangle fill)(cf. smiLynxEM)
VIDEO_HW_BITBLT 图像芯片支持位块传输(bit-blit) (cf. smiLynxEM)
VIDEO_VISIBLE_COLS 可视像素列 (cols=pitch)
VIDEO_VISIBLE_ROWS 可视像素行
VIDEO_PIXEL_SIZE 每像素字节数
VIDEO_DATA_FORMAT 图像数据格式 (0-5, cf. cfb_console.c)
VIDEO_FB_ADRS 帧缓冲地址
VIDEO_KBD_INIT_FCT keyboard int fct(i.e. i8042_kbd_init())
VIDEO_TSTC_FCT test char fct (i.e. i8042_tstc)
VIDEO_GETC_FCT get char fct (i.e. i8042_getc)
CONFIG_CONSOLE_CURSOR 打开/关闭 光标绘制 (需要 blink timer cf. i8042.c)
CFG_CONSOLE_BLINK_COUNT blink 间隔 (cf. i8042.c)
CONFIG_CONSOLE_TIME 在右上角显示时间/日期信息 (需要 CONFIG_CMD_DATE)
CONFIG_VIDEO_LOGO 在左上角显示Linux logo
CONFIG_VIDEO_BMP_LOGO 使用bmp_logo.h作为logo(默认是linux_logo.h)。 需要 CONFIG_VIDEO_LOGO。
CONFIG_CONSOLE_EXTRA_INFO 除了logo外的其它单板信息
如果定义了CONFIG_CFB_CONSOLE, 视频终端是默认的i/o. 使用'console=serial'环境可以强制使用串口终端
如果定义了 CONFIG_SILENT_CONSOLE, 可以用'silent'环境变量屏蔽所有终端消息(包括U-Boot和Linux的输出!)。更多信息见doc/README.silent
CONFIG_SYS_CONSOLE_IS_IN_ENV:如果你想将标准输入、标准输出、标准错误设为usbttyusbtty(USB串口终端),定义该宏。
CONFIG_VIDEO_BMP_GZIP:如果设置该选项, 除了支持标准BMP图像外, splashscreen或者bmp命令可以使用gzip压缩的BMP图像
CONFIG_SPLASH_SCREEN:如果设置该选项, 将检查环境变量"splashimage"。 如果变量存在则显示一张BMP图像,普通的logo, 版权及系统信息不再显示。 "splashimage"指定了位图的存放地址。终端也被重定向到"nulldev"。由于启动的早期就会加载Splash screen,使用它可以实现安静的启动。
7.2 重新编译后nor档a命令下载,nand启动:
可以看到左上角的logo图标换成了自己的制作的图标,下面启动信息与串口终端完全一样。LCD显示功能添加成功。
本篇文章来源于 Linux公社网站(www.linuxidc.com) 原文链接:http://www.linuxidc.com/Linux/2011-05/35982p7.htm