Uboot中支持lcd和hdmi显示不同的logo图片【转】
本文转载自:http://blog.csdn.net/u010865783/article/details/54953315
在lcd为竖屏,hdmi显示横屏的情况下,如果按照默认的uboot显示框架来看,只能保证lcd或者hdmi上面显示出来的图片一个是正的,另外一个是旋转了90度的样子。
为了能是lcd和hdmi同时支持显示图片都是正的,需要对uboot的框架做修改。如果硬件支持旋转功能的话,就可直接使用硬件旋转,不需要软件来调整。
由于项目原因,折腾了一把这个流程,具体实现记录下:
1:由于硬件不支持rotation功能,在软件上采用的方法是准备两份logo资源,解析后将两份数据送到不同的显示设备上面做显示。
在解析logo的时候需要解析两份资源:
static int splash_image_load(void)
{
int ret;
char *filename,*filename_hdmi;
void *splash_image_addr,*splash_image_hdmi_addr;
char splash_image_char[16], splash_image_hdmi_char[16];
//分配给lcd资源的地址
splash_image_addr = memalign(128, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE);
if(splash_image_addr == NULL) {
printk("Malloc size for splash image failed!\n");
return -1;
}
//分配给hdmi资源logo的地址
splash_image_hdmi_addr = memalign(128, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE);
if(splash_image_hdmi_addr == NULL) {
printk("Malloc size for splash image hdmi failed!\n");
return -1;
}
filename = splash_image_select();
filename_hdmi = CONFIG_SYS_VIDEO_LOGO_HDMI_NAME;
if (!filename) {
printk("No splash image loaded\n");
return -1;
}
//拿到lcd的logo
ret = file_fat_read(filename, splash_image_addr, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE);
if(ret < 0) {
printk("Fail to load splash image\n");
free(splash_image_addr);
return -1;
}
//拿到hdmi的logo
ret = file_fat_read(filename_hdmi, splash_image_hdmi_addr, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE);
if(ret < 0) {
printk("Fail to load splash hdmi image\n");
free(splash_image_hdmi_addr);
return -1;
}
sprintf(splash_image_char, "%x", (unsigned int) splash_image_addr);
sprintf(splash_image_hdmi_char, "%x", (unsigned int) splash_image_hdmi_addr);
//将解析到的地址保存到env中,后续需要再读取出来
setenv("splashimage", splash_image_char);
setenv("splashimagehdmi", splash_image_hdmi_char);
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
2:添加对hdmi驱动中的支持和在cfb_console.c中添加解析图片的支持
static int video_init(void)
{
unsigned char color8;
pGD = video_hw_init();
if (pGD == NULL)
return -1;
//获取驱动中的hdmi的fb的信息video_hw_hdmi_init在fb的驱动中实现
pGD_HDMI = video_hw_hdmi_init();
if (pGD_HDMI == NULL)
return -1;
...
}
static void *video_logo(void)
{
char info[128];
int space, len;
__maybe_unused int y_off = 0;
__maybe_unused ulong addr;
__maybe_unused char *s,*s_hdmi;
splash_get_pos(&video_logo_xpos, &video_logo_ypos);
//splash_get_pos(&video_logo_xpos, &video_logo_ypos);
video_hdmi_logo_xpos = BMP_ALIGN_CENTER; //init xpos and ypos
video_hdmi_logo_ypos = BMP_ALIGN_CENTER;
#ifdef CONFIG_SPLASH_SCREEN
//从env中拿到lcd和hdmi图片的地址
s = getenv("splashimage");
s_hdmi = getenv("splashimagehdmi");
if (s != NULL) {
splash_screen_prepare();
addr = simple_strtoul(s, NULL, 16);
//解析lcd的logo资源成送显的数据
if (video_display_bitmap(addr,
video_logo_xpos,
video_logo_ypos) == 0) {
video_logo_height = 0;
//return ((void *) (video_fb_address));
}
}
if (s_hdmi != NULL) {
//printf("xieshsh debug video display\n");
splash_screen_prepare();
addr = simple_strtoul(s_hdmi, NULL, 16);
//解析lcd的hdmi资源成送显的数据
if (video_display_hdmi_bitmap(addr,
video_hdmi_logo_xpos,
video_hdmi_logo_ypos) == 0) {
video_hdmi_logo_ypos = 0;
return ((void *) (video_fb_address));
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
3:接下来需要对添加对hdmi logo的解析成fb的数据
int video_display_hdmi_bitmap(ulong bmp_image, int x, int y)
{
ushort xcount, ycount;
uchar *fb;
bmp_image_t *bmp = (bmp_image_t *) bmp_image;
uchar *bmap;
ushort padded_line;
unsigned long width, height, bpp;
unsigned colors;
unsigned long compression;
bmp_color_table_entry_t cte;
#ifdef CONFIG_VIDEO_BMP_GZIP
unsigned char *dst = NULL;
ulong len;
#endif
WATCHDOG_RESET();
if (!((bmp->header.signature[0] == 'B') &&
(bmp->header.signature[1] == 'M'))) {
#ifdef CONFIG_VIDEO_BMP_GZIP
/*
* Could be a gzipped bmp image, try to decrompress...
*/
len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE;
dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE);
if (dst == NULL) {
printf("Error: malloc in gunzip failed!\n");
return 1;
}
/*
* NB: we need to force offset of +2
* See doc/README.displaying-bmps
*/
if (gunzip(dst+2, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE-2,
(uchar *) bmp_image,
&len) != 0) {
printf("Error: no valid bmp or bmp.gz image at %lx\n",
bmp_image);
free(dst);
return 1;
}
if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE) {
printf("Image could be truncated "
"(increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n");
}
/*
* Set addr to decompressed image
*/
bmp = (bmp_image_t *)(dst+2);
if (!((bmp->header.signature[0] == 'B') &&
(bmp->header.signature[1] == 'M'))) {
printf("Error: no valid bmp.gz image at %lx\n",
bmp_image);
free(dst);
return 1;
}
#else
printf("Error: no valid bmp image at %lx\n", bmp_image);
return 1;
#endif /* CONFIG_VIDEO_BMP_GZIP */
}
width = le32_to_cpu(bmp->header.width);
height = le32_to_cpu(bmp->header.height);
bpp = le16_to_cpu(bmp->header.bit_count);
colors = le32_to_cpu(bmp->header.colors_used);
compression = le32_to_cpu(bmp->header.compression);
debug("Display-bmp: %ld x %ld with %d colors\n",
width, height, colors);
if (compression != BMP_BI_RGB
#ifdef CONFIG_VIDEO_BMP_RLE8
&& compression != BMP_BI_RLE8
#endif
) {
printf("Error: compression type %ld not supported\n",
compression);
#ifdef CONFIG_VIDEO_BMP_GZIP
if (dst)
free(dst);
#endif
return 1;
}
padded_line = (((width * bpp + 7) / 8) + 3) & ~0x3;
#ifdef CONFIG_SPLASH_SCREEN_ALIGN
if (x == BMP_ALIGN_CENTER){
x = max(0, (int)(VIDEO_HDMI_VISIBLE_COLS - width) / 2);
printf("VVVVVVVVx=%d",x);
}
else if (x < 0)
x = max(0, (int)(VIDEO_HDMI_VISIBLE_COLS - width + x + 1));
if (y == BMP_ALIGN_CENTER)
y = max(0, (int)(VIDEO_HDMI_VISIBLE_ROWS - height) / 2);
else if (y < 0)
y = max(0, (int)(VIDEO_HDMI_VISIBLE_ROWS - height + y + 1));
#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
/*
* Just ignore elements which are completely beyond screen
* dimensions.
*/
if ((x >= VIDEO_HDMI_VISIBLE_COLS) || (y >= VIDEO_HDMI_VISIBLE_ROWS))
return 0;
if ((x + width) > VIDEO_HDMI_VISIBLE_COLS)
width = VIDEO_HDMI_VISIBLE_COLS - x;
if ((y + height) > VIDEO_HDMI_VISIBLE_ROWS)
height = VIDEO_HDMI_VISIBLE_ROWS - y;
bmap = (uchar *) bmp + le32_to_cpu(bmp->header.data_offset);
fb = (uchar *) (video_hdmi_fb_address +
((y + height - 1) * VIDEO_HDMI_VISIBLE_COLS * VIDEO_HDMI_PIXEL_SIZE) +
x * VIDEO_HDMI_PIXEL_SIZE);
/* We handle only 4, 8, or 24 bpp bitmaps */
switch (le16_to_cpu(bmp->header.bit_count)) {
case 24:
padded_line -= 3 * width;
ycount = height;
//printf("xiessh----VIDEO_DATA_FORMAT = %d\n",VIDEO_HDMI_DATA_FORMAT);
switch (VIDEO_HDMI_DATA_FORMAT) {
case GDF_32BIT_X888RGB:
while (ycount--) {
WATCHDOG_RESET();
xcount = width;
while (xcount--) {
FILL_32BIT_X888RGB(bmap[2], bmap[1],
bmap[0]);
bmap += 3;
}
bmap += padded_line;
fb -= (VIDEO_HDMI_VISIBLE_COLS + width) *
VIDEO_PIXEL_SIZE;
}
break;
default:
printf("Error: 24 bits/pixel bitmap incompatible "
"with current video mode\n");
break;
}
break;
default:
printf("Error: %d bit/pixel bitmaps not supported by U-Boot\n",
le16_to_cpu(bmp->header.bit_count));
break;
}
#ifdef CONFIG_VIDEO_BMP_GZIP
if (dst) {
free(dst);
}
#endif
if (cfb_do_flush_cache)
flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
return (0);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
实现了上面的内容之后,接下来需要在uboot的fb中做好映射,主要是将fb0对应的logo的资源送到lcd、fb1对应的logo资源送到hdmi显示,具体的代码和平台相关。
这样造成的影响是会使uboot阶段显示的内存增加一倍,之前只用了一个图片,现在用到了两个图片,所以内存会增加一倍。
当android系统起来的时候,因为lcd是竖屏,lcd上面的内容旋转了90度当成了横屏模式在使用,hdmi是横屏,会造成android动画的前半段在hdmi上面显示的android字样变成了垂直显示,知道android的display的java服务启动之后,android的显示系统识别到了hdmi设备,系统才显示正常。
对于这种情况,hdmi的前半段的异常显示,由于硬件无法rotation,只能采取一个规避的方式解决,将开机启动的logo一直保存到android上层的显示系统识别到hdmi后,才释放boot logo的资源,在这个之前,一直都显示logo的图片。具体的实现方式和平台相关,代码就不贴了。