diff options
author | Shixiang Zheng <shixiang.zheng@rock-chips.com> | 2018-04-25 15:19:19 +0800 |
---|---|---|
committer | Tao Huang <huangtao@rock-chips.com> | 2018-04-27 10:43:43 +0800 |
commit | 9fd9c79820e9e0338c7913137f6a4dc1b8be1ae0 (patch) | |
tree | 5791c09185294f958c2c7813d4707222eaf4e5a2 | |
parent | 1c40af5de0ac8ac6670f417db06b5cee8233191c (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.c | 215 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/Kconfig | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_fb.h | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 72 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 6 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 40 |
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 }; /** |