rk_fb: logo: support display bmp logo from uboot
authorMark Yao <mark.yao@rock-chips.com>
Mon, 8 Dec 2014 08:55:21 +0000 (16:55 +0800)
committerMark Yao <mark.yao@rock-chips.com>
Mon, 8 Dec 2014 09:54:59 +0000 (17:54 +0800)
get bmp file data from bootargs "kernel_logo=xxxxxx", decoder bmp
file to framebuffer.

now support rle 8bit bmp files and 24bit bmp files.

Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
drivers/video/rockchip/bmp_helper.c
drivers/video/rockchip/bmp_helper.h
drivers/video/rockchip/rk_fb.c
drivers/video/rockchip/rkfb_sysfs.c

index ac2406c558f4c3ef19f9c4f1557e5a41de228797..75e8c3ae1aedd4f9e8d876eb9f586c6224f25c92 100755 (executable)
 
 #include "bmp_helper.h"
 
+unsigned short bmp_logo_palette[] = {
+       0x0000, 0x0021, 0x0840, 0x0841, 0x0041, 0x0862, 0x0043, 0x1060,
+       0x1061, 0x1081, 0x18a1, 0x1082, 0x18c3, 0x18c2, 0x18e4, 0x1904,
+       0x20e2, 0x2901, 0x2123, 0x2902, 0x3123, 0x3983, 0x2104, 0x2945,
+       0x2924, 0x2966, 0x3144, 0x3185, 0x3984, 0x39a5, 0x31a6, 0x39c7,
+       0x51a2, 0x41c4, 0x61e4, 0x4a02, 0x4a24, 0x5a65, 0x5245, 0x5226,
+       0x5a66, 0x62a3, 0x7202, 0x6ac4, 0x62c7, 0x72c5, 0x7285, 0x7b03,
+       0x6b05, 0x6b07, 0x7b46, 0x7326, 0x4228, 0x4a69, 0x5a88, 0x528a,
+       0x5aeb, 0x62a8, 0x7b4a, 0x7ba9, 0x630c, 0x6b4d, 0x73ae, 0x7bcf,
+       0x92c4, 0x8b25, 0x83a4, 0x8bc6, 0x9b65, 0x9ba6, 0xa2a2, 0xa364,
+       0xa324, 0xabe5, 0xb364, 0xb3a4, 0xb386, 0x8369, 0x83a8, 0x8b8b,
+       0x93a8, 0x8bcc, 0xc3c4, 0xebc1, 0x9c23, 0x9c04, 0x9406, 0x9427,
+       0xac23, 0xb483, 0xa445, 0xa407, 0xacc7, 0xbc64, 0xb4c4, 0xbd26,
+       0x9c2d, 0xac4c, 0xbd29, 0xc4c2, 0xc4e4, 0xc4a4, 0xdce5, 0xcc44,
+       0xc563, 0xdd02, 0xdd03, 0xdd83, 0xc544, 0xcd87, 0xd544, 0xdd24,
+       0xdd84, 0xddc4, 0xd5c7, 0xe462, 0xe463, 0xe4c1, 0xeca3, 0xecc2,
+       0xecc2, 0xf442, 0xf4a3, 0xe444, 0xec65, 0xe485, 0xeca5, 0xecc4,
+       0xecc5, 0xe4a4, 0xf465, 0xf4a4, 0xed22, 0xed23, 0xed62, 0xed63,
+       0xe522, 0xedc2, 0xfd20, 0xfd02, 0xfde1, 0xfdc1, 0xf5c3, 0xf5c3,
+       0xe5c1, 0xed04, 0xed25, 0xed64, 0xed65, 0xe505, 0xed66, 0xed26,
+       0xed84, 0xeda5, 0xede4, 0xedc5, 0xe5e4, 0xf525, 0xf5e4, 0xf5e5,
+       0xf5a4, 0xed49, 0xeda8, 0xedab, 0xf5eb, 0xf5cb, 0xedac, 0xf5cc,
+       0xf5ce, 0xee21, 0xee42, 0xee22, 0xfe21, 0xf602, 0xfe63, 0xfe22,
+       0xfea0, 0xfea3, 0xfee2, 0xfec3, 0xf682, 0xee65, 0xe624, 0xee85,
+       0xf625, 0xf664, 0xf645, 0xfe64, 0xf624, 0xf606, 0xf684, 0xf685,
+       0xfea4, 0xfee4, 0xf6c4, 0xf6a6, 0xff03, 0xff02, 0xee2f, 0xf60d,
+       0xf62e, 0xf64f, 0xf64e, 0x8410, 0x8c51, 0x94b2, 0x9cd3, 0xa4b0,
+       0xbd30, 0xbd72, 0xa534, 0xad55, 0xb596, 0xbdd7, 0xde75, 0xf671,
+       0xf691, 0xf692, 0xf6b3, 0xf6d3, 0xfeb3, 0xf673, 0xe6b6, 0xf6d4,
+       0xf6f5, 0xfef5, 0xf6f6, 0xfef6, 0xff15, 0xf716, 0xff16, 0xff17,
+       0xc618, 0xce79, 0xd69a, 0xdefb, 0xef19, 0xff38, 0xff58, 0xff79,
+       0xf718, 0xff7a, 0xf75a, 0xff99, 0xff9a, 0xffbb, 0xffdb, 0xe73c,
+       0xef5d, 0xfffc, 0xf7be, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static void draw_unencoded_bitmap(uint16_t **dst, uint8_t *bmap, uint16_t *cmap,
+                                 uint32_t cnt)
+{
+       while (cnt > 0) {
+               *(*dst)++ = cmap[*bmap++];
+               cnt--;
+       }
+}
+
+static void draw_encoded_bitmap(uint16_t **dst, uint16_t c, uint32_t cnt)
+{
+       uint16_t *fb = *dst;
+       int cnt_8copy = cnt >> 3;
+
+       cnt -= cnt_8copy << 3;
+       while (cnt_8copy > 0) {
+               *fb++ = c;
+               *fb++ = c;
+               *fb++ = c;
+               *fb++ = c;
+               *fb++ = c;
+               *fb++ = c;
+               *fb++ = c;
+               *fb++ = c;
+               cnt_8copy--;
+       }
+       while (cnt > 0) {
+               *fb++ = c;
+               cnt--;
+       }
+       *dst = fb;
+}
+
 static void yuv_to_rgb(int y, int u, int v, int *r, int *g, int *b)
 {
        int rdif, invgdif, bdif;
@@ -38,8 +106,8 @@ static void yuv_to_rgb(int y, int u, int v, int *r, int *g, int *b)
        *b = range(y + bdif, 0, 0xff);
 }
 
-int datatobmp(void *__iomem *vaddr, int width, int height, u8 data_format,
-             void *data, void (*fn)(void *, void *, int))
+int bmpencoder(void *__iomem *vaddr, int width, int height, u8 data_format,
+              void *data, void (*fn)(void *, void *, int))
 {
        uint32_t *d, *d1, *d2;
        uint8_t *dst, *yrgb, *uv, *y1, *y2;
@@ -169,3 +237,175 @@ int datatobmp(void *__iomem *vaddr, int width, int height, u8 data_format,
 
        return 0;
 }
+
+static void decode_rle8_bitmap(uint8_t *psrc, uint8_t *pdst, uint16_t *cmap,
+                              unsigned int width, unsigned int height,
+                              int bits, int x_off, int y_off, bool flip)
+{
+       uint32_t cnt, runlen;
+       int x = 0, y = 0;
+       int decode = 1;
+       uint8_t *bmap = psrc;
+       uint8_t *dst = pdst;
+       int linesize = width * 2;
+
+       if (flip) {
+               y = height - 1;
+               dst = pdst + y * linesize;
+       }
+
+       while (decode) {
+               if (bmap[0] == BMP_RLE8_ESCAPE) {
+                       switch (bmap[1]) {
+                       case BMP_RLE8_EOL:
+                               /* end of line */
+                               bmap += 2;
+                               x = 0;
+                               if (flip) {
+                                       y--;
+                                       dst -= linesize * 2;
+                               } else {
+                                       y++;
+                               }
+                               break;
+                       case BMP_RLE8_EOBMP:
+                               /* end of bitmap */
+                               decode = 0;
+                               break;
+                       case BMP_RLE8_DELTA:
+                               /* delta run */
+                               x += bmap[2];
+                               if (flip) {
+                                       y -= bmap[3];
+                                       dst -= bmap[3] * linesize;
+                                       dst += bmap[2] * 2;
+                               } else {
+                                       y += bmap[3];
+                                       dst += bmap[3] * linesize;
+                                       dst += bmap[2] * 2;
+                               }
+                               bmap += 4;
+                               break;
+                       default:
+                               /* unencoded run */
+                               runlen = bmap[1];
+                               bmap += 2;
+                               if (y >= height || x >= width) {
+                                       decode = 0;
+                                       break;
+                               }
+                               if (x + runlen > width)
+                                       cnt = width - x;
+                               else
+                                       cnt = runlen;
+                               draw_unencoded_bitmap((uint16_t **)&dst, bmap,
+                                                     cmap, cnt);
+                               x += runlen;
+                               bmap += runlen;
+                               if (runlen & 1)
+                                       bmap++;
+                       }
+               } else {
+                       /* encoded run */
+                       if (y < height) {
+                               runlen = bmap[0];
+                               if (x < width) {
+                                       /* aggregate the same code */
+                                       while (bmap[0] == 0xff &&
+                                              bmap[2] != BMP_RLE8_ESCAPE &&
+                                              bmap[1] == bmap[3]) {
+                                               runlen += bmap[2];
+                                               bmap += 2;
+                                       }
+                                       if (x + runlen > width)
+                                               cnt = width - x;
+                                       else
+                                               cnt = runlen;
+                                       draw_encoded_bitmap((uint16_t **)&dst,
+                                                           cmap[bmap[1]], cnt);
+                               }
+                               x += runlen;
+                       }
+                       bmap += 2;
+               }
+       }
+}
+
+int bmpdecoder(void *bmp_addr, void *pdst, int *width, int *height, int *bits)
+{
+       BITMAPHEADER header;
+       BITMAPINFOHEADER infoheader;
+       uint32_t size;
+       uint16_t linesize;
+       char *src = bmp_addr;
+       char *dst = pdst;
+       int i, j;
+       bool flip = false;
+
+       memcpy(&header, src, sizeof(header));
+       src += sizeof(header);
+       memcpy(&infoheader, src, sizeof(infoheader));
+       *width = infoheader.width;
+       *height = infoheader.height;
+
+       if (*height < 0)
+               *height = 0 - *height;
+       else
+               flip = true;
+
+       size = header.size - header.offset;
+       linesize = *width * infoheader.bitcount >> 3;
+       src = bmp_addr + header.offset;
+
+       switch (infoheader.bitcount) {
+       case 8:
+               /*
+                * only support convert 8bit bmap file to RGB565.
+                */
+               decode_rle8_bitmap(src, dst, bmp_logo_palette,
+                                  infoheader.width, infoheader.height,
+                                  infoheader.bitcount, 0, 0, flip);
+               *bits = 16;
+               break;
+       case 16:
+               /*
+                * Todo
+                */
+               pr_info("unsupport bit=%d now\n", infoheader.bitcount);
+               break;
+       case 24:
+               if (size % 3 != 0) {
+                       pr_info("wrong bmp file with unalign size\n");
+
+                       return -EINVAL;
+               }
+               if (flip)
+                       src += (*width) * (*height - 1) * 3;
+
+               for (i = 0; i < *height; i++) {
+                       for (j = 0; j < *width; j++) {
+                               dst[0] = src[2];
+                               dst[1] = src[1];
+                               dst[2] = src[0];
+                               dst += 3;
+                               src += 3;
+                       }
+                       if (flip)
+                               src -= *width * 3 * 2;
+               }
+
+               *bits = 24;
+               break;
+       case 32:
+               /*
+                * Todo
+                */
+               pr_info("unsupport bit=%d now\n", infoheader.bitcount);
+               break;
+       default:
+               pr_info("unsupport bit=%d now\n", infoheader.bitcount);
+               break;
+       }
+
+       return 0;
+}
index 0df19380d065554de6b38e68219357a759dd115e..fd1ad43f6d71d4ddd2c5971dc503efd67601b29a 100644 (file)
@@ -41,8 +41,14 @@ typedef struct bmpinfoheader {
        unsigned int colorsimportant;
 }__attribute__((packed)) BITMAPINFOHEADER;
 
+#define BMP_RLE8_ESCAPE                0
+#define BMP_RLE8_EOL           0
+#define BMP_RLE8_EOBMP         1
+#define BMP_RLE8_DELTA         2
+
 #define range(x, min, max) ((x) < (min)) ? (min) : (((x) > (max)) ? (max) : (x))
 
-int datatobmp(void *__iomem *vaddr,int width, int height, u8 data_format,
-             void *data, void (*fn)(void *, void *, int));
+int bmpencoder(void *__iomem *vaddr,int width, int height, u8 data_format,
+              void *data, void (*fn)(void *, void *, int));
+int bmpdecoder(void *bmp_addr, void *dst, int *width, int *height, int *bits);
 #endif /* _BMP_HELPER_H_ */
index 78b4b869567586b9313aa1fe32d7961314df60b8..cf41a1635959398fba88042f9ea63a2c2a07dda5 100755 (executable)
@@ -31,6 +31,8 @@
 #include <linux/dma-mapping.h>
 #include <linux/regulator/consumer.h>
 
+#include "bmp_helper.h"
+
 #if defined(CONFIG_RK_HDMI)
 #include "hdmi/rk_hdmi.h"
 #endif
@@ -65,6 +67,16 @@ int (*video_data_to_mirroring) (struct fb_info *info, u32 yuv_phy[2]);
 EXPORT_SYMBOL(video_data_to_mirroring);
 #endif
 
+static uint32_t kernel_logo_addr;
+static int __init kernel_logo_setup(char *str)
+{
+       if(str) {
+               sscanf(str, "%x", &kernel_logo_addr);
+       }
+
+       return 0;
+}
+early_param("kernel_logo", kernel_logo_setup);
 static struct rk_fb_trsm_ops *trsm_lvds_ops;
 static struct rk_fb_trsm_ops *trsm_edp_ops;
 static struct rk_fb_trsm_ops *trsm_mipi_ops;
@@ -215,6 +227,9 @@ static int rk_fb_data_fmt(int data_format, int bits_per_pixel)
                case 32:
                        fb_data_fmt = ARGB888;
                        break;
+               case 24:
+                       fb_data_fmt = RGB888;
+                       break;
                case 16:
                        fb_data_fmt = RGB565;
                        break;
@@ -4162,15 +4177,40 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
 
                rk_fb_alloc_buffer(main_fbi, 0);        /* only alloc memory for main fb */
                dev_drv->uboot_logo = support_uboot_display();
-#if !defined(CONFIG_LOGO)
-               if (support_uboot_display()) {
-                       /*
-                       if (dev_drv->iommu_enabled)
-                               rk_fb_copy_from_loader(main_fbi);
-                       */
+
+               if (kernel_logo_addr) {
+                       struct rk_lcdc_win *win = dev_drv->win[0];
+                       char *addr = phys_to_virt(kernel_logo_addr);
+                       int width, height, bits;
+
+                       bmpdecoder(addr, main_fbi->screen_base,
+                                  &width, &height, &bits);
+                       win->area[0].format = rk_fb_data_fmt(0, bits);
+                       win->area[0].y_vir_stride = width * bits >> 5;
+                       win->area[0].xpos = (main_fbi->var.xres - width) >> 1;
+                       win->area[0].ypos = (main_fbi->var.yres - height) >> 1;;
+                       win->area[0].xsize = width;
+                       win->area[0].ysize = height;
+                       win->area[0].xact = width;
+                       win->area[0].yact = height;
+                       win->area[0].xvir = win->area[0].y_vir_stride;
+                       win->area[0].yvir = height;
+                       win->area[0].smem_start = main_fbi->fix.smem_start;
+                       win->area[0].y_offset = 0;
+
+                       win->area_num = 1;
+                       win->alpha_mode = 4;
+                       win->alpha_en = 0;
+                       win->g_alpha_val = 0;
+
+                       win->state = 1;
+                       dev_drv->ops->set_par(dev_drv, 0);
+                       dev_drv->ops->pan_display(dev_drv, 0);
+                       dev_drv->ops->cfg_done(dev_drv);
+
                        return 0;
                }
-#else
+#if defined(CONFIG_LOGO)
                main_fbi->fbops->fb_set_par(main_fbi);
 #if  defined(CONFIG_LOGO_LINUX_BMP)
                if (fb_prewine_bmp_logo(main_fbi, FB_ROTATE_UR)) {
index cf9f8c9b7a1f647dca03290b38ce4dbc4b62dc9e..da80013612d7783bb4853cb023bf57a315d00b5c 100755 (executable)
@@ -166,7 +166,8 @@ static int dump_win(struct rk_fb *rk_fb, struct rk_fb_reg_area_data *area_data,
        set_fs(KERNEL_DS);
 
        if (is_bmp)
-               datatobmp(vaddr, width, height, data_format, filp, fill_buffer);
+               bmpencoder(vaddr, width, height,
+                          data_format, filp, fill_buffer);
        else
                fill_buffer(filp, vaddr, width * height * 4);