由于默认的UBOOT不支持OMAPL138开机画面, 所以需要手动移植, 我的移植分为3个阶段, 前2个阶段都以失败告终, 如果不想耽误时间可以直接跳转到第3阶段处.
先说说环境 OMAPL138 软件以TI为主, 开发板是我们自己做的, 仿真器是闻亭的
第一阶段: 在TI官方提供的开发包里, 找到用CCS测试LCD 的程序, 将此程序稍作修改生成2个文件, my_lcd.h和my_lcd.c
MY_LCD.C ( 示意代码 ) |
#include "my_lcd.h" void mlz_usleep ( int n ) { 略 } void OMAPL138_lpscTransition(psc_regs_t *psc, unsigned int in_domain, unsigned char in_module, unsigned char in_next_state) { while (CHKBIT(psc->PTSTAT, in_domain)) {} ... 略 } unsigned int enable_lcdc( void ) { /* Enable the LCD Hardware */ OMAPL138_lpscTransition(PSC1, DOMAIN0, LPSC_LCDC, PSC_ENABLE); ... 略 return (ERR_NO_ERROR); } unsigned int raster_config( void ) { unsigned int x; unsigned short *pdata; LCDC->RASTER_CTRL &= 0xfffffffe; // Turn raster controller off return (ERR_NO_ERROR); ... 略 } unsigned int disable_lcdc( void ) {略} void RASTER_plot(unsigned short x, unsigned short y, unsigned short pixel_data) { *((unsigned short *)(FRAMEBUF_BASE + 32 + y * (LCD_WIDTH <<1) + (x << 1))) = pixel_data; } unsigned int RASTER_init(void) { int x,y; unsigned int rtn = ERR_NO_ERROR;
// enable power and setup lcdc. enable_lcdc(); raster_config();
mlz_usleep(300000); disable_lcdc();
mlz_usleep(100000);
// power-up the display kit following the correct sequence. // enable_lcd_power(); enable_lcdc(); mlz_usleep(300000); // enable_lcd_backlight();
for (x = 0; x < LCD_WIDTH; x++) for (y = 0; y < LCD_HEIGHT; y++) RASTER_plot(x, y, 0x55aa ); return (rtn); }
|
MY_LCD.H ( 示意代码 ) |
typedef struct { volatile unsigned int REVID; // 0x0000 } psc_regs_t; #define SETBIT(dest,mask) (dest |= mask) #define CLRBIT(dest,mask) (dest &= ~mask)
// define the power and sleep config modules. #define PSC0 ((psc_regs_t *)PSC0_REG_BASE) #define PSC1 ((psc_regs_t *)PSC1_REG_BASE)
//----------------------------------------------------------------------------- // power and sleep config registers typedef struct { volatile unsigned int REVID; // 0x0000 volatile unsigned int LCD_CTRL; // 0x0004 ... } lcdc_regs_t; #define LCDC ((lcdc_regs_t *)LCDC_REG_BASE)
#define LCDC_REG_BASE (0x01E13000) #define FRAMEBUF_BASE 0xc0000000
|
修改后把这2个文件放入common文件夹中, 并强制修改common文件夹的Makefile, 以生产my_lcd.o
然后在board/davinci/da8xxevm/da850evm.c中增加RASTER_init调用
int board_init(void) { Extern void RASTER_init ( void ); RASTER_init(); } |
开机, 应该出现整屏的蓝色, 但颜色变成了渐变色而且分成了好几块, 且一段时间后会花屏, 跟彩色电视机的雪花一样, 然后在linux的开机画面出现前1s, 出现了一个错位/缩小的linux开机画面.
第二阶段, 利用CONFIG_LCD
自己写驱动失败, 于是想利用UBOOT里的CONFIG_LCD和CONFIG_LCD_LOGO.于是寻找带这2个标记的代码段, 在添加这2个选项后 , 编译会报很多错, 主要因为需要指定一款LCD, 而UBOOT里没有对138的支持, 在 drvier/video里找到atmel 的驱动, 这个对LCD支持比较强, 准备在此基础上改, 把驱动的核心代码换成上面第一阶段的代码. 而思想就是对LCDC进行控制.此过程持续了2,3天, 最终因为关联东西太多而放弃.
第三阶段, 参考HAWK
在QQ群里有人提到了,http://code.google.com/p/hawkboard/downloads/list
作为TI的138的合作伙伴, hawkboard也出了开发板, 下载他的UBOOT代码,编译,可以看见启动画面了, 只是在uboot和linux直接会有1s的时间图像错位, 这点至今我也不会改.
Hawk的源代码在TI的基础上做了不大不小的改动, 在LCD方面, 他没有修改现有的驱动(如atmel), 也没有建立单独的c文件, 也就是说它没有用到 CONFIG_LCD选项. 他的思想和我的第一阶段比较相似, 直接写寄存器, 只不过他做的更简单,下面给出了我修改的文件:
文件名: board/davinci/da8xxevm/da850evm.c | |
修改说明: 写了一个LCDC初始化函数, 并在系统启动时调用, 写了一个画进度条函数, 以便在别的初始化时显示 LCDC初始化函数里, 对LCDC寄存器的初始化没有采用hawd的方式, 而是采用之前my_lcdc.c里面的参数, | |
修 改 内 容 | 增加 #include "uboot_logo.h" , 此文件存储开机画面图片, 后面介绍 |
增加 static int X1 = 117; //进度条外框 static int Y1 = 342; static int X2 = 497; static int Y2 = 362; | |
增加 #define LCDDMA_FB0_BASE 0xC3601000 - 32 //定义FB基地址, 范围 0xc0000000~0xc8000000 在这个地址中, -32 是为了将来画图直接从1000开始, 因为前32个字节是调色板, 而1000也是为了变成整数, 最重要的在0xc360xxxx, 以前在my_lcd里写成了0xc0000000, 因为在启动参数里将uImage调入0xc0700000, 而内核的入口地址是c0008000, 这就导致画面被冲, 结果也是如此, 在第一阶段load内核后,只有屏幕最上方的画面还在, 下面花屏了, 最上方正好对应 8000个字节 在HAWD的地址写成了c7200000, 我把它改成了36, 反正DDR的寻址是128M, 即c80000000, 而我的36M也没用, 所以没问题. 之前失败的时候还曾经试过0XA000000, 因为以前写DOS程序的时候FB就是a000000, 现在发现, 在UBOOT里, 这个基地址任意给, 只要在DDR的寻址范围内即可. | |
增加进度条显示函数 void DispLogoProgress ( int data ) { int i, j; int n = ( X2 - X1 - 6 ) / 100.0 * data*2 + X1 * 2;
for ( i = ( Y1 + 3 ) * 640 * 2 ; i < ( Y2 - 3 ) * 640 * 2; i += 2*640 ) for ( j = ( X1 + 3 ) * 2 ; j < n; j+= 2 ) *((volatile unsigned short *)(LCDDMA_FB0_BASE+32+i+j ) ) = 0xfc00; } | |
增加初始化LCDC函数 static void logo_init(void) { unsigned int i,k; unsigned char pixel[3]; int offset = 0; int ptr = 0;
*((volatile uint *) 0x01E13028) = 0x010000C0; //TURN_OFF RASTER_CTRL *((volatile uint *) LCDDMA_FB0_BASE) = 0x00004000; *((volatile uint *) 0x01E13004) = 0x00000801; //LCD_CTRL *((volatile uint *) 0x01E1302C) = (0x19 << 24) | (0x89 << 16) | (0x31 << 10) | (0x27 << 4);; //RASTER_TIMING_0 *((volatile uint *) 0x01E13030) = (0x1F << 24) | (0x20 <<16) | (0x02 <<10) | (0x1DF);; //RASTER_TIMING_1 *((volatile uint *) 0x01E13034) = 0x02700000 ; //RASTER_TIMING_2 *((volatile uint *) 0x01E13038) = 0x00000000; //RASTER_SUBPANEL *((volatile uint *) 0x01E13040) = 0x00000640; //LCDDMA_CTRL *((volatile uint *) 0x01E13044) = LCDDMA_FB0_BASE; //LCDDMA_FB0_BASE *((volatile uint *) 0x01E13048) = LCDDMA_FB0_BASE + 640*480*2 + 30; //LCDDMA_FB0_CEILING //画黑色背景 for (i = 0; i < (640*480*2); i+= 2) *((volatile unsigned short *)(LCDDMA_FB0_BASE+32 + i)) = 0x0;
//显示白色字体, log_buf里存的不是颜色, 而是白色的偏移量 for ( i = 0 ; i < 4608 ; i++ ) *((volatile unsigned short *)(LCDDMA_FB0_BASE+32 + logo_buf[i] ) ) = 0xffff; // //显示进度条框 for ( i = Y1*640*2+X1*2 ; i < Y1*640*2+X2*2; i+= 2 ) //横线 *((volatile unsigned short *)(LCDDMA_FB0_BASE+32 + i)) = 0xfc00; for ( i = Y2*640*2+X1*2 ; i < Y2*640*2+X2*2; i+= 2 ) *((volatile unsigned short *)(LCDDMA_FB0_BASE+32 + i)) = 0xfc00; 这里有2点值得注意, 一是一开始TURN_OFF RASTER_CTRL然后对LCDC寄存器初始化, 在my_lcd.c里, 初始化结束后要再打开这个CTRL, 然后就可以写屏了, 但HAWD把它放到了后面(下文提到), 我把它放到这里屏幕不正常. 二是LCDDMA_CTRL的默认值, MY_lcd.C里是0x20, 而通过调试发现, uboot实际启动时, 此参数是640, 而hawd是540, 而不论哪个值, 都会在uboot和linux切换的1s左右会有闪屏, 但640 闪的小些, 这个问题暂时无法解决. | |
增加logo_init调用logo_init int board_init(void) { logo_init(); Return 0; } | |
增加代码, 关闭LCDC int misc_init_r(void) { dspwake(); *((volatile uint *) 0x01E13028) = 0x010000C1; //关闭控制器 return (0); } |
文件名 | /lib_arm/board.c |
修改摘要 | 增加阶段显示进度条 |
修改内容 | 增加函数声明:extern void DispLogoProgress ( int ) ; |
增加进度显示 void start_armboot (void) { for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) {hang ();}} DispLogoProgress(10); } | |
增加进度显示 DispLogoProgress(20); for (;;) { main_loop (); } |
文件名 | /lib_arm/common/cmd_nand.c |
修改摘要 | 增加阶段显示进度条 |
修改内容 | Void nand_load_image ( void ) { /* Loading ok, update default load address */ load_addr = addr; // 从NAND将linux内核load到内存后, 显示进度条 extern void DispLogoProgress(int); DispLogoProgress(40); } |
文件名 | /lib_arm/common/cmd_bootm.c |
修改摘要 | 增加阶段显示进度条 |
修改内容 | Int bootm_start( void ) { // bootm 执行成功后更新进度条 extern void DispLogoProgress(int); DispLogoProgress ( 50 ); return 0; } |
增加文件:board/davinci/da8xxevm/uboot_logo.h |
说明: 存放初始背景图片, 由于初始背景图片简单, 且单色, 所以实际存储的只是白色的文字所在的位置, 一共4K多个点, |
最后附上UBOOT 启动流程(从LCD角度)
start_armboot ()
{
board_init ()
{
logo_init()
{
初始化LCDC
设置进度条 0%
}
}
.... 其他初始化
设置进度条10%
misc_init_r
{
关闭LCDC控制器
}
设置进度条20%
main_loop
{
加载内核从NAND到内存后, 40%
BOOTM执行后50%
}
}