From: Mark Yao Date: Wed, 3 Dec 2014 02:05:26 +0000 (+0800) Subject: rk_fb: sysfs: add dump_buffer func to fb sysfs X-Git-Tag: firefly_0821_release~4421 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=2855e146a1df33e30170032ccf8341664ffc3832;p=firefly-linux-kernel-4.4.55.git rk_fb: sysfs: add dump_buffer func to fb sysfs Due to some time we want to know which buffer vop scaning, use "io" cammand to dump buffer is too complex, so we add a sys node to help buffer dump. how to use it: - echo bin > /sys/class/graphics/fb0/disp_info it will create bin file at /data/xxx.bin - or echo bmp > /sys/class/graphics/fb0/disp_info it will create bmp file at /data/xxx.bmp, this file is normal bmp file. Signed-off-by: Mark Yao --- diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile index 03f76012b533..f3adbabbaeb8 100755 --- a/drivers/video/rockchip/Makefile +++ b/drivers/video/rockchip/Makefile @@ -1,4 +1,4 @@ -obj-$(CONFIG_FB_ROCKCHIP) += rk_fb.o rkfb_sysfs.o screen/ +obj-$(CONFIG_FB_ROCKCHIP) += rk_fb.o rkfb_sysfs.o bmp_helper.o screen/ obj-$(CONFIG_DRM_ROCKCHIP) += rk_drm_fb.o screen/ obj-$(CONFIG_RK_TRSM) += transmitter/ obj-$(CONFIG_DRM_ROCKCHIP) += lcdc/ diff --git a/drivers/video/rockchip/bmp_helper.c b/drivers/video/rockchip/bmp_helper.c new file mode 100755 index 000000000000..ac2406c558f4 --- /dev/null +++ b/drivers/video/rockchip/bmp_helper.c @@ -0,0 +1,171 @@ +/* + * linux/drivers/video/rockchip/bmp_helper.c + * + * Copyright (C) 2012 Rockchip Corporation + * Author: Mark Yao + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include +#include +#include + +#include "bmp_helper.h" + +static void yuv_to_rgb(int y, int u, int v, int *r, int *g, int *b) +{ + int rdif, invgdif, bdif; + + u -= 128; + v -= 128; + rdif = v + ((v * 103) >> 8); + invgdif = ((u * 88) >> 8) + ((v * 183) >> 8); + bdif = u + ((u*198) >> 8); + *r = range(y + rdif, 0, 0xff); + *g = range(y - invgdif, 0, 0xff); + *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)) +{ + uint32_t *d, *d1, *d2; + uint8_t *dst, *yrgb, *uv, *y1, *y2; + int y, u, v, r, g, b; + + int yu = width * 4 % 4; + int byteperline; + unsigned int size; + BITMAPHEADER header; + BITMAPINFOHEADER infoheader; + void *buf; + int i, j; + + yu = yu != 0 ? 4 - yu : yu; + byteperline = width * 4 + yu; + size = byteperline * height + 54; + memset(&header, 0, sizeof(header)); + memset(&infoheader, 0, sizeof(infoheader)); + header.type = 'M'<<8|'B'; + header.size = size; + header.offset = 54; + + infoheader.size = 40; + infoheader.width = width; + infoheader.height = 0 - height; + infoheader.bitcount = 4 * 8; + infoheader.compression = 0; + infoheader.imagesize = byteperline * height; + infoheader.xpelspermeter = 0; + infoheader.ypelspermeter = 0; + infoheader.colors = 0; + infoheader.colorsimportant = 0; + fn(data, (void *)&header, sizeof(header)); + fn(data, (void *)&infoheader, sizeof(infoheader)); + + /* + * if data_format is ARGB888 or XRGB888, not need convert. + */ + if (data_format == ARGB888 || data_format == XRGB888) { + fn(data, (char *)vaddr, width * height * 4); + return 0; + } + /* + * alloc 2 line buffer. + */ + buf = kmalloc(width * 2 * 4, GFP_KERNEL); + if (!buf) + return -ENOMEM; + yrgb = (uint8_t *)vaddr; + uv = yrgb + width * height; + for (j = 0; j < height; j++) { + if (j % 2 == 0) { + dst = buf; + y1 = yrgb + j * width; + y2 = y1 + width; + d1 = buf; + d2 = d1 + width; + } + + for (i = 0; i < width; i++) { + switch (data_format) { + case XBGR888: + case ABGR888: + dst[0] = yrgb[2]; + dst[1] = yrgb[1]; + dst[2] = yrgb[0]; + dst[3] = yrgb[3]; + dst += 4; + yrgb += 4; + break; + case RGB888: + dst[0] = yrgb[0]; + dst[1] = yrgb[1]; + dst[2] = yrgb[2]; + dst[3] = 0xff; + dst += 4; + yrgb += 3; + break; + case RGB565: + dst[0] = (yrgb[0] & 0x1f) << 3; + dst[1] = (yrgb[0] & 0xe0) >> 3 | + (yrgb[1] & 0x7) << 5; + dst[2] = yrgb[1] & 0xf8; + dst[3] = 0xff; + dst += 4; + yrgb += 2; + break; + case YUV420: + case YUV422: + case YUV444: + if (data_format == YUV420) { + if (i % 2 == 0) { + d = d1++; + y = *y1++; + } else { + d = d2++; + y = *y2++; + } + if (i % 4 == 0) { + u = *uv++; + v = *uv++; + } + } else if (data_format == YUV422) { + if (i % 2 == 0) { + u = *uv++; + v = *uv++; + } + d = d1++; + } else { + u = *uv++; + v = *uv++; + d = d1++; + } + yuv_to_rgb(y, u, v, &r, &g, &b); + *d = 0xff<<24 | r << 16 | g << 8 | b; + break; + case YUV422_A: + case YUV444_A: + default: + pr_err("unsupport now\n"); + return -EINVAL; + } + } + if (j % 2 == 1) + fn(data, (char *)buf, 2 * width * 4); + } + + return 0; +} diff --git a/drivers/video/rockchip/bmp_helper.h b/drivers/video/rockchip/bmp_helper.h new file mode 100644 index 000000000000..0df19380d065 --- /dev/null +++ b/drivers/video/rockchip/bmp_helper.h @@ -0,0 +1,48 @@ +/* + * drivers/video/rockchip/bmp_helper.h + * + * Copyright (C) 2012 Rockchip Corporation + * Author: Mark Yao + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef _BMP_HELPER_H_ +#define _BMP_HELPER_H_ + +typedef struct bmpheader { + unsigned short type; + unsigned int size; + unsigned int reserved; + unsigned int offset; +}__attribute__((packed)) BITMAPHEADER; + +typedef struct bmpinfoheader { + unsigned int size; + unsigned int width; + unsigned int height; + unsigned short planes; + unsigned short bitcount; + unsigned int compression; + unsigned int imagesize; + unsigned int xpelspermeter; + unsigned int ypelspermeter; + unsigned int colors; + unsigned int colorsimportant; +}__attribute__((packed)) BITMAPINFOHEADER; + +#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)); +#endif /* _BMP_HELPER_H_ */ diff --git a/drivers/video/rockchip/rkfb_sysfs.c b/drivers/video/rockchip/rkfb_sysfs.c index f9d8efd744b5..ee4f557d746e 100755 --- a/drivers/video/rockchip/rkfb_sysfs.c +++ b/drivers/video/rockchip/rkfb_sysfs.c @@ -29,9 +29,46 @@ #include #include #include +#include #include #include #include +#if defined(CONFIG_ION_ROCKCHIP) +#include +#endif +#include "bmp_helper.h" + +static char *get_format_str(enum data_format format) +{ + switch (format) { + case ARGB888: + return "ARGB888"; + case RGB888: + return "RGB888"; + case RGB565: + return "RGB565"; + case YUV420: + return "YUV420"; + case YUV422: + return "YUV422"; + case YUV444: + return "YUV444"; + case YUV420_A: + return "YUV420_A"; + case YUV422_A: + return "YUV422_A"; + case YUV444_A: + return "YUV444_A"; + case XRGB888: + return "XRGB888"; + case XBGR888: + return "XBGR888"; + case ABGR888: + return "ABGR888"; + } + + return "invalid"; +} static ssize_t show_screen_info(struct device *dev, struct device_attribute *attr, char *buf) @@ -67,6 +104,136 @@ static ssize_t show_disp_info(struct device *dev, return 0; } +static void fill_buffer(void *handle, void *vaddr, int size) +{ + struct file *filp = handle; + + if (filp) + vfs_write(filp, vaddr, size, &filp->f_pos); +} + +static int dump_win(struct rk_fb *rk_fb, struct rk_fb_reg_area_data *area_data, + u8 data_format, int win_id, int area_id, bool is_bmp) +{ + void __iomem *vaddr; + struct file *filp; + mm_segment_t old_fs; + char name[100]; + struct ion_handle *ion_handle = area_data->ion_handle; + int width = area_data->xvir; + int height = area_data->yvir; + + if (ion_handle) { + vaddr = ion_map_kernel(rk_fb->ion_client, ion_handle); + } else if (area_data->smem_start && area_data->smem_start != -1) { + unsigned long start; + unsigned int nr_pages; + struct page **pages; + int i = 0; + + start = area_data->smem_start; + nr_pages = width * height * 3 / 2 / PAGE_SIZE; + pages = kzalloc(sizeof(struct page) * nr_pages,GFP_KERNEL); + while (i < nr_pages) { + pages[i] = phys_to_page(start); + start += PAGE_SIZE; + i++; + } + vaddr = vmap(pages, nr_pages, VM_MAP, pgprot_writecombine(PAGE_KERNEL)); + } else { + return -1; + } + + snprintf(name, 100, "/data/win%d_%d_%dx%d_%s.%s", win_id, area_id, + width, height, get_format_str(data_format), + is_bmp ? "bmp" : "bin"); + + pr_info("dump win == > /data/win%d_%d_%dx%d_%s.%s\n", win_id, area_id, + width, height, get_format_str(data_format), + is_bmp ? "bmp" : "bin"); + + filp = filp_open(name, O_RDWR | O_CREAT, 0x664); + if (!filp) + printk("fail to create %s\n", name); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + if (is_bmp) + datatobmp(vaddr, width, height, data_format, filp, fill_buffer); + else + fill_buffer(filp, vaddr, width * height * 4); + + set_fs(old_fs); + + if (ion_handle) { + ion_unmap_kernel(rk_fb->ion_client, ion_handle); + + ion_handle_put(ion_handle); + } + + filp_close(filp, NULL); + + return 0; +} + +static ssize_t set_dump_info(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + +{ + struct fb_info *fbi = dev_get_drvdata(dev); + struct rk_fb_par *fb_par = (struct rk_fb_par *)fbi->par; + struct rk_lcdc_driver *dev_drv = fb_par->lcdc_drv; + struct rk_fb *rk_fb = dev_get_drvdata(fbi->device); + struct rk_fb_reg_data *front_regs; + struct rk_fb_reg_win_data *win_data; + struct rk_fb_reg_area_data *area_data; + bool is_img; + int i, j; + + if (!rk_fb->ion_client) + return 0; + + front_regs = kmalloc(sizeof(*front_regs), GFP_KERNEL); + if (!front_regs) + return -ENOMEM; + + mutex_lock(&dev_drv->front_lock); + + if (!dev_drv->front_regs) { + mutex_unlock(&dev_drv->front_lock); + return 0; + } + memcpy(front_regs, dev_drv->front_regs, sizeof(*front_regs)); + for (i = 0; i < front_regs->win_num; i++) { + for (j = 0; j < RK_WIN_MAX_AREA; j++) { + win_data = &front_regs->reg_win_data[i]; + area_data = &win_data->reg_area_data[j]; + if (area_data->ion_handle) { + ion_handle_get(area_data->ion_handle); + } + } + } + mutex_unlock(&dev_drv->front_lock); + + if (strncmp(buf, "bin", 3)) + is_img = true; + else + is_img = false; + + for (i = 0; i < front_regs->win_num; i++) { + for (j = 0; j < RK_WIN_MAX_AREA; j++) { + win_data = &front_regs->reg_win_data[i]; + if (dump_win(rk_fb, &win_data->reg_area_data[j], + win_data->data_format, i, j, is_img)) + continue; + } + } + kfree(front_regs); + + return count; +} + static ssize_t show_phys(struct device *dev, struct device_attribute *attr, char *buf) { @@ -580,7 +747,7 @@ static ssize_t set_scale(struct device *dev, struct device_attribute *attr, static struct device_attribute rkfb_attrs[] = { __ATTR(phys_addr, S_IRUGO, show_phys, NULL), __ATTR(virt_addr, S_IRUGO, show_virt, NULL), - __ATTR(disp_info, S_IRUGO, show_disp_info, NULL), + __ATTR(disp_info, S_IRUGO | S_IWUSR, show_disp_info, set_dump_info), __ATTR(screen_info, S_IRUGO, show_screen_info, NULL), __ATTR(dual_mode, S_IRUGO, show_dual_mode, NULL), __ATTR(enable, S_IRUGO | S_IWUSR, show_fb_state, set_fb_state),