u-boot-2009.11在MINI2440上的移植 LCD驱动

 

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

你可能感兴趣的:(linux,struct,String,video,终端,colors)