From 872aaef89f1d267209eec932375337983748860e Mon Sep 17 00:00:00 2001 From: Mark Yao Date: Mon, 8 Dec 2014 16:55:21 +0800 Subject: [PATCH] rk_fb: logo: support display bmp logo from uboot 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 --- drivers/video/rockchip/bmp_helper.c | 244 +++++++++++++++++++++++++++- drivers/video/rockchip/bmp_helper.h | 10 +- drivers/video/rockchip/rk_fb.c | 54 +++++- drivers/video/rockchip/rkfb_sysfs.c | 3 +- 4 files changed, 299 insertions(+), 12 deletions(-) diff --git a/drivers/video/rockchip/bmp_helper.c b/drivers/video/rockchip/bmp_helper.c index ac2406c558f4..75e8c3ae1aed 100755 --- a/drivers/video/rockchip/bmp_helper.c +++ b/drivers/video/rockchip/bmp_helper.c @@ -24,6 +24,74 @@ #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; +} diff --git a/drivers/video/rockchip/bmp_helper.h b/drivers/video/rockchip/bmp_helper.h index 0df19380d065..fd1ad43f6d71 100644 --- a/drivers/video/rockchip/bmp_helper.h +++ b/drivers/video/rockchip/bmp_helper.h @@ -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_ */ diff --git a/drivers/video/rockchip/rk_fb.c b/drivers/video/rockchip/rk_fb.c index 78b4b8695675..cf41a1635959 100755 --- a/drivers/video/rockchip/rk_fb.c +++ b/drivers/video/rockchip/rk_fb.c @@ -31,6 +31,8 @@ #include #include +#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)) { diff --git a/drivers/video/rockchip/rkfb_sysfs.c b/drivers/video/rockchip/rkfb_sysfs.c index cf9f8c9b7a1f..da80013612d7 100755 --- a/drivers/video/rockchip/rkfb_sysfs.c +++ b/drivers/video/rockchip/rkfb_sysfs.c @@ -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); -- 2.34.1