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

Posted 请给我倒杯茶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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的图片。具体的实现方式和平台相关,代码就不贴了。

以上是关于Uboot中支持lcd和hdmi显示不同的logo图片的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 QT 在 Raspberry Pi 上的 LCD 和 HDMI 上同时在 Linux 中绘制图像?

fpga实操训练(lcd测试)

fpga实操训练(lcd测试)

嵌入式Linux | 设置LCD屏幕为终端控制台

嵌入式Linux | 设置LCD屏幕为终端控制台

i.MX6ULL驱动开发 | 10 - 修改LCD驱动点亮LCD显示小企鹅logo