首页 > 学院 > 开发设计 > 正文

Uboot中支持lcd和hdmi显示不同的logo图片

2019-11-09 14:33:27
字体:
来源:转载
供稿:网友

在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;}

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)); } }

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);}

实现了上面的内容之后,接下来需要在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的图片。具体的实现方式和平台相关,代码就不贴了。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表