分享

uboot: lcd frame buffer的保留机理

 guitarhua 2012-10-18
标签lcd  frame 


board.c: start_armboot()

1.lcd frame buffer的保留机理:

#ifdef CONFIG_LCD
# ifndef PAGE_SIZE
# define PAGE_SIZE 4096
# endif
/*
* reserve memory for LCD display (always full pages)
*/
/* bss_end is defined in the board-specific linker script */
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
size = lcd_setmem (addr);
gd->fb_base = addr;
#endif /* CONFIG_LCD */

1)==> CONFIG_LCD in include/configs/smdk6410.h
==> PAGE_SIZE same as above
不同的芯片,不同的PAGE_SIZE,不同的LCD有无的配置

2)_bss_end
cpu/s3c64xx/start.S:
.globl _bss_start
_bss_start:
.word __bss_start

.globl _bss_end
_bss_end:
.word _end

3)boarc/samsung/smdk6410/u-boot.lds:
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
...
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) }
_end = .;
}

4)common/lcd.c: lcd_setmem()
入口参数:addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); see above

/*
* This is called early in the system initialization to grab memory
* for the LCD controller.
* Returns new address for monitor, after reserving LCD buffer memory
*
* Note that this is running from ROM, so no write access to global data.
*/
ulong lcd_setmem (ulong addr)
{
ulong size;
int line_length = (panel_info.vl_col * NBITS (panel_info.vl_bpix)) / 8;

debug ("LCD panel info: %d x %d, %d bit/pix/n",
panel_info.vl_col, panel_info.vl_row, NBITS (panel_info.vl_bpix) );

size = line_length * panel_info.vl_row;

/* Round up to nearest full page */
size = (size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);

/* Allocate pages for the frame buffer. */
addr -= size;

debug ("Reserving %ldk for LCD Framebuffer at: %08lx/n", size>>10, addr);

return (addr);
}

===>这里没有支持6410的LCD,故,也无定义s3c6410的控制器的结构,也无初始化

===>panel_info
vidinfo_t panel_info;

===>vidinfo_t:
include/lcd.h

#if defined CONFIG_MPC823
/*
* LCD controller stucture for MPC823 CPU
*/
typedef struct vidinfo {
ushort vl_col; /* Number of columns (i.e. 640) */
ushort vl_row; /* Number of rows (i.e. 480) */
ushort vl_width; /* Width of display area in millimeters */
ushort vl_height; /* Height of display area in millimeters */

/* LCD configuration register */
u_char vl_clkp; /* Clock polarity */
u_char vl_oep; /* Output Enable polarity */
u_char vl_hsp; /* Horizontal Sync polarity */
u_char vl_vsp; /* Vertical Sync polarity */
u_char vl_dp; /* Data polarity */
u_char vl_bpix; /* Bits per pixel, 0 = 1, 1 = 2, 2 = 4, 3 = 8 */
u_char vl_lbw; /* LCD Bus width, 0 = 4, 1 = 8 */
u_char vl_splt; /* Split display, 0 = single-scan, 1 = dual-scan */
u_char vl_clor; /* Color, 0 = mono, 1 = color */
u_char vl_tft; /* 0 = passive, 1 = TFT */

/* Horizontal control register. Timing from data sheet */
ushort vl_wbl; /* Wait between lines */

/* Vertical control register */
u_char vl_vpw; /* Vertical sync pulse width */
u_char vl_lcdac; /* LCD AC timing */
u_char vl_wbf; /* Wait between frames */
} vidinfo_t;

extern vidinfo_t panel_info;

#elif defined CONFIG_PXA250
/*
* PXA LCD info
*/
struct pxafb_info {

/* Misc registers */
u_long reg_lccr3;
u_long reg_lccr2;
u_long reg_lccr1;
u_long reg_lccr0;
u_long fdadr0;
u_long fdadr1;

/* DMA descriptors */
struct pxafb_dma_descriptor * dmadesc_fblow;
struct pxafb_dma_descriptor * dmadesc_fbhigh;
struct pxafb_dma_descriptor * dmadesc_palette;

u_long screen; /* physical address of frame buffer */
u_long palette; /* physical address of palette memory */
u_int palette_size;
};

/*
* LCD controller stucture for PXA CPU
*/
typedef struct vidinfo {
ushort vl_col; /* Number of columns (i.e. 640) */
ushort vl_row; /* Number of rows (i.e. 480) */
ushort vl_width; /* Width of display area in millimeters */
ushort vl_height; /* Height of display area in millimeters */

/* LCD configuration register */
u_char vl_clkp; /* Clock polarity */
u_char vl_oep; /* Output Enable polarity */
u_char vl_hsp; /* Horizontal Sync polarity */
u_char vl_vsp; /* Vertical Sync polarity */
u_char vl_dp; /* Data polarity */
u_char vl_bpix; /* Bits per pixel, 0 = 1, 1 = 2, 2 = 4, 3 = 8, 4 = 16 */
u_char vl_lbw; /* LCD Bus width, 0 = 4, 1 = 8 */
u_char vl_splt; /* Split display, 0 = single-scan, 1 = dual-scan */
u_char vl_clor; /* Color, 0 = mono, 1 = color */
u_char vl_tft; /* 0 = passive, 1 = TFT */

/* Horizontal control register. Timing from data sheet */
ushort vl_hpw; /* Horz sync pulse width */
u_char vl_blw; /* Wait before of line */
u_char vl_elw; /* Wait end of line */

/* Vertical control register. */
u_char vl_vpw; /* Vertical sync pulse width */
u_char vl_bfw; /* Wait before of frame */
u_char vl_efw; /* Wait end of frame */

/* PXA LCD controller params */
struct pxafb_info pxa;
} vidinfo_t;

extern vidinfo_t panel_info;

#elif defined(CONFIG_MCC200)
typedef struct vidinfo {
ushort vl_col; /* Number of columns (i.e. 160) */
ushort vl_row; /* Number of rows (i.e. 100) */

u_char vl_bpix; /* Bits per pixel, 0 = 1 */
} vidinfo_t;
#endif /* CONFIG_MPC823, CONFIG_PXA250 or CONFIG_MCC200 */

common/lcd.c

1.调用流程 :
start_armboot()==>devices_init()==>drv_lcd_init()==>lcd_init()

2.
结构功能:

int drv_lcd_init (void)
{
device_t lcddev;
int rc;

lcd_base = (void *)(gd->fb_base);

lcd_line_length = (panel_info.vl_col * NBITS (panel_info.vl_bpix)) / 8;

lcd_init (lcd_base); /* LCD initialization */

/* Device initialization */
memset (&lcddev, 0, sizeof (lcddev));

strcpy (lcddev.name, "lcd");
lcddev.ext = 0; /* No extensions */
lcddev.flags = DEV_FLAGS_OUTPUT; /* Output only */
lcddev.putc = lcd_putc; /* 'putc' function */
lcddev.puts = lcd_puts; /* 'puts' function */

rc = device_register (&lcddev);

return (rc == 0) ? 1 : rc;
}

==》lcd_init(lcd_base):

static int lcd_init (void *lcdbase)
{
/* Initialize the lcd controller */
debug ("[LCD] Initializing LCD frambuffer at %p/n", lcdbase);

lcd_ctrl_init (lcdbase);
lcd_clear (NULL, 1, 1, NULL); /* dummy args */
lcd_enable ();

/* Initialize the console */
console_col = 0;
#ifdef CONFIG_LCD_INFO_BELOW_LOGO
console_row = 7 + BMP_LOGO_HEIGHT / VIDEO_FONT_HEIGHT;
#else
console_row = 1; /* leave 1 blank line below logo */
#endif
lcd_is_enabled = 1;

return 0;
}

==>lcd_ctrl_init(), lcd_enable ()
由对应的CPU进行专门实现

==>lcd_clear(NULL, 1, 1, NULL)
static int lcd_clear (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
#if LCD_BPP == LCD_MONOCHROME
/* Setting the palette */
lcd_initcolregs();

#elif LCD_BPP == LCD_COLOR8
/* Setting the palette */
lcd_setcolreg (CONSOLE_COLOR_BLACK, 0, 0, 0);
lcd_setcolreg (CONSOLE_COLOR_RED, 0xFF, 0, 0);
lcd_setcolreg (CONSOLE_COLOR_GREEN, 0, 0xFF, 0);
lcd_setcolreg (CONSOLE_COLOR_YELLOW, 0xFF, 0xFF, 0);
lcd_setcolreg (CONSOLE_COLOR_BLUE, 0, 0, 0xFF);
lcd_setcolreg (CONSOLE_COLOR_MAGENTA, 0xFF, 0, 0xFF);
lcd_setcolreg (CONSOLE_COLOR_CYAN, 0, 0xFF, 0xFF);
lcd_setcolreg (CONSOLE_COLOR_GREY, 0xAA, 0xAA, 0xAA);
lcd_setcolreg (CONSOLE_COLOR_WHITE, 0xFF, 0xFF, 0xFF);
#endif

#ifndef CFG_WHITE_ON_BLACK
lcd_setfgcolor (CONSOLE_COLOR_BLACK);
lcd_setbgcolor (CONSOLE_COLOR_WHITE);
#else
lcd_setfgcolor (CONSOLE_COLOR_WHITE);
lcd_setbgcolor (CONSOLE_COLOR_BLACK);
#endif /* CFG_WHITE_ON_BLACK */

#ifdef LCD_TEST_PATTERN
test_pattern();
#else
/* set framebuffer to background color */
memset ((char *)lcd_base,
COLOR_MASK(lcd_getbgcolor()),
lcd_line_length*panel_info.vl_row);
#endif
/* Paint the logo and retrieve LCD base address */
debug ("[LCD] Drawing the logo.../n");
lcd_console_address = lcd_logo ();

console_col = 0;
console_row = 0;

return (0);
}

依据LCD_BPP为单色,8BPP,等(其余未实现)来设置相应的颜色寄存器

===>
#elif LCD_BPP == LCD_COLOR8

/*
* 8bpp color definitions
*/
# define CONSOLE_COLOR_BLACK 0
# define CONSOLE_COLOR_RED 1
# define CONSOLE_COLOR_GREEN 2
# define CONSOLE_COLOR_YELLOW 3
# define CONSOLE_COLOR_BLUE 4
# define CONSOLE_COLOR_MAGENTA 5
# define CONSOLE_COLOR_CYAN 6
# define CONSOLE_COLOR_GREY 14
# define CONSOLE_COLOR_WHITE 15 /* Must remain last / highest */

/************************************************************************/
/** Small utility to check that you got the colours right */
/************************************************************************/
#ifdef LCD_TEST_PATTERN

#define N_BLK_VERT 2
#define N_BLK_HOR 3

static int test_colors[N_BLK_HOR*N_BLK_VERT] = {
CONSOLE_COLOR_RED, CONSOLE_COLOR_GREEN, CONSOLE_COLOR_YELLOW,
CONSOLE_COLOR_BLUE, CONSOLE_COLOR_MAGENTA, CONSOLE_COLOR_CYAN,
};

static void test_pattern (void)
{
ushort v_max = panel_info.vl_row;
ushort h_max = panel_info.vl_col;
ushort v_step = (v_max + N_BLK_VERT - 1) / N_BLK_VERT;
ushort h_step = (h_max + N_BLK_HOR - 1) / N_BLK_HOR;
ushort v, h;
uchar *pix = (uchar *)lcd_base;

printf ("[LCD] Test Pattern: %d x %d [%d x %d]/n",
h_max, v_max, h_step, v_step);

/* WARNING: Code silently assumes 8bit/pixel */
for (v=0; v<v_max; ++v) {
uchar iy = v / v_step;
for (h=0; h<h_max; ++h) {
uchar ix = N_BLK_HOR * iy + (h/h_step);
*pix++ = test_colors[ix];
}
}
}
#endif /* LCD_TEST_PATTERN */

==>
static void lcd_setbgcolor (int color)
{
lcd_color_bg = color & 0x0F;
}

/*----------------------------------------------------------------------*/

static int lcd_getbgcolor (void)
{
return lcd_color_bg;
}

==================================
void lcd_putc (const char c)
{
if (!lcd_is_enabled) {
serial_putc(c);
return;
}

switch (c) {
case '/r': console_col = 0;
return;

case '/n': console_newline();
return;

case '/t': /* Tab (8 chars alignment) */
console_col |= 8;
console_col &= ~7;

if (console_col >= CONSOLE_COLS) {
console_newline();
}
return;

case '/b': console_back();
return;

default: lcd_putc_xy (console_col * VIDEO_FONT_WIDTH,
console_row * VIDEO_FONT_HEIGHT,
c);
if (++console_col >= CONSOLE_COLS) {
console_newline();
}
return;
}
/* NOTREACHED */
}

/*----------------------------------------------------------------------*/

void lcd_puts (const char *s)
{
if (!lcd_is_enabled) {
serial_puts (s);
return;
}

while (*s) {
lcd_putc (*s++);
}
}
 
 
uboot开机logo

参考资料:
【1】U-boot开机logo的制作方法(Tekkaman Ninja):http://blog./u1/34474/showart_2085233.html
【2】U-Boot中的Splash Screen(Charlie Chen):http://blog./u1/51797/showart.php?id=2070554
【3】UBOOT LCD驱动流程(牛蹄印章):http://blog./u3/90973/showart_2303809.html

在有实现LCD显示和LCD命令行终端的U-boot中,默认情况下在左上角都有显示一个logo,如果是atmel的芯片,就会有atmel的logo,三星的则是denx的logo。如果想把它改成自己喜欢的或者公司的logo,则只要作简单的修改便可以实现。

一、图片的放置路径

所 有的开机logo都放在了 /tools/logos 之下,所以,把你需要显示的logo图片(bmp格式)也放置到该目录下。根据你所设置的显示帧缓存的大小,图片大小有所限制。使用这种方法还有一个限制 是:图片只能是8bpp的bmp图(参考uboot源码)。Tekkman文章中所说的“所替换的logo必须和原来的大小、格式一模一样,否则会出现 u-boot使用过程中宕机重启的后果”,我自己亲测中并未遇到,当然,我也并没有做足够的测试,只是这并不需要和原图的大小一模一样。

二、修改Makefile文件
修改/tools目录下的Makefile文件,大约是44~46行

ifeq ($(LOGO_BMP),)
LOGO_BMP= logos/denx.bmp
endif

把 denx.bmp 替换为你需要显示的logo图片的文件名,保存退出,重新编译uboot。

三、图片的转换脚本
在制作图片前,请您现确认您的Linux主机上安装了Netpbm 工具包。如果是ubuntu,你可以直接用新立得安装;如果是别的发行版,可以在 Netpbm主页 下载源代码编译。然后用以下的脚本处理一下就好了:

#!/bin/sh
#install Netpbm first
jpegtopnm $1 | ppmquant 31 | ppmtobmp -bpp 8 > $2

使用方法: (脚本名) ( 待处理的JPG图片名) (输出文件名)

关于uboot的lcd驱动的编写,可参考资料【3】和Tekkaman的uboot移植源码以及相应的芯片数据手册。参考资料【2】中的BMP命令不是必须的,不过实现了这个命令可以方便调试。

博客推荐文章

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多