-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/
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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_ */
#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)
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)
{
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),