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 <mark.yao@rock-chips.com>
This commit is contained in:
Mark Yao
2014-12-03 10:05:26 +08:00
parent dec12c59c7
commit 2855e146a1
4 changed files with 388 additions and 2 deletions

View File

@@ -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/

View File

@@ -0,0 +1,171 @@
/*
* linux/drivers/video/rockchip/bmp_helper.c
*
* Copyright (C) 2012 Rockchip Corporation
* Author: Mark Yao <mark.yao@rock-chips.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <linux/sysfs.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <linux/rk_fb.h>
#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;
}

View File

@@ -0,0 +1,48 @@
/*
* drivers/video/rockchip/bmp_helper.h
*
* Copyright (C) 2012 Rockchip Corporation
* Author: Mark Yao <mark.yao@rock-chips.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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_ */

View File

@@ -29,9 +29,46 @@
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <asm/div64.h>
#include <linux/rk_screen.h>
#include <linux/rk_fb.h>
#if defined(CONFIG_ION_ROCKCHIP)
#include <linux/rockchip_ion.h>
#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),