summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShixiang Zheng <shixiang.zheng@rock-chips.com>2018-04-25 15:19:19 +0800
committerTao Huang <huangtao@rock-chips.com>2018-04-27 10:43:43 +0800
commit9fd9c79820e9e0338c7913137f6a4dc1b8be1ae0 (patch)
tree5791c09185294f958c2c7813d4707222eaf4e5a2
parent1c40af5de0ac8ac6670f417db06b5cee8233191c (diff)
drm/rockchip: add a debug node to dump buf from application
dump path: /data/vop_buf debug nod: d/dri/0/ff900000.vop/vop_dump/dump echo dump > dump to dump one frame echo dumpon > dump to start vop keep dumping echo dumpoff > dump to stop keep dumping echo dumpn > dump n is the number of dump times if fd err -3 try rm -r /data/vopbuf echo dump1 > dump can fix it if fd err -28 save needed data try rm -r /data/vopbuf Change-Id: Id5fefa428db1b5669ceae418cd8bddfa52e52f61 Signed-off-by: Shixiang Zheng <shixiang.zheng@rock-chips.com>
-rw-r--r--drivers/gpu/drm/drm_debugfs.c215
-rw-r--r--drivers/gpu/drm/rockchip/Kconfig14
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_fb.c10
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_fb.h9
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.c72
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.h6
-rw-r--r--include/drm/drm_crtc.h40
7 files changed, 355 insertions, 11 deletions
diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c
index 3bcf8e6a85b3..0d4604bfe8f0 100644
--- a/drivers/gpu/drm/drm_debugfs.c
+++ b/drivers/gpu/drm/drm_debugfs.c
@@ -37,8 +37,11 @@
#include <drm/drmP.h>
#include <drm/drm_edid.h>
#include "drm_internal.h"
+#include <linux/ctype.h>
+#include <linux/syscalls.h>
#if defined(CONFIG_DEBUG_FS)
+#define DUMP_BUF_PATH "/data/vop_buf"
/***************************************************
* Initialization, etc.
@@ -71,7 +74,219 @@ static const struct file_operations drm_debugfs_fops = {
.release = single_release,
};
+#if defined(CONFIG_ROCKCHIP_DRM_DEBUG)
+static char *get_format_str(uint32_t format)
+{
+ switch (format) {
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_ABGR8888:
+ return "ARGB8888";
+ case DRM_FORMAT_RGB888:
+ case DRM_FORMAT_BGR888:
+ return "BGR888";
+ case DRM_FORMAT_RGB565:
+ case DRM_FORMAT_BGR565:
+ return "RGB565";
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV12_10:
+ return "YUV420NV12";
+ case DRM_FORMAT_NV16:
+ case DRM_FORMAT_NV16_10:
+ return "YUV422NV16";
+ case DRM_FORMAT_NV24:
+ case DRM_FORMAT_NV24_10:
+ return "YUV444NV24";
+ default:
+ DRM_ERROR("unsupport format[%08x]\n", format);
+ return "UNF";
+ }
+}
+
+int vop_plane_dump(struct vop_dump_info *dump_info, int frame_count)
+{
+ int flags;
+ int bits = 32;
+ int fd;
+ const char *ptr;
+ char file_name[100];
+ int width;
+ void *kvaddr;
+ mm_segment_t old_fs;
+ u32 format = dump_info->pixel_format;
+
+ switch (format) {
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_ABGR8888:
+ bits = 32;
+ break;
+ case DRM_FORMAT_RGB888:
+ case DRM_FORMAT_BGR888:
+ case DRM_FORMAT_NV24:
+ case DRM_FORMAT_NV24_10:
+ bits = 24;
+ break;
+ case DRM_FORMAT_RGB565:
+ case DRM_FORMAT_BGR565:
+ case DRM_FORMAT_NV16:
+ case DRM_FORMAT_NV16_10:
+ bits = 16;
+ break;
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV12_10:
+ bits = 12;
+ break;
+ default:
+ DRM_ERROR("unsupport format[%08x]\n", format);
+ return -1;
+ }
+
+ if (dump_info->yuv_format) {
+ width = dump_info->pitches;
+ flags = O_RDWR | O_CREAT | O_APPEND;
+ snprintf(file_name, 100, "%s/video%d_%d_%s.%s", DUMP_BUF_PATH,
+ width, dump_info->height, get_format_str(format),
+ "bin");
+ } else {
+ width = dump_info->pitches >> 2;
+ flags = O_RDWR | O_CREAT;
+ snprintf(file_name, 100, "%s/win%d_area%d_%dx%d_%s%s%d.%s",
+ DUMP_BUF_PATH, dump_info->win_id,
+ dump_info->area_id, width, dump_info->height,
+ get_format_str(format), dump_info->AFBC_flag ?
+ "_AFBC_" : "_", frame_count, "bin");
+ }
+ kvaddr = vmap(dump_info->pages, dump_info->num_pages, VM_MAP,
+ pgprot_writecombine(PAGE_KERNEL));
+ if (!kvaddr)
+ DRM_ERROR("failed to vmap() buffer\n");
+ else
+ kvaddr += dump_info->offset;
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ sys_mkdir(DUMP_BUF_PATH, 0700);
+ ptr = file_name;
+ fd = sys_open(ptr, flags, 0644);
+ if (fd >= 0) {
+ sys_write(fd, kvaddr, width * dump_info->height * bits >> 3);
+ DRM_INFO("dump file name is:%s\n", file_name);
+ sys_close(fd);
+ } else {
+ DRM_INFO("writ fail fd err fd is %d\n", fd);
+ }
+ set_fs(old_fs);
+ vunmap(kvaddr);
+ return 0;
+}
+
+static int vop_dump_show(struct seq_file *m, void *data)
+{
+ seq_puts(m, " echo dump > dump to dump one frame\n");
+ seq_puts(m, " echo dumpon > dump to start vop keep dumping\n");
+ seq_puts(m, " echo dumpoff > dump to stop keep dumping\n");
+ seq_puts(m, " echo dumpn > dump n is the number of dump times\n");
+ seq_puts(m, " dump path is /data/vop_buf\n");
+ seq_puts(m, " if fd err = -3 try rm -r /data/vopbuf echo dump1 > dump can fix it\n");
+ seq_puts(m, " if fd err = -28 save needed data try rm -r /data/vopbuf\n");
+ return 0;
+}
+
+static int vop_dump_open(struct inode *inode, struct file *file)
+{
+ struct drm_crtc *crtc = inode->i_private;
+
+ return single_open(file, vop_dump_show, crtc);
+}
+
+static int temp_pow(int sum, int n)
+{
+ int i;
+ int temp = sum;
+ if (n < 1)
+ return 1;
+ for (i = 1; i < n ; i++)
+ sum *= temp;
+ return sum;
+}
+
+static ssize_t vop_dump_write(struct file *file, const char __user *ubuf,
+ size_t len, loff_t *offp)
+{
+ struct seq_file *m = file->private_data;
+ struct drm_crtc *crtc = m->private;
+ char buf[14];
+ int dump_times = 0;
+ struct vop_dump_list *pos, *n;
+ int i = 0;
+
+ if (len > sizeof(buf) - 1)
+ return -EINVAL;
+ if (copy_from_user(buf, ubuf, len))
+ return -EFAULT;
+ buf[len - 1] = '\0';
+ if (strncmp(buf, "dumpon", 6) == 0) {
+ crtc->vop_dump_status = DUMP_KEEP;
+ DRM_INFO("keep dumping\n");
+ } else if (strncmp(buf, "dumpoff", 7) == 0) {
+ crtc->vop_dump_status = DUMP_DISABLE;
+ DRM_INFO("close keep dumping\n");
+ } else if (strncmp(buf, "dump", 4) == 0) {
+ if (isdigit(buf[4])) {
+ for (i = 4; i < strlen(buf); i++) {
+ dump_times += temp_pow(10, (strlen(buf)
+ - i - 1))
+ * (buf[i] - '0');
+ }
+ crtc->vop_dump_times = dump_times;
+ } else {
+ drm_modeset_lock_all(crtc->dev);
+ list_for_each_entry_safe(pos, n,
+ &crtc->vop_dump_list_head,
+ entry) {
+ vop_plane_dump(&pos->dump_info,
+ crtc->frame_count);
+ }
+ drm_modeset_unlock_all(crtc->dev);
+ crtc->frame_count++;
+ }
+ } else {
+ return -EINVAL;
+ }
+ return len;
+}
+
+static const struct file_operations drm_vopdump_fops = {
+ .owner = THIS_MODULE,
+ .open = vop_dump_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = vop_dump_write,
+};
+
+int drm_debugfs_vop_add(struct drm_crtc *crtc, struct dentry *root)
+{
+ struct dentry *vop_dump_root;
+ struct dentry *ent;
+
+ vop_dump_root = debugfs_create_dir("vop_dump", root);
+ crtc->vop_dump_status = DUMP_DISABLE;
+ crtc->vop_dump_list_init_flag = false;
+ crtc->vop_dump_times = 0;
+ crtc->frame_count = 0;
+ ent = debugfs_create_file("dump", 0644, vop_dump_root,
+ crtc, &drm_vopdump_fops);
+ if (!ent) {
+ DRM_ERROR("create vop_plane_dump err\n");
+ debugfs_remove_recursive(vop_dump_root);
+ }
+ return 0;
+}
+#endif
/**
* Initialize a given set of debugfs files for a device
*
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index d9950333cdd7..57958c04f5d7 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -16,6 +16,20 @@ config DRM_ROCKCHIP
2D or 3D acceleration; acceleration is performed by other
IP found on the SoC.
+config ROCKCHIP_DRM_DEBUG
+ tristate "Rockchip DRM debug"
+ depends on DRM_ROCKCHIP
+ help
+ This option add a debug nod to dump buf from application.
+ dump path: /data/vop_buf
+ debug nod: d/dri/0/ff900000.vop/vop_dump/dump
+ echo dump > dump to dump one frame
+ echo dumpon > dump to start vop keep dumping
+ echo dumpoff > dump to stop keep dumping
+ echo dumpn > dump n is the number of dump times
+ if fd err -3 try rm -r /data/vopbuf echo dump1 > dump can fix it
+ if fd err -28 save needed data try rm -r /data/vopbuf
+
config ROCKCHIP_CDN_DP
tristate "Rockchip cdn DP"
depends on DRM_ROCKCHIP
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index ee50aef6b16c..a85d12eb98cc 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -27,16 +27,6 @@
#include "rockchip_drm_gem.h"
#include "rockchip_drm_backlight.h"
-#define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb)
-
-struct rockchip_drm_fb {
- struct drm_framebuffer fb;
- dma_addr_t dma_addr[ROCKCHIP_MAX_FB_BUFFER];
- void *kvaddr[ROCKCHIP_MAX_FB_BUFFER];
- struct drm_gem_object *obj[ROCKCHIP_MAX_FB_BUFFER];
- struct rockchip_logo *logo;
-};
-
bool rockchip_fb_is_logo(struct drm_framebuffer *fb)
{
struct rockchip_drm_fb *rk_fb = to_rockchip_fb(fb);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h
index ea96bf359b2a..a2351124c4c8 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h
@@ -53,4 +53,13 @@ rockchip_dmcfreq_vop_bandwidth_update(struct devfreq *devfreq,
}
#endif
+#define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb)
+
+struct rockchip_drm_fb {
+ struct drm_framebuffer fb;
+ dma_addr_t dma_addr[ROCKCHIP_MAX_FB_BUFFER];
+ void *kvaddr[ROCKCHIP_MAX_FB_BUFFER];
+ struct drm_gem_object *obj[ROCKCHIP_MAX_FB_BUFFER];
+ struct rockchip_logo *logo;
+};
#endif /* _ROCKCHIP_DRM_FB_H */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 99b62bafb238..df966d4b233a 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -178,6 +178,7 @@ struct vop_plane_state {
bool enable;
int global_alpha;
int blend_mode;
+ unsigned long offset;
};
struct vop_win {
@@ -1531,6 +1532,7 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
}
offset = (src->x1 >> 16) * drm_format_plane_bpp(fb->pixel_format, 0) / 8;
+ vop_plane_state->offset = offset + fb->offsets[0];
if (state->rotation & BIT(DRM_REFLECT_Y) ||
(rockchip_fb_is_logo(fb) && vop_plane_state->logo_ymirror))
offset += ((src->y2 >> 16) - 1) * fb->pitches[0];
@@ -1626,6 +1628,29 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
uint32_t val;
bool rb_swap, global_alpha_en;
+#if defined(CONFIG_ROCKCHIP_DRM_DEBUG)
+ bool AFBC_flag = false;
+ struct vop_dump_list *planlist;
+ unsigned long num_pages;
+ struct page **pages;
+ struct rockchip_drm_fb *rk_fb;
+ struct drm_gem_object *obj;
+ struct rockchip_gem_object *rk_obj;
+
+ num_pages = 0;
+ pages = NULL;
+ rk_fb = to_rockchip_fb(fb);
+ obj = rk_fb->obj[0];
+ rk_obj = to_rockchip_obj(obj);
+ if (rk_obj) {
+ num_pages = rk_obj->num_pages;
+ pages = rk_obj->pages;
+ }
+ if (fb->modifier[0] == DRM_FORMAT_MOD_ARM_AFBC)
+ AFBC_flag = true;
+ else
+ AFBC_flag = false;
+#endif
/*
* can't update plane when vop is disabled.
*/
@@ -1728,6 +1753,32 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
* actual_w, actual_h)
*/
vop->is_iommu_needed = true;
+
+#if defined(CONFIG_ROCKCHIP_DRM_DEBUG)
+ planlist = kmalloc(sizeof(*planlist), GFP_KERNEL);
+ if (planlist) {
+ planlist->dump_info.AFBC_flag = AFBC_flag;
+ planlist->dump_info.area_id = win->area_id;
+ planlist->dump_info.win_id = win->win_id;
+ planlist->dump_info.yuv_format =
+ is_yuv_support(fb->pixel_format);
+ planlist->dump_info.num_pages = num_pages;
+ planlist->dump_info.pages = pages;
+ planlist->dump_info.offset = vop_plane_state->offset;
+ planlist->dump_info.pitches = fb->pitches[0];
+ planlist->dump_info.height = actual_h;
+ planlist->dump_info.pixel_format = fb->pixel_format;
+ list_add_tail(&planlist->entry, &crtc->vop_dump_list_head);
+ } else {
+ DRM_ERROR("can't alloc a node of planlist %p\n", planlist);
+ return;
+ }
+ if (crtc->vop_dump_status == DUMP_KEEP ||
+ crtc->vop_dump_times > 0) {
+ vop_plane_dump(&planlist->dump_info, crtc->frame_count);
+ crtc->vop_dump_times--;
+ }
+#endif
}
static const struct drm_plane_helper_funcs plane_helper_funcs = {
@@ -2145,7 +2196,9 @@ static int vop_crtc_debugfs_init(struct drm_minor *minor, struct drm_crtc *crtc)
ret = -ENOMEM;
goto remove;
}
-
+#if defined(CONFIG_ROCKCHIP_DRM_DEBUG)
+ drm_debugfs_vop_add(crtc, vop->debugfs);
+#endif
for (i = 0; i < ARRAY_SIZE(vop_debugfs_files); i++)
vop->debugfs_files[i].data = vop;
@@ -2830,6 +2883,23 @@ static int vop_crtc_atomic_check(struct drm_crtc *crtc,
int dsp_layer_sel = 0;
int i, j, cnt = 0, ret = 0;
+#if defined(CONFIG_ROCKCHIP_DRM_DEBUG)
+ struct vop_dump_list *pos, *n;
+
+ if (!crtc->vop_dump_list_init_flag) {
+ INIT_LIST_HEAD(&crtc->vop_dump_list_head);
+ crtc->vop_dump_list_init_flag = true;
+ }
+ list_for_each_entry_safe(pos, n, &crtc->vop_dump_list_head, entry) {
+ list_del(&pos->entry);
+ kfree(pos);
+ }
+ if (crtc->vop_dump_status == DUMP_KEEP ||
+ crtc->vop_dump_times > 0) {
+ crtc->frame_count++;
+ }
+#endif
+
ret = vop_afbdc_atomic_check(crtc, crtc_state);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index 3f909c5d220f..531503a8fba9 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -689,4 +689,10 @@ static inline int interpolate(int x1, int y1, int x2, int y2, int x)
}
extern const struct component_ops vop_component_ops;
+
+#if defined(CONFIG_ROCKCHIP_DRM_DEBUG)
+int drm_debugfs_vop_add(struct drm_crtc *crtc, struct dentry *root);
+int vop_plane_dump(struct vop_dump_info *dump_info, int frame_count);
+#endif
+
#endif /* _ROCKCHIP_DRM_VOP_H */
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 1ff48539154a..4b06e1aa2885 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -525,6 +525,31 @@ struct drm_crtc_funcs {
void (*early_unregister)(struct drm_crtc *crtc);
};
+#if defined(CONFIG_ROCKCHIP_DRM_DEBUG)
+struct vop_dump_info {
+ int win_id;
+ int area_id;
+ unsigned int pitches;
+ unsigned int height;
+ u32 pixel_format;
+ bool AFBC_flag;
+ bool yuv_format;
+ unsigned long offset;
+ unsigned long num_pages;
+ struct page **pages;
+};
+
+struct vop_dump_list {
+ struct list_head entry;
+ struct vop_dump_info dump_info;
+};
+
+enum vop_dump_status {
+ DUMP_DISABLE = 0,
+ DUMP_KEEP
+};
+#endif
+
/**
* struct drm_crtc - central CRTC control structure
* @dev: parent DRM device
@@ -629,6 +654,21 @@ struct drm_crtc {
* context.
*/
struct drm_modeset_acquire_ctx *acquire_ctx;
+
+#if defined(CONFIG_ROCKCHIP_DRM_DEBUG)
+ /**
+ * @vop_dump_status the status of vop dump control
+ * @vop_dump_list_head the list head of vop dump list
+ * @vop_dump_list_init_flag init once
+ * @vop_dump_times control the dump times
+ * @frme_count the frame of dump buf
+ */
+ enum vop_dump_status vop_dump_status;
+ struct list_head vop_dump_list_head;
+ bool vop_dump_list_init_flag;
+ int vop_dump_times;
+ int frame_count;
+#endif
};
/**