基于s3c2440的u-boot-2010.3 LCD驱动流程以及LOGO的显示详解
2014-12-10 15:10
736 查看
如果需要在UBOOT的阶段就要显示LOGO,直到内核启动完毕后UI接管FrameBuffer为止。这样可以避免内核启动过程的这段时间大约5-8秒内的黑屏。所以我们要为u-boot添加LCD驱动并且了解LCD驱动的流程便于修改。
u-boot的启动流程:从文件层面上看主要流程是在两个文件中:cpu/arm920t/start.s,lib_arm/board.c,
其中start.s
是用汇编写的初始化cpu的堆栈 中断向量 时钟频率 SDRAM,并把c部分的代码从nand flash拷贝到SDRAM中,board.c的代码主要是初始化各外设比如串口 i2c LCD等,所以LCD驱动的开始在board.c中。下面分析board.c的部分源码
typedef
int (init_fnc_t) (void);//定义一个函数数据类型
int print_cpuinfo (void);
/***一个函数数组里面是各种初始化函数***/
init_fnc_t *init_sequence[] = {
#if defined(CONFIG_ARCH_CPU_INIT)
arch_cpu_init,/* basic arch cpu dependent setup */
#endif
board_init,/*
初始化开发板的相关外设 下面会详细分析 */
#if defined(CONFIG_USE_IRQ)
interrupt_init,/* set up exceptions */
#endif
timer_init,/* initialize timer */
#ifdef CONFIG_FSL_ESDHC
get_clocks,
#endif
env_init,/* initialize environment */
init_baudrate,/* initialze baudrate settings */
serial_init,/* serial communications setup */
console_init_f,/* stage 1 init of console */
display_banner,/* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo,/* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard,/* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
init_func_i2c,
#endif
dram_init,/* configure available RAM banks */
#if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)
arm_pci_init,
#endif
display_dram_config,
NULL,
};
/*******c入口*******/
void start_armboot (void)
{
init_fnc_t **init_fnc_ptr;//定义一个init_fnc_t类型的指针
char *s;
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
unsigned long addr;
#endif
/* Pointer is writable since we allocated a register for it */
gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));//u-boot的全局变量存储各种信息
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");
memset ((void*)gd, 0, sizeof (gd_t));
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));
gd->flags |= GD_FLG_RELOC;
monitor_flash_len = _bss_start - _armboot_start;
/******************下面这个循环将上面数组的函数都执行一遍********************/
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
/* armboot_start is defined in the board-specific linker script */
mem_malloc_init (_armboot_start - CONFIG_SYS_MALLOC_LEN,
CONFIG_SYS_MALLOC_LEN);
#ifndef CONFIG_SYS_NO_FLASH
/* configure available FLASH banks */
display_flash_config (flash_init ());
#endif /* CONFIG_SYS_NO_FLASH */
#ifdef CONFIG_VFD
#ifndef PAGE_SIZE
# define PAGE_SIZE 4096
#endif
/*
* reserve memory for VFD display (always full pages)
*/
/* bss_end is defined in the board-specific linker script */
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
vfd_setmem (addr);
gd->fb_base = addr;
#endif /* CONFIG_VFD */
#ifdef CONFIG_LCD
/* board init may have inited fb_base */
if (!gd->fb_base) {
#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);
lcd_setmem (addr);
gd->fb_base = addr;
}
#endif /* CONFIG_LCD */
#if defined(CONFIG_CMD_NAND)
puts ("NAND: ");
nand_init();/* go init the NAND */
#endif
#if defined(CONFIG_CMD_ONENAND)
onenand_init();
#endif
#ifdef CONFIG_HAS_DATAFLASH
AT91F_DataflashInit();
dataflash_print_info();
#endif
/* initialize environment */
env_relocate ();
#ifdef CONFIG_VFD
/* must do this after the framebuffer is allocated */
drv_vfd_init();//mini2440的LCD初始化和此函数无关
#endif
/* CONFIG_VFD */
#ifdef CONFIG_SERIAL_MULTI
serial_initialize();
#endif
/* IP Address */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
stdio_init ();/* 初始化设备列表mini2440LCD设备初始化就在这里
下面会详细分析此函数*/
jumptable_init ();
#if defined(CONFIG_API)
/* Initialize API */
api_init ();
#endif
cosole_init_r ();/* fully init console as a device */
#if defined(CONFIG_ARCH_MISC_INIT)
/* miscellaneous arch dependent initialisations */
arch_misc_init ();
#endif
#if defined(CONFIG_MISC_INIT_R)
/* miscellaneous platform dependent initialisations */
misc_init_r ();
#endif
// extern void Port_Init(void);
// Port_Init();
/* enable exceptions */
enable_interrupts ();
extern int usb_init_slave(void);
usb_init_slave();
/* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_TI_EMAC
/* XXX: this needs to be moved to board init */
extern void davinci_eth_set_mac_addr (const u_int8_t *addr);
if (getenv ("ethaddr")) {
uchar enetaddr[6];
eth_getenv_enetaddr("ethaddr", enetaddr);
davinci_eth_set_mac_addr(enetaddr);
}
#endif
#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
/* XXX: this needs to be moved to board init */
if (getenv ("ethaddr")) {
uchar enetaddr[6];
eth_getenv_enetaddr("ethaddr", enetaddr);
smc_set_mac_addr(enetaddr);
}
#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */
/* Initialize from environment */
if ((s = getenv ("loadaddr")) != NULL) {
load_addr = simple_strtoul (s, NULL, 16);
}
#if defined(CONFIG_CMD_NET)
if ((s = getenv ("bootfile")) != NULL) {
copy_filename (BootFile, s, sizeof (BootFile));
}
#endif
#ifdef BOARD_LATE_INIT
board_late_init ();
#endif
#ifdef CONFIG_GENERIC_MMC
puts ("MMC: ");
mmc_initialize (gd->bd);
#endif
#ifdef CONFIG_BITBANGMII
bb_miiphy_init();
#endif
#if defined(CONFIG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
puts ("Net: ");
#endif
eth_initialize(gd->bd);
#if defined(CONFIG_RESET_PHY_R)
debug ("Reset Ethernet PHY\n");
reset_phy();
#endif
#endif
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop ();
}
/* NOTREACHED - no way out of command loop except booting */
}
以上是board.c中源码的分析,下面将介绍和lcd相关的上面提到的board_init()和stadio_init()函数
在board/embedclub/smdk2440a/smdk2440a.c文件中
//*****************以下部分是我的LCD模组SPI初始化代码,如果大家的不用初始化则没有此部分*********/
#define LCD_CS_SHIFT 5
#define LCD_CLK_SHIFT 4
#define LCD_DAT_SHIFT 6
#define LCD_RST_SHIFT 0
static void set_cs(int cs)
{
struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
int reg;
reg = gpio->GPFDAT;
reg &= ~(0x1 << LCD_CS_SHIFT);
reg |= (cs << LCD_CS_SHIFT);
gpio->GPFDAT = reg;
}
static void set_clk(int clk)
{
struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
int reg;
reg = gpio->GPFDAT;
reg &= ~(0x1 << LCD_CLK_SHIFT);
reg |= (clk << LCD_CLK_SHIFT);
gpio->GPFDAT = reg;
}
static void set_sdi(int outdata)
{
struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
int reg;
reg = gpio->GPFDAT;
reg &= ~(0x1 << LCD_DAT_SHIFT);
reg |= (outdata << LCD_DAT_SHIFT);
gpio->GPFDAT = reg;
}
static void set_res(int res)
{
struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
int reg;
reg = gpio->GPFDAT;
reg &= ~(0x1 << LCD_RST_SHIFT);
reg |= (res << LCD_RST_SHIFT);
gpio->GPFDAT = reg;
}
static void lcd_reset()
{
set_res(1);
udelay(20000);
set_res(0);
udelay(10000);
set_res(1);
udelay(120000);
}
static chushihua_gpio(void)
{
set_cs(1);
set_clk(1);
set_sdi(1);
set_res(1);
udelay(10000);
}
static void send_cmd(unsigned char cmd)
{
unsigned char i;
set_cs(0);
udelay(10);
set_clk(0);
set_sdi(0);
udelay(100);
set_clk(1);
udelay(100);
for(i=0;i<8;i++)
{
set_clk(0);
if (cmd&0x80)
{
set_sdi(1);
}
else
{
set_sdi(0);
}
udelay(100);
set_clk(1);
udelay(100);
cmd=cmd<<1;
}
set_cs(1);
udelay(10);
}
static void send_date(unsigned char date)
{
unsigned char i;
set_cs(0);
udelay(10);
set_clk(0);
set_sdi(1);
udelay(100);
set_clk(1);
udelay(100);
for(i=0;i<8;i++)
{
set_clk(0);
if (date&0x80)
{
set_sdi(1);
}
else
{
set_sdi(0);
}
udelay(100);
set_clk(1);
udelay(100);
date=date<<1;
}
set_cs(1);
udelay(10);
}
static void set_hx8369(void)
{
lcd_reset(); //Set_EXTC
send_cmd(0xB9); // SET password
send_date(0xFF);
send_date(0x83);
send_date(0x69);
send_cmd(0xB1); //Set Power
send_date(0x01);
send_date(0x00);
send_date(0x34);
send_date(0x06);
send_date(0x00);
send_date(0x11);
send_date(0x11);
send_date(0x2A);
send_date(0x32);
send_date(0x3F);
send_date(0x3F);
send_date(0x07);
send_date(0x23);
send_date(0x01);
send_date(0xE6);
send_date(0xE6);
send_date(0xE6);
send_date(0xE6);
send_date(0xE6);
udelay(120000);
send_cmd(0xB2); // SET Display 480x800
send_date(0x00);
send_date(0x2B);
send_date(0x03);
send_date(0x03);
send_date(0x70);
send_date(0x00);
send_date(0xFF);
send_date(0x00);
send_date(0x00);
send_date(0x00);
send_date(0x00);
send_date(0x03);
send_date(0x03);
send_date(0x00);
send_date(0x01);
send_cmd(0xB4); // SET Display 480x800
send_date(0x00);
send_date(0x0C);
send_date(0xA0);
send_date(0x0E);
send_date(0x06);
send_cmd(0xB6); // SET VCOM
send_date(0x35);
send_date(0x35);
udelay(120000);
send_cmd(0xD5); // SET GIP
send_date(0x00);
send_date(0x05);
send_date(0x03);
send_date(0x00);
send_date(0x01);
send_date(0x09);
send_date(0x10);
send_date(0x80);
send_date(0x37);
send_date(0x37);
send_date(0x20);
send_date(0x31);
send_date(0x46);
send_date(0x8A);
send_date(0x57);
send_date(0x9B);
send_date(0x20);
send_date(0x31);
send_date(0x46);
send_date(0x8A);
send_date(0x57);
send_date(0x9B);
send_date(0x07);
send_date(0x0F);
send_date(0x02);
send_date(0x00);
send_cmd(0xE0); // SET Gamma
send_date(0x00);
send_date(0x08);
send_date(0x0D);
send_date(0x2D);
send_date(0x34);
send_date(0x3F);
send_date(0x19);
send_date(0x38);
send_date(0x09);
send_date(0x0E);
send_date(0x0E);
send_date(0x12);
send_date(0x14);
send_date(0x12);
send_date(0x14);
send_date(0x13);
send_date(0x19);
send_date(0x00);
send_date(0x08);
send_date(0x0D);
send_date(0x2D);
send_date(0x34);
send_date(0x3F);
send_date(0x19);
send_date(0x38);
send_date(0x09);
send_date(0x0E);
send_date(0x0E);
send_date(0x12);
send_date(0x14);
send_date(0x12);
send_date(0x14);
send_date(0x13);
send_date(0x19);
udelay(120000);
send_cmd(0xC1);
send_date(0x01); //enable DGC function
send_date(0x02); //SET R-GAMMA
send_date(0x08);
send_date(0x12);
send_date(0x1A);
send_date(0x22);
send_date(0x2A);
send_date(0x31);
send_date(0x36);
send_date(0x3F);
send_date(0x48);
send_date(0x51);
send_date(0x58);
send_date(0x60);
send_date(0x68);
send_date(0x70);
send_date(0x78);
send_date(0x80);
send_date(0x88);
send_date(0x90);
send_date(0x98);
send_date(0xA0);
send_date(0xA7);
send_date(0xAF);
send_date(0xB6);
send_date(0xBE);
send_date(0xC7);
send_date(0xCE);
send_date(0xD6);
send_date(0xDE);
send_date(0xE6);
send_date(0xEF);
send_date(0xF5);
send_date(0xFB);
send_date(0xFC);
send_date(0xFE);
send_date(0x8C);
send_date(0xA4);
send_date(0x19);
send_date(0xEC);
send_date(0x1B);
send_date(0x4C);
send_date(0x40);
send_date(0x02); //SET G-Gamma
send_date(0x08);
send_date(0x12);
send_date(0x1A);
send_date(0x22);
send_date(0x2A);
send_date(0x31);
send_date(0x36);
send_date(0x3F);
send_date(0x48);
send_date(0x51);
send_date(0x58);
send_date(0x60);
send_date(0x68);
send_date(0x70);
send_date(0x78);
send_date(0x80);
send_date(0x88);
send_date(0x90);
send_date(0x98);
send_date(0xA0);
send_date(0xA7);
send_date(0xAF);
send_date(0xB6);
send_date(0xBE);
send_date(0xC7);
send_date(0xCE);
send_date(0xD6);
send_date(0xDE);
send_date(0xE6);
send_date(0xEF);
send_date(0xF5);
send_date(0xFB);
send_date(0xFC);
send_date(0xFE);
send_date(0x8C);
send_date(0xA4);
send_date(0x19);
send_date(0xEC);
send_date(0x1B);
send_date(0x4C);
send_date(0x40);
send_date(0x02); //SET B-Gamma
send_date(0x08);
send_date(0x12);
send_date(0x1A);
send_date(0x22);
send_date(0x2A);
send_date(0x31);
send_date(0x36);
send_date(0x3F);
send_date(0x48);
send_date(0x51);
send_date(0x58);
send_date(0x60);
send_date(0x68);
send_date(0x70);
send_date(0x78);
send_date(0x80);
send_date(0x88);
send_date(0x90);
send_date(0x98);
send_date(0xA0);
send_date(0xA7);
send_date(0xAF);
send_date(0xB6);
send_date(0xBE);
send_date(0xC7);
send_date(0xCE);
send_date(0xD6);
send_date(0xDE);
send_date(0xE6);
send_date(0xEF);
send_date(0xF5);
send_date(0xFB);
send_date(0xFC);
send_date(0xFE);
send_date(0x8C);
send_date(0xA4);
send_date(0x19);
send_date(0xEC);
send_date(0x1B);
send_date(0x4C);
send_date(0x40);
send_cmd(0x3A);
send_date(0x55);
send_cmd(0x11);
udelay(120000);
send_cmd(0x29);
send_cmd(0x2c);
}
void lcd_config()
{
chushihua_gpio();
set_hx8369();
}
/*****************以上部分是我的LCD模组SPI初始化代码,如果大家的不用初始化则没有此部分*********/
int board_init (void)//初始化时钟IO等,我在此处初始化LCD
{
struct s3c24x0_clock_power * const clk_power =
s3c24x0_get_base_clock_power();
struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
/* to reduce PLL lock time, adjust the LOCKTIME register */
clk_power->LOCKTIME = 0xFFFFFF;
/* configure MPLL */
clk_power->MPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV);
/* some delay between MPLL and UPLL */
delay (4000);
/* configure UPLL */
clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV);
/* some delay between MPLL and UPLL */
delay (8000);
/* set up the I/O ports */
gpio->GPACON = 0x007FFFFF;
#if defined(CONFIG_SMDK2440)
gpio->GPBCON = 0x00295551;
#else
gpio->GPBCON = 0x00044556;
#endif
gpio->GPBUP = 0x000007FF;
#if defined(CONFIG_SMDK2440)
gpio->GPCCON = 0xAAAAA6AA;
gpio->GPCDAT &= ~(1<<5);
#else
gpio->GPCCON = 0xAAAAAAAA;
#endif
gpio->GPCUP = 0xFFFFFFFF;
gpio->GPDCON = 0xAAAAAAAA;
gpio->GPDUP = 0xFFFFFFFF;
gpio->GPECON = 0xAAAAAAAA;
gpio->GPEUP = 0x0000FFFF;
gpio->GPFCON = 0x000055AA;
gpio->GPFUP = 0x000000FF;
gpio->GPGCON = 0xFF95FF3A;
gpio->GPGUP = 0x0000FFFF;
gpio->GPHCON = 0x0016FAAA;
gpio->GPHUP = 0x000007FF;
gpio->EXTINT0=0x22222222;
gpio->EXTINT1=0x22222222;
gpio->EXTINT2=0x22222222;
#if defined(CONFIG_S3C2410)
/* arch number of SMDK2410-Board */
gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
#endif
#if defined(CONFIG_S3C2440)
/* arch number of S3C2440-Board */
gd->bd->bi_arch_number = MACH_TYPE_SMDK2440A;
//gd->bd->bi_arch_number = 782;
#endif
//printf("Start Linux parameters at 0x30000100\n");
//printf("MACH_TYPE=%d\n", gd->bd->bi_arch_number);
//printf("Linux command line is: %s\n",CONFIG_BOOTARGS);
/* adress of boot parameters */
gd->bd->bi_boot_params = 0x30000100;
icache_enable();
dcache_enable();
lcd_config() ;//此处初始化lcd的配置
如果大家不用初始化LCD,则不必关心board_init函数
return 0;
}
在common/stadio.c中
int
stdio_init (void) //初始化板子的外设
{
#if !defined(CONFIG_RELOC_FIXUP_WORKS)
/* already relocated for current ARM implementation */
ulong relocation_offset = gd->reloc_off;
int i;
/* relocate device name pointers */
for (i = 0; i < (sizeof (stdio_names) / sizeof (char *)); ++i) {
stdio_names[i] = (char *) (((ulong) stdio_names[i]) +
relocation_offset);
}
#endif /* !CONFIG_RELOC_FIXUP_WORKS */
/* Initialize the list */
INIT_LIST_HEAD(&(devs.list));
#ifdef CONFIG_ARM_DCC_MULTI
drv_arm_dcc_init ();
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
#endif
#ifdef CONFIG_LCD
drv_lcd_init ();//和mini2440LCD无关
#endif
#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
drv_video_init ();//此函数初始化mini2440的LCD控制器以及显示LOGO
#endif
#ifdef CONFIG_KEYBOARD
drv_keyboard_init ();
#endif
#ifdef CONFIG_LOGBUFFER
drv_logbuff_init ();
#endif
drv_system_init ();
#ifdef CONFIG_SERIAL_MULTI
serial_stdio_init ();
#endif
#ifdef CONFIG_USB_TTY
drv_usbtty_init ();
#endif
#ifdef CONFIG_NETCONSOLE
drv_nc_init ();
#endif
#ifdef CONFIG_JTAG_CONSOLE
drv_jtag_console_init ();
#endif
return (0);
}
下面介绍drv_video_init
()函数
在driver/video/cfb_console.c
int drv_video_init (void) //初始化LCD控制器并显示LOGO
{
int skip_dev_init;
struct stdio_dev console_dev;
/* Check if video initialization should be skipped */
if (board_video_skip())
return 0;
/* Init video chip - returns with framebuffer cleared */
skip_dev_init = (video_init ()== -1);//初始化LCD控制器并显示LOGO
#if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
PRINTD ("KBD: Keyboard init ...\n");
skip_dev_init |= (VIDEO_KBD_INIT_FCT == -1);
#endif
if (skip_dev_init)
return 0;
/* Init vga device */
memset (&console_dev, 0, sizeof (console_dev));
strcpy (console_dev.name, "vga");
console_dev.ext = DEV_EXT_VIDEO;/* Video extensions */
console_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_SYSTEM;
console_dev.putc = video_putc;/* 'putc' function */
console_dev.puts = video_puts;/* 'puts' function */
console_dev.tstc = NULL;/* 'tstc' function */
console_dev.getc = NULL;/* 'getc' function */
#if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
/* Also init console device */
console_dev.flags |= DEV_FLAGS_INPUT;
console_dev.tstc = VIDEO_TSTC_FCT;/* 'tstc' function */
console_dev.getc = VIDEO_GETC_FCT;/* 'getc' function */
#endif /* CONFIG_VGA_AS_SINGLE_DEVICE */
if (stdio_register (&console_dev) != 0)
return 0;
/* Return success */
return 1;
下面介绍video_init ()也在cfb_console.c中
static int video_init (void)
{
unsigned char color8;
if ((pGD = video_hw_init ()) == NULL)//配置LCD控制寄存器数值
return -1;
video_fb_address = (void *) VIDEO_FB_ADRS;
#ifdef CONFIG_VIDEO_HW_CURSOR
video_init_hw_cursor (VIDEO_FONT_WIDTH, VIDEO_FONT_HEIGHT);
#endif
/* Init drawing pats */
switch (VIDEO_DATA_FORMAT) {
case GDF__8BIT_INDEX:
video_set_lut (0x01, CONSOLE_FG_COL, CONSOLE_FG_COL, CONSOLE_FG_COL);
video_set_lut (0x00, CONSOLE_BG_COL, CONSOLE_BG_COL, CONSOLE_BG_COL);
fgx = 0x01010101;
bgx = 0x00000000;
break;
case GDF__8BIT_332RGB:
color8 = ((CONSOLE_FG_COL & 0xe0) |
((CONSOLE_FG_COL >> 3) & 0x1c) | CONSOLE_FG_COL >> 6);
fgx = (color8 << 24) | (color8 << 16) | (color8 << 8) | color8;
color8 = ((CONSOLE_BG_COL & 0xe0) |
((CONSOLE_BG_COL >> 3) & 0x1c) | CONSOLE_BG_COL >> 6);
bgx = (color8 << 24) | (color8 << 16) | (color8 << 8) | color8;
break;
case GDF_15BIT_555RGB:
fgx = (((CONSOLE_FG_COL >> 3) << 26) |
((CONSOLE_FG_COL >> 3) << 21) | ((CONSOLE_FG_COL >> 3) << 16) |
((CONSOLE_FG_COL >> 3) << 10) | ((CONSOLE_FG_COL >> 3) << 5) |
(CONSOLE_FG_COL >> 3));
bgx = (((CONSOLE_BG_COL >> 3) << 26) |
((CONSOLE_BG_COL >> 3) << 21) | ((CONSOLE_BG_COL >> 3) << 16) |
((CONSOLE_BG_COL >> 3) << 10) | ((CONSOLE_BG_COL >> 3) << 5) |
(CONSOLE_BG_COL >> 3));
break;
case GDF_16BIT_565RGB:
fgx = (((CONSOLE_FG_COL >> 3) << 27) |
((CONSOLE_FG_COL >> 2) << 21) | ((CONSOLE_FG_COL >> 3) << 16) |
((CONSOLE_FG_COL >> 3) << 11) | ((CONSOLE_FG_COL >> 2) << 5) |
(CONSOLE_FG_COL >> 3));
bgx = (((CONSOLE_BG_COL >> 3) << 27) |
((CONSOLE_BG_COL >> 2) << 21) | ((CONSOLE_BG_COL >> 3) << 16) |
((CONSOLE_BG_COL >> 3) << 11) | ((CONSOLE_BG_COL >> 2) << 5) |
(CONSOLE_BG_COL >> 3));
break;
case GDF_32BIT_X888RGB:
fgx = (CONSOLE_FG_COL << 16) | (CONSOLE_FG_COL << 8) | CONSOLE_FG_COL;
bgx = (CONSOLE_BG_COL << 16) | (CONSOLE_BG_COL << 8) | CONSOLE_BG_COL;
break;
case GDF_24BIT_888RGB:
fgx = (CONSOLE_FG_COL << 24) | (CONSOLE_FG_COL << 16) |
(CONSOLE_FG_COL << 8) | CONSOLE_FG_COL;
bgx = (CONSOLE_BG_COL << 24) | (CONSOLE_BG_COL << 16) |
(CONSOLE_BG_COL << 8) | CONSOLE_BG_COL;
break;
}
eorx = fgx ^ bgx;
#ifdef CONFIG_VIDEO_LOGO
/* Plot the logo and get start point of console */
PRINTD ("Video: Drawing the logo ...\n");
video_console_address =
video_logo ();//显示LOGO
#else
video_console_address = video_fb_address;
#endif
/* Initialize the console */
console_col = 0;
console_row = 0;
return 0;
}
在driver/video/s3c2410_fb.c中
void *video_hw_init (void)
{
struct s3c24x0_lcd * const lcd = s3c24x0_get_base_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初始化下面是直接赋值所以上面的没用**/
//pGD->winSizeX = pGD->plnSizeX = 240;
//pGD->winSizeY = pGD->plnSizeY = 320;
pGD->winSizeX = pGD->plnSizeX = 320;
pGD->winSizeY = pGD->plnSizeY = 240;
pGD->gdfBytesPP = 2;
pGD->gdfIndex = GDF_16BIT_565RGB;
pGD->frameAdrs = LCD_VIDEO_ADDR;
pGD->memSize = VIDEO_MEM_SIZE;
board_video_init(pGD);//配置控制寄存器数值
//*******下面初始化LCD的地址寄存器*********//
writel((pGD->frameAdrs >> 1), &lcd->LCDSADDR1);
/* This marks the end of the frame buffer. */
writel((((readl(&lcd->LCDSADDR1))&0x1fffff) + (pGD->winSizeX+0) * pGD->winSizeY), &lcd->LCDSADDR2);
writel((pGD->winSizeX & 0x7ff), &lcd->LCDSADDR3);
/* Clear video memory */
memset((void *)pGD->frameAdrs, 0, pGD->memSize);
/* Enable Display */
writel((readl(&lcd->LCDCON1) | 0x01), & lcd->LCDCON1); /* ENVID = 1 */
return ((void*)&smi);
}
在cfb_console.c中
static void *video_logo (void)
{
char info[128];
extern char version_string;
int space, len, y_off = 0;
#ifdef CONFIG_SPLASH_SCREEN
char *s;
ulong addr;
if ((s = getenv ("splashimage")) != NULL) {
int x = 0, y = 0;
addr = simple_strtoul (s, NULL, 16);
#ifdef CONFIG_SPLASH_SCREEN_ALIGN
if ((s = getenv ("splashpos")) != NULL) {
if (s[0] == 'm')
x = BMP_ALIGN_CENTER;
else
x = simple_strtol (s, NULL, 0);
if ((s = strchr (s + 1, ',')) != NULL) {
if (s[1] == 'm')
y = BMP_ALIGN_CENTER;
else
y = simple_strtol (s + 1, NULL, 0);
}
}
#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
if (video_display_bitmap (addr, x, y) == 0) {
video_logo_height = 0;
return ((void *) (video_fb_address));
}
}
#endif /* CONFIG_SPLASH_SCREEN */
logo_plot (video_fb_address, VIDEO_COLS, 0, 0);//此函数是真正的显示LOGO函数可以改变X,Y改变LOGO位置
sprintf (info, " %s", &version_string);
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);
#ifdef CONFIG_CONSOLE_EXTRA_INFO
{
int i, n = ((video_logo_height - VIDEO_FONT_HEIGHT) / VIDEO_FONT_HEIGHT);
for (i = 1; i < n; i++) {
video_get_info_str (i, info);
if (!*info)
continue;
len = strlen(info);
if (len > space) {
video_drawchars (VIDEO_INFO_X,
VIDEO_INFO_Y +
(i + y_off) * VIDEO_FONT_HEIGHT,
(uchar *)info, space);
y_off++;
video_drawchars (VIDEO_INFO_X + VIDEO_FONT_WIDTH,
VIDEO_INFO_Y +
(i + y_off) * VIDEO_FONT_HEIGHT,
(uchar *)info + space,
len - space);
} else {
video_drawstring (VIDEO_INFO_X,
VIDEO_INFO_Y +
(i + y_off) * VIDEO_FONT_HEIGHT,
(uchar *)info);
}
}
}
#endif
return (video_fb_address + video_logo_height * VIDEO_LINE_LEN);
}
#endif
下面总结一下
board.c
board_init()
stdio_init()------------>
common/stdio.c
drv_video_init ()--------->
driver/video/cfb_console.c
video_init ()--->video_hw_init ()-------->
board/embedclu/smdk2440/smdk2440ac
board_video_init(pGD)
video_logo ()-->logo_plot (video_fb_address, VIDEO_COLS, 0, 0);
修改u-boot的开机logo其实很简单。请见下面步骤。
1. 获取一张BMP的图片,修改之,让其色深必须为8位,即256色,如果用24位,则显示出问题,(至于是否能用24位,有待深究)。
2. 将制作好的BMP图片,放置到<u-boot>/tools/logos下面。
3. 修改<u-boot>/tools/Makefile中的LOGO_BMP,使其指向你的bmp图片。如:LOGO_BMP= logos/test.bmp (此名应该放到:LOGO_BMP赋值的最后,否则会被覆盖掉)
----------------------------------------------------------------------------
ifeq ($(LOGO_BMP),)
LOGO_BMP= logos/denx.bmp
endif
<snip>
ifeq ($(VENDOR),intercontrol)
LOGO_BMP= logos/intercontrol.bmp
endif
LOGO_BMP= logos/test.bmp
----------------------------------------------------------------------------
注:此处的VENDOR信息是从<boards.cfg>文件中来。
重新编译u-boot, 生成u-boot.bin,然后放到板子上进行测试。
如果定义了VIDEO_LOGO和VIDEO_BMP_LOGO
编译时会执行tools目录下的bmp_logo程序,读取"tools/logos/denx.bmp"文件,在include下生成bmp_logo.h文件
文件内容如下:
#define BMP_LOGO_WIDTH 160
#define BMP_LOGO_HEIGHT 96
#define BMP_LOGO_COLORS 31
#define BMP_LOGO_OFFSET 16
unsigned short bmp_logo_palette[] = {
.......................
};
unsigned char bmp_logo_bitmap[] = {
.......................
};
显示logo函数就会调用这个数组中的数据,显示到屏上
在cfb_console.c中定义了LOGO的属性
#define VIDEO_LOGO_WIDTH BMP_LOGO_WIDTH
#define VIDEO_LOGO_HEIGHT BMP_LOGO_HEIGHT
#define VIDEO_LOGO_LUT_OFFSET BMP_LOGO_OFFSET
#define VIDEO_LOGO_COLORS BMP_LOGO_COLORS
这个bmp文件是有要求的,位深度必须为8位,大小也有限制(全屏图片肯定是不行的,读取文件的后半部数据都是0)
自己做个logo图片,jpeg格式就可以,使用linux下的图片工具转成8位的bmp文件
u-boot的启动流程:从文件层面上看主要流程是在两个文件中:cpu/arm920t/start.s,lib_arm/board.c,
其中start.s
是用汇编写的初始化cpu的堆栈 中断向量 时钟频率 SDRAM,并把c部分的代码从nand flash拷贝到SDRAM中,board.c的代码主要是初始化各外设比如串口 i2c LCD等,所以LCD驱动的开始在board.c中。下面分析board.c的部分源码
typedef
int (init_fnc_t) (void);//定义一个函数数据类型
int print_cpuinfo (void);
/***一个函数数组里面是各种初始化函数***/
init_fnc_t *init_sequence[] = {
#if defined(CONFIG_ARCH_CPU_INIT)
arch_cpu_init,/* basic arch cpu dependent setup */
#endif
board_init,/*
初始化开发板的相关外设 下面会详细分析 */
#if defined(CONFIG_USE_IRQ)
interrupt_init,/* set up exceptions */
#endif
timer_init,/* initialize timer */
#ifdef CONFIG_FSL_ESDHC
get_clocks,
#endif
env_init,/* initialize environment */
init_baudrate,/* initialze baudrate settings */
serial_init,/* serial communications setup */
console_init_f,/* stage 1 init of console */
display_banner,/* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo,/* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard,/* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
init_func_i2c,
#endif
dram_init,/* configure available RAM banks */
#if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)
arm_pci_init,
#endif
display_dram_config,
NULL,
};
/*******c入口*******/
void start_armboot (void)
{
init_fnc_t **init_fnc_ptr;//定义一个init_fnc_t类型的指针
char *s;
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
unsigned long addr;
#endif
/* Pointer is writable since we allocated a register for it */
gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));//u-boot的全局变量存储各种信息
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");
memset ((void*)gd, 0, sizeof (gd_t));
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));
gd->flags |= GD_FLG_RELOC;
monitor_flash_len = _bss_start - _armboot_start;
/******************下面这个循环将上面数组的函数都执行一遍********************/
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
/* armboot_start is defined in the board-specific linker script */
mem_malloc_init (_armboot_start - CONFIG_SYS_MALLOC_LEN,
CONFIG_SYS_MALLOC_LEN);
#ifndef CONFIG_SYS_NO_FLASH
/* configure available FLASH banks */
display_flash_config (flash_init ());
#endif /* CONFIG_SYS_NO_FLASH */
#ifdef CONFIG_VFD
#ifndef PAGE_SIZE
# define PAGE_SIZE 4096
#endif
/*
* reserve memory for VFD display (always full pages)
*/
/* bss_end is defined in the board-specific linker script */
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
vfd_setmem (addr);
gd->fb_base = addr;
#endif /* CONFIG_VFD */
#ifdef CONFIG_LCD
/* board init may have inited fb_base */
if (!gd->fb_base) {
#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);
lcd_setmem (addr);
gd->fb_base = addr;
}
#endif /* CONFIG_LCD */
#if defined(CONFIG_CMD_NAND)
puts ("NAND: ");
nand_init();/* go init the NAND */
#endif
#if defined(CONFIG_CMD_ONENAND)
onenand_init();
#endif
#ifdef CONFIG_HAS_DATAFLASH
AT91F_DataflashInit();
dataflash_print_info();
#endif
/* initialize environment */
env_relocate ();
#ifdef CONFIG_VFD
/* must do this after the framebuffer is allocated */
drv_vfd_init();//mini2440的LCD初始化和此函数无关
#endif
/* CONFIG_VFD */
#ifdef CONFIG_SERIAL_MULTI
serial_initialize();
#endif
/* IP Address */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
stdio_init ();/* 初始化设备列表mini2440LCD设备初始化就在这里
下面会详细分析此函数*/
jumptable_init ();
#if defined(CONFIG_API)
/* Initialize API */
api_init ();
#endif
cosole_init_r ();/* fully init console as a device */
#if defined(CONFIG_ARCH_MISC_INIT)
/* miscellaneous arch dependent initialisations */
arch_misc_init ();
#endif
#if defined(CONFIG_MISC_INIT_R)
/* miscellaneous platform dependent initialisations */
misc_init_r ();
#endif
// extern void Port_Init(void);
// Port_Init();
/* enable exceptions */
enable_interrupts ();
extern int usb_init_slave(void);
usb_init_slave();
/* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_TI_EMAC
/* XXX: this needs to be moved to board init */
extern void davinci_eth_set_mac_addr (const u_int8_t *addr);
if (getenv ("ethaddr")) {
uchar enetaddr[6];
eth_getenv_enetaddr("ethaddr", enetaddr);
davinci_eth_set_mac_addr(enetaddr);
}
#endif
#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
/* XXX: this needs to be moved to board init */
if (getenv ("ethaddr")) {
uchar enetaddr[6];
eth_getenv_enetaddr("ethaddr", enetaddr);
smc_set_mac_addr(enetaddr);
}
#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */
/* Initialize from environment */
if ((s = getenv ("loadaddr")) != NULL) {
load_addr = simple_strtoul (s, NULL, 16);
}
#if defined(CONFIG_CMD_NET)
if ((s = getenv ("bootfile")) != NULL) {
copy_filename (BootFile, s, sizeof (BootFile));
}
#endif
#ifdef BOARD_LATE_INIT
board_late_init ();
#endif
#ifdef CONFIG_GENERIC_MMC
puts ("MMC: ");
mmc_initialize (gd->bd);
#endif
#ifdef CONFIG_BITBANGMII
bb_miiphy_init();
#endif
#if defined(CONFIG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
puts ("Net: ");
#endif
eth_initialize(gd->bd);
#if defined(CONFIG_RESET_PHY_R)
debug ("Reset Ethernet PHY\n");
reset_phy();
#endif
#endif
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop ();
}
/* NOTREACHED - no way out of command loop except booting */
}
以上是board.c中源码的分析,下面将介绍和lcd相关的上面提到的board_init()和stadio_init()函数
在board/embedclub/smdk2440a/smdk2440a.c文件中
//*****************以下部分是我的LCD模组SPI初始化代码,如果大家的不用初始化则没有此部分*********/
#define LCD_CS_SHIFT 5
#define LCD_CLK_SHIFT 4
#define LCD_DAT_SHIFT 6
#define LCD_RST_SHIFT 0
static void set_cs(int cs)
{
struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
int reg;
reg = gpio->GPFDAT;
reg &= ~(0x1 << LCD_CS_SHIFT);
reg |= (cs << LCD_CS_SHIFT);
gpio->GPFDAT = reg;
}
static void set_clk(int clk)
{
struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
int reg;
reg = gpio->GPFDAT;
reg &= ~(0x1 << LCD_CLK_SHIFT);
reg |= (clk << LCD_CLK_SHIFT);
gpio->GPFDAT = reg;
}
static void set_sdi(int outdata)
{
struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
int reg;
reg = gpio->GPFDAT;
reg &= ~(0x1 << LCD_DAT_SHIFT);
reg |= (outdata << LCD_DAT_SHIFT);
gpio->GPFDAT = reg;
}
static void set_res(int res)
{
struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
int reg;
reg = gpio->GPFDAT;
reg &= ~(0x1 << LCD_RST_SHIFT);
reg |= (res << LCD_RST_SHIFT);
gpio->GPFDAT = reg;
}
static void lcd_reset()
{
set_res(1);
udelay(20000);
set_res(0);
udelay(10000);
set_res(1);
udelay(120000);
}
static chushihua_gpio(void)
{
set_cs(1);
set_clk(1);
set_sdi(1);
set_res(1);
udelay(10000);
}
static void send_cmd(unsigned char cmd)
{
unsigned char i;
set_cs(0);
udelay(10);
set_clk(0);
set_sdi(0);
udelay(100);
set_clk(1);
udelay(100);
for(i=0;i<8;i++)
{
set_clk(0);
if (cmd&0x80)
{
set_sdi(1);
}
else
{
set_sdi(0);
}
udelay(100);
set_clk(1);
udelay(100);
cmd=cmd<<1;
}
set_cs(1);
udelay(10);
}
static void send_date(unsigned char date)
{
unsigned char i;
set_cs(0);
udelay(10);
set_clk(0);
set_sdi(1);
udelay(100);
set_clk(1);
udelay(100);
for(i=0;i<8;i++)
{
set_clk(0);
if (date&0x80)
{
set_sdi(1);
}
else
{
set_sdi(0);
}
udelay(100);
set_clk(1);
udelay(100);
date=date<<1;
}
set_cs(1);
udelay(10);
}
static void set_hx8369(void)
{
lcd_reset(); //Set_EXTC
send_cmd(0xB9); // SET password
send_date(0xFF);
send_date(0x83);
send_date(0x69);
send_cmd(0xB1); //Set Power
send_date(0x01);
send_date(0x00);
send_date(0x34);
send_date(0x06);
send_date(0x00);
send_date(0x11);
send_date(0x11);
send_date(0x2A);
send_date(0x32);
send_date(0x3F);
send_date(0x3F);
send_date(0x07);
send_date(0x23);
send_date(0x01);
send_date(0xE6);
send_date(0xE6);
send_date(0xE6);
send_date(0xE6);
send_date(0xE6);
udelay(120000);
send_cmd(0xB2); // SET Display 480x800
send_date(0x00);
send_date(0x2B);
send_date(0x03);
send_date(0x03);
send_date(0x70);
send_date(0x00);
send_date(0xFF);
send_date(0x00);
send_date(0x00);
send_date(0x00);
send_date(0x00);
send_date(0x03);
send_date(0x03);
send_date(0x00);
send_date(0x01);
send_cmd(0xB4); // SET Display 480x800
send_date(0x00);
send_date(0x0C);
send_date(0xA0);
send_date(0x0E);
send_date(0x06);
send_cmd(0xB6); // SET VCOM
send_date(0x35);
send_date(0x35);
udelay(120000);
send_cmd(0xD5); // SET GIP
send_date(0x00);
send_date(0x05);
send_date(0x03);
send_date(0x00);
send_date(0x01);
send_date(0x09);
send_date(0x10);
send_date(0x80);
send_date(0x37);
send_date(0x37);
send_date(0x20);
send_date(0x31);
send_date(0x46);
send_date(0x8A);
send_date(0x57);
send_date(0x9B);
send_date(0x20);
send_date(0x31);
send_date(0x46);
send_date(0x8A);
send_date(0x57);
send_date(0x9B);
send_date(0x07);
send_date(0x0F);
send_date(0x02);
send_date(0x00);
send_cmd(0xE0); // SET Gamma
send_date(0x00);
send_date(0x08);
send_date(0x0D);
send_date(0x2D);
send_date(0x34);
send_date(0x3F);
send_date(0x19);
send_date(0x38);
send_date(0x09);
send_date(0x0E);
send_date(0x0E);
send_date(0x12);
send_date(0x14);
send_date(0x12);
send_date(0x14);
send_date(0x13);
send_date(0x19);
send_date(0x00);
send_date(0x08);
send_date(0x0D);
send_date(0x2D);
send_date(0x34);
send_date(0x3F);
send_date(0x19);
send_date(0x38);
send_date(0x09);
send_date(0x0E);
send_date(0x0E);
send_date(0x12);
send_date(0x14);
send_date(0x12);
send_date(0x14);
send_date(0x13);
send_date(0x19);
udelay(120000);
send_cmd(0xC1);
send_date(0x01); //enable DGC function
send_date(0x02); //SET R-GAMMA
send_date(0x08);
send_date(0x12);
send_date(0x1A);
send_date(0x22);
send_date(0x2A);
send_date(0x31);
send_date(0x36);
send_date(0x3F);
send_date(0x48);
send_date(0x51);
send_date(0x58);
send_date(0x60);
send_date(0x68);
send_date(0x70);
send_date(0x78);
send_date(0x80);
send_date(0x88);
send_date(0x90);
send_date(0x98);
send_date(0xA0);
send_date(0xA7);
send_date(0xAF);
send_date(0xB6);
send_date(0xBE);
send_date(0xC7);
send_date(0xCE);
send_date(0xD6);
send_date(0xDE);
send_date(0xE6);
send_date(0xEF);
send_date(0xF5);
send_date(0xFB);
send_date(0xFC);
send_date(0xFE);
send_date(0x8C);
send_date(0xA4);
send_date(0x19);
send_date(0xEC);
send_date(0x1B);
send_date(0x4C);
send_date(0x40);
send_date(0x02); //SET G-Gamma
send_date(0x08);
send_date(0x12);
send_date(0x1A);
send_date(0x22);
send_date(0x2A);
send_date(0x31);
send_date(0x36);
send_date(0x3F);
send_date(0x48);
send_date(0x51);
send_date(0x58);
send_date(0x60);
send_date(0x68);
send_date(0x70);
send_date(0x78);
send_date(0x80);
send_date(0x88);
send_date(0x90);
send_date(0x98);
send_date(0xA0);
send_date(0xA7);
send_date(0xAF);
send_date(0xB6);
send_date(0xBE);
send_date(0xC7);
send_date(0xCE);
send_date(0xD6);
send_date(0xDE);
send_date(0xE6);
send_date(0xEF);
send_date(0xF5);
send_date(0xFB);
send_date(0xFC);
send_date(0xFE);
send_date(0x8C);
send_date(0xA4);
send_date(0x19);
send_date(0xEC);
send_date(0x1B);
send_date(0x4C);
send_date(0x40);
send_date(0x02); //SET B-Gamma
send_date(0x08);
send_date(0x12);
send_date(0x1A);
send_date(0x22);
send_date(0x2A);
send_date(0x31);
send_date(0x36);
send_date(0x3F);
send_date(0x48);
send_date(0x51);
send_date(0x58);
send_date(0x60);
send_date(0x68);
send_date(0x70);
send_date(0x78);
send_date(0x80);
send_date(0x88);
send_date(0x90);
send_date(0x98);
send_date(0xA0);
send_date(0xA7);
send_date(0xAF);
send_date(0xB6);
send_date(0xBE);
send_date(0xC7);
send_date(0xCE);
send_date(0xD6);
send_date(0xDE);
send_date(0xE6);
send_date(0xEF);
send_date(0xF5);
send_date(0xFB);
send_date(0xFC);
send_date(0xFE);
send_date(0x8C);
send_date(0xA4);
send_date(0x19);
send_date(0xEC);
send_date(0x1B);
send_date(0x4C);
send_date(0x40);
send_cmd(0x3A);
send_date(0x55);
send_cmd(0x11);
udelay(120000);
send_cmd(0x29);
send_cmd(0x2c);
}
void lcd_config()
{
chushihua_gpio();
set_hx8369();
}
/*****************以上部分是我的LCD模组SPI初始化代码,如果大家的不用初始化则没有此部分*********/
int board_init (void)//初始化时钟IO等,我在此处初始化LCD
{
struct s3c24x0_clock_power * const clk_power =
s3c24x0_get_base_clock_power();
struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
/* to reduce PLL lock time, adjust the LOCKTIME register */
clk_power->LOCKTIME = 0xFFFFFF;
/* configure MPLL */
clk_power->MPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV);
/* some delay between MPLL and UPLL */
delay (4000);
/* configure UPLL */
clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV);
/* some delay between MPLL and UPLL */
delay (8000);
/* set up the I/O ports */
gpio->GPACON = 0x007FFFFF;
#if defined(CONFIG_SMDK2440)
gpio->GPBCON = 0x00295551;
#else
gpio->GPBCON = 0x00044556;
#endif
gpio->GPBUP = 0x000007FF;
#if defined(CONFIG_SMDK2440)
gpio->GPCCON = 0xAAAAA6AA;
gpio->GPCDAT &= ~(1<<5);
#else
gpio->GPCCON = 0xAAAAAAAA;
#endif
gpio->GPCUP = 0xFFFFFFFF;
gpio->GPDCON = 0xAAAAAAAA;
gpio->GPDUP = 0xFFFFFFFF;
gpio->GPECON = 0xAAAAAAAA;
gpio->GPEUP = 0x0000FFFF;
gpio->GPFCON = 0x000055AA;
gpio->GPFUP = 0x000000FF;
gpio->GPGCON = 0xFF95FF3A;
gpio->GPGUP = 0x0000FFFF;
gpio->GPHCON = 0x0016FAAA;
gpio->GPHUP = 0x000007FF;
gpio->EXTINT0=0x22222222;
gpio->EXTINT1=0x22222222;
gpio->EXTINT2=0x22222222;
#if defined(CONFIG_S3C2410)
/* arch number of SMDK2410-Board */
gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
#endif
#if defined(CONFIG_S3C2440)
/* arch number of S3C2440-Board */
gd->bd->bi_arch_number = MACH_TYPE_SMDK2440A;
//gd->bd->bi_arch_number = 782;
#endif
//printf("Start Linux parameters at 0x30000100\n");
//printf("MACH_TYPE=%d\n", gd->bd->bi_arch_number);
//printf("Linux command line is: %s\n",CONFIG_BOOTARGS);
/* adress of boot parameters */
gd->bd->bi_boot_params = 0x30000100;
icache_enable();
dcache_enable();
lcd_config() ;//此处初始化lcd的配置
如果大家不用初始化LCD,则不必关心board_init函数
return 0;
}
在common/stadio.c中
int
stdio_init (void) //初始化板子的外设
{
#if !defined(CONFIG_RELOC_FIXUP_WORKS)
/* already relocated for current ARM implementation */
ulong relocation_offset = gd->reloc_off;
int i;
/* relocate device name pointers */
for (i = 0; i < (sizeof (stdio_names) / sizeof (char *)); ++i) {
stdio_names[i] = (char *) (((ulong) stdio_names[i]) +
relocation_offset);
}
#endif /* !CONFIG_RELOC_FIXUP_WORKS */
/* Initialize the list */
INIT_LIST_HEAD(&(devs.list));
#ifdef CONFIG_ARM_DCC_MULTI
drv_arm_dcc_init ();
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
#endif
#ifdef CONFIG_LCD
drv_lcd_init ();//和mini2440LCD无关
#endif
#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
drv_video_init ();//此函数初始化mini2440的LCD控制器以及显示LOGO
#endif
#ifdef CONFIG_KEYBOARD
drv_keyboard_init ();
#endif
#ifdef CONFIG_LOGBUFFER
drv_logbuff_init ();
#endif
drv_system_init ();
#ifdef CONFIG_SERIAL_MULTI
serial_stdio_init ();
#endif
#ifdef CONFIG_USB_TTY
drv_usbtty_init ();
#endif
#ifdef CONFIG_NETCONSOLE
drv_nc_init ();
#endif
#ifdef CONFIG_JTAG_CONSOLE
drv_jtag_console_init ();
#endif
return (0);
}
下面介绍drv_video_init
()函数
在driver/video/cfb_console.c
int drv_video_init (void) //初始化LCD控制器并显示LOGO
{
int skip_dev_init;
struct stdio_dev console_dev;
/* Check if video initialization should be skipped */
if (board_video_skip())
return 0;
/* Init video chip - returns with framebuffer cleared */
skip_dev_init = (video_init ()== -1);//初始化LCD控制器并显示LOGO
#if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
PRINTD ("KBD: Keyboard init ...\n");
skip_dev_init |= (VIDEO_KBD_INIT_FCT == -1);
#endif
if (skip_dev_init)
return 0;
/* Init vga device */
memset (&console_dev, 0, sizeof (console_dev));
strcpy (console_dev.name, "vga");
console_dev.ext = DEV_EXT_VIDEO;/* Video extensions */
console_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_SYSTEM;
console_dev.putc = video_putc;/* 'putc' function */
console_dev.puts = video_puts;/* 'puts' function */
console_dev.tstc = NULL;/* 'tstc' function */
console_dev.getc = NULL;/* 'getc' function */
#if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
/* Also init console device */
console_dev.flags |= DEV_FLAGS_INPUT;
console_dev.tstc = VIDEO_TSTC_FCT;/* 'tstc' function */
console_dev.getc = VIDEO_GETC_FCT;/* 'getc' function */
#endif /* CONFIG_VGA_AS_SINGLE_DEVICE */
if (stdio_register (&console_dev) != 0)
return 0;
/* Return success */
return 1;
下面介绍video_init ()也在cfb_console.c中
static int video_init (void)
{
unsigned char color8;
if ((pGD = video_hw_init ()) == NULL)//配置LCD控制寄存器数值
return -1;
video_fb_address = (void *) VIDEO_FB_ADRS;
#ifdef CONFIG_VIDEO_HW_CURSOR
video_init_hw_cursor (VIDEO_FONT_WIDTH, VIDEO_FONT_HEIGHT);
#endif
/* Init drawing pats */
switch (VIDEO_DATA_FORMAT) {
case GDF__8BIT_INDEX:
video_set_lut (0x01, CONSOLE_FG_COL, CONSOLE_FG_COL, CONSOLE_FG_COL);
video_set_lut (0x00, CONSOLE_BG_COL, CONSOLE_BG_COL, CONSOLE_BG_COL);
fgx = 0x01010101;
bgx = 0x00000000;
break;
case GDF__8BIT_332RGB:
color8 = ((CONSOLE_FG_COL & 0xe0) |
((CONSOLE_FG_COL >> 3) & 0x1c) | CONSOLE_FG_COL >> 6);
fgx = (color8 << 24) | (color8 << 16) | (color8 << 8) | color8;
color8 = ((CONSOLE_BG_COL & 0xe0) |
((CONSOLE_BG_COL >> 3) & 0x1c) | CONSOLE_BG_COL >> 6);
bgx = (color8 << 24) | (color8 << 16) | (color8 << 8) | color8;
break;
case GDF_15BIT_555RGB:
fgx = (((CONSOLE_FG_COL >> 3) << 26) |
((CONSOLE_FG_COL >> 3) << 21) | ((CONSOLE_FG_COL >> 3) << 16) |
((CONSOLE_FG_COL >> 3) << 10) | ((CONSOLE_FG_COL >> 3) << 5) |
(CONSOLE_FG_COL >> 3));
bgx = (((CONSOLE_BG_COL >> 3) << 26) |
((CONSOLE_BG_COL >> 3) << 21) | ((CONSOLE_BG_COL >> 3) << 16) |
((CONSOLE_BG_COL >> 3) << 10) | ((CONSOLE_BG_COL >> 3) << 5) |
(CONSOLE_BG_COL >> 3));
break;
case GDF_16BIT_565RGB:
fgx = (((CONSOLE_FG_COL >> 3) << 27) |
((CONSOLE_FG_COL >> 2) << 21) | ((CONSOLE_FG_COL >> 3) << 16) |
((CONSOLE_FG_COL >> 3) << 11) | ((CONSOLE_FG_COL >> 2) << 5) |
(CONSOLE_FG_COL >> 3));
bgx = (((CONSOLE_BG_COL >> 3) << 27) |
((CONSOLE_BG_COL >> 2) << 21) | ((CONSOLE_BG_COL >> 3) << 16) |
((CONSOLE_BG_COL >> 3) << 11) | ((CONSOLE_BG_COL >> 2) << 5) |
(CONSOLE_BG_COL >> 3));
break;
case GDF_32BIT_X888RGB:
fgx = (CONSOLE_FG_COL << 16) | (CONSOLE_FG_COL << 8) | CONSOLE_FG_COL;
bgx = (CONSOLE_BG_COL << 16) | (CONSOLE_BG_COL << 8) | CONSOLE_BG_COL;
break;
case GDF_24BIT_888RGB:
fgx = (CONSOLE_FG_COL << 24) | (CONSOLE_FG_COL << 16) |
(CONSOLE_FG_COL << 8) | CONSOLE_FG_COL;
bgx = (CONSOLE_BG_COL << 24) | (CONSOLE_BG_COL << 16) |
(CONSOLE_BG_COL << 8) | CONSOLE_BG_COL;
break;
}
eorx = fgx ^ bgx;
#ifdef CONFIG_VIDEO_LOGO
/* Plot the logo and get start point of console */
PRINTD ("Video: Drawing the logo ...\n");
video_console_address =
video_logo ();//显示LOGO
#else
video_console_address = video_fb_address;
#endif
/* Initialize the console */
console_col = 0;
console_row = 0;
return 0;
}
在driver/video/s3c2410_fb.c中
void *video_hw_init (void)
{
struct s3c24x0_lcd * const lcd = s3c24x0_get_base_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初始化下面是直接赋值所以上面的没用**/
//pGD->winSizeX = pGD->plnSizeX = 240;
//pGD->winSizeY = pGD->plnSizeY = 320;
pGD->winSizeX = pGD->plnSizeX = 320;
pGD->winSizeY = pGD->plnSizeY = 240;
pGD->gdfBytesPP = 2;
pGD->gdfIndex = GDF_16BIT_565RGB;
pGD->frameAdrs = LCD_VIDEO_ADDR;
pGD->memSize = VIDEO_MEM_SIZE;
board_video_init(pGD);//配置控制寄存器数值
//*******下面初始化LCD的地址寄存器*********//
writel((pGD->frameAdrs >> 1), &lcd->LCDSADDR1);
/* This marks the end of the frame buffer. */
writel((((readl(&lcd->LCDSADDR1))&0x1fffff) + (pGD->winSizeX+0) * pGD->winSizeY), &lcd->LCDSADDR2);
writel((pGD->winSizeX & 0x7ff), &lcd->LCDSADDR3);
/* Clear video memory */
memset((void *)pGD->frameAdrs, 0, pGD->memSize);
/* Enable Display */
writel((readl(&lcd->LCDCON1) | 0x01), & lcd->LCDCON1); /* ENVID = 1 */
return ((void*)&smi);
}
在cfb_console.c中
static void *video_logo (void)
{
char info[128];
extern char version_string;
int space, len, y_off = 0;
#ifdef CONFIG_SPLASH_SCREEN
char *s;
ulong addr;
if ((s = getenv ("splashimage")) != NULL) {
int x = 0, y = 0;
addr = simple_strtoul (s, NULL, 16);
#ifdef CONFIG_SPLASH_SCREEN_ALIGN
if ((s = getenv ("splashpos")) != NULL) {
if (s[0] == 'm')
x = BMP_ALIGN_CENTER;
else
x = simple_strtol (s, NULL, 0);
if ((s = strchr (s + 1, ',')) != NULL) {
if (s[1] == 'm')
y = BMP_ALIGN_CENTER;
else
y = simple_strtol (s + 1, NULL, 0);
}
}
#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
if (video_display_bitmap (addr, x, y) == 0) {
video_logo_height = 0;
return ((void *) (video_fb_address));
}
}
#endif /* CONFIG_SPLASH_SCREEN */
logo_plot (video_fb_address, VIDEO_COLS, 0, 0);//此函数是真正的显示LOGO函数可以改变X,Y改变LOGO位置
sprintf (info, " %s", &version_string);
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);
#ifdef CONFIG_CONSOLE_EXTRA_INFO
{
int i, n = ((video_logo_height - VIDEO_FONT_HEIGHT) / VIDEO_FONT_HEIGHT);
for (i = 1; i < n; i++) {
video_get_info_str (i, info);
if (!*info)
continue;
len = strlen(info);
if (len > space) {
video_drawchars (VIDEO_INFO_X,
VIDEO_INFO_Y +
(i + y_off) * VIDEO_FONT_HEIGHT,
(uchar *)info, space);
y_off++;
video_drawchars (VIDEO_INFO_X + VIDEO_FONT_WIDTH,
VIDEO_INFO_Y +
(i + y_off) * VIDEO_FONT_HEIGHT,
(uchar *)info + space,
len - space);
} else {
video_drawstring (VIDEO_INFO_X,
VIDEO_INFO_Y +
(i + y_off) * VIDEO_FONT_HEIGHT,
(uchar *)info);
}
}
}
#endif
return (video_fb_address + video_logo_height * VIDEO_LINE_LEN);
}
#endif
下面总结一下
board.c
board_init()
stdio_init()------------>
common/stdio.c
drv_video_init ()--------->
driver/video/cfb_console.c
video_init ()--->video_hw_init ()-------->
board/embedclu/smdk2440/smdk2440ac
board_video_init(pGD)
video_logo ()-->logo_plot (video_fb_address, VIDEO_COLS, 0, 0);
修改u-boot的开机logo其实很简单。请见下面步骤。
1. 获取一张BMP的图片,修改之,让其色深必须为8位,即256色,如果用24位,则显示出问题,(至于是否能用24位,有待深究)。
2. 将制作好的BMP图片,放置到<u-boot>/tools/logos下面。
3. 修改<u-boot>/tools/Makefile中的LOGO_BMP,使其指向你的bmp图片。如:LOGO_BMP= logos/test.bmp (此名应该放到:LOGO_BMP赋值的最后,否则会被覆盖掉)
----------------------------------------------------------------------------
ifeq ($(LOGO_BMP),)
LOGO_BMP= logos/denx.bmp
endif
<snip>
ifeq ($(VENDOR),intercontrol)
LOGO_BMP= logos/intercontrol.bmp
endif
LOGO_BMP= logos/test.bmp
----------------------------------------------------------------------------
注:此处的VENDOR信息是从<boards.cfg>文件中来。
重新编译u-boot, 生成u-boot.bin,然后放到板子上进行测试。
如果定义了VIDEO_LOGO和VIDEO_BMP_LOGO
编译时会执行tools目录下的bmp_logo程序,读取"tools/logos/denx.bmp"文件,在include下生成bmp_logo.h文件
文件内容如下:
#define BMP_LOGO_WIDTH 160
#define BMP_LOGO_HEIGHT 96
#define BMP_LOGO_COLORS 31
#define BMP_LOGO_OFFSET 16
unsigned short bmp_logo_palette[] = {
.......................
};
unsigned char bmp_logo_bitmap[] = {
.......................
};
显示logo函数就会调用这个数组中的数据,显示到屏上
在cfb_console.c中定义了LOGO的属性
#define VIDEO_LOGO_WIDTH BMP_LOGO_WIDTH
#define VIDEO_LOGO_HEIGHT BMP_LOGO_HEIGHT
#define VIDEO_LOGO_LUT_OFFSET BMP_LOGO_OFFSET
#define VIDEO_LOGO_COLORS BMP_LOGO_COLORS
这个bmp文件是有要求的,位深度必须为8位,大小也有限制(全屏图片肯定是不行的,读取文件的后半部数据都是0)
自己做个logo图片,jpeg格式就可以,使用linux下的图片工具转成8位的bmp文件
相关文章推荐
- 基于s3c2440 lcd framebuffer 320x240 驱动 测试 显示 320x240 16bpp bmp 图片测试程序
- 制作uboot LCD开机logo以及lcd字符显示错误的解决方法
- 转:linux下 s3c2440 lcd驱动移植详解
- uboot2012 LCD驱动流程及机制分析
- RT-Thread 学习笔记(十一)--- 开启基于RTGUI的LCD显示功能(1)<LCD驱动接口移植>
- Ti-am335x-uboot-2015.07移植LCD显示logo功能
- 基于S3C6410&WINCE6.0的LCD驱动详解
- 基于S3C6410&WINCE6.0的LCD驱动详解
- RT-Thread 学习笔记(十三)--- 开启基于RTGUI的LCD显示功能(3)<触屏屏驱动移植和测试>
- S3C2440上LCD驱动(FrameBuffer)实例开发详解
- 基于S3c2440的LCD驱动
- S3C2440 LCD驱动详解
- 转:S3C2440上LCD驱动(FrameBuffer)实例开发详解
- u-boot下载模式LCD显示图片修改方法(基于TQ2440)
- s3c2440 LCD驱动,USB驱动,触摸屏以及ADC驱动移植
- Windows CE LCD显示驱动简析(2)(基于WinCE5.0 SMDK2410 BSP的LCD显示设备驱动)
- 基于S3C6410&WINCE6.0的LCD驱动详解
- linux下 s3c2440 lcd驱动移植详解
- 多CPU下基于e1000e驱动的数据包以及网卡中断流程分析.doc
- 基于STM32的OLED与TFTLCD详解1(IC驱动及FSMC初探)