|
37 | 37 | #include <drm/drmP.h> |
38 | 38 | #include <drm/drm_edid.h> |
39 | 39 | #include "drm_internal.h" |
| 40 | +#include <linux/ctype.h> |
| 41 | +#include <linux/syscalls.h> |
40 | 42 |
|
41 | 43 | #if defined(CONFIG_DEBUG_FS) |
| 44 | +#define DUMP_BUF_PATH "/data/vop_buf" |
42 | 45 |
|
43 | 46 | /*************************************************** |
44 | 47 | * Initialization, etc. |
@@ -71,7 +74,219 @@ static const struct file_operations drm_debugfs_fops = { |
71 | 74 | .release = single_release, |
72 | 75 | }; |
73 | 76 |
|
| 77 | +#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) |
| 78 | +static char *get_format_str(uint32_t format) |
| 79 | +{ |
| 80 | + switch (format) { |
| 81 | + case DRM_FORMAT_XRGB8888: |
| 82 | + case DRM_FORMAT_ARGB8888: |
| 83 | + case DRM_FORMAT_XBGR8888: |
| 84 | + case DRM_FORMAT_ABGR8888: |
| 85 | + return "ARGB8888"; |
| 86 | + case DRM_FORMAT_RGB888: |
| 87 | + case DRM_FORMAT_BGR888: |
| 88 | + return "BGR888"; |
| 89 | + case DRM_FORMAT_RGB565: |
| 90 | + case DRM_FORMAT_BGR565: |
| 91 | + return "RGB565"; |
| 92 | + case DRM_FORMAT_NV12: |
| 93 | + case DRM_FORMAT_NV12_10: |
| 94 | + return "YUV420NV12"; |
| 95 | + case DRM_FORMAT_NV16: |
| 96 | + case DRM_FORMAT_NV16_10: |
| 97 | + return "YUV422NV16"; |
| 98 | + case DRM_FORMAT_NV24: |
| 99 | + case DRM_FORMAT_NV24_10: |
| 100 | + return "YUV444NV24"; |
| 101 | + default: |
| 102 | + DRM_ERROR("unsupport format[%08x]\n", format); |
| 103 | + return "UNF"; |
| 104 | + } |
| 105 | +} |
| 106 | + |
| 107 | +int vop_plane_dump(struct vop_dump_info *dump_info, int frame_count) |
| 108 | +{ |
| 109 | + int flags; |
| 110 | + int bits = 32; |
| 111 | + int fd; |
| 112 | + const char *ptr; |
| 113 | + char file_name[100]; |
| 114 | + int width; |
| 115 | + void *kvaddr; |
| 116 | + mm_segment_t old_fs; |
| 117 | + u32 format = dump_info->pixel_format; |
| 118 | + |
| 119 | + switch (format) { |
| 120 | + case DRM_FORMAT_XRGB8888: |
| 121 | + case DRM_FORMAT_ARGB8888: |
| 122 | + case DRM_FORMAT_XBGR8888: |
| 123 | + case DRM_FORMAT_ABGR8888: |
| 124 | + bits = 32; |
| 125 | + break; |
| 126 | + case DRM_FORMAT_RGB888: |
| 127 | + case DRM_FORMAT_BGR888: |
| 128 | + case DRM_FORMAT_NV24: |
| 129 | + case DRM_FORMAT_NV24_10: |
| 130 | + bits = 24; |
| 131 | + break; |
| 132 | + case DRM_FORMAT_RGB565: |
| 133 | + case DRM_FORMAT_BGR565: |
| 134 | + case DRM_FORMAT_NV16: |
| 135 | + case DRM_FORMAT_NV16_10: |
| 136 | + bits = 16; |
| 137 | + break; |
| 138 | + case DRM_FORMAT_NV12: |
| 139 | + case DRM_FORMAT_NV12_10: |
| 140 | + bits = 12; |
| 141 | + break; |
| 142 | + default: |
| 143 | + DRM_ERROR("unsupport format[%08x]\n", format); |
| 144 | + return -1; |
| 145 | + } |
| 146 | + |
| 147 | + if (dump_info->yuv_format) { |
| 148 | + width = dump_info->pitches; |
| 149 | + flags = O_RDWR | O_CREAT | O_APPEND; |
| 150 | + snprintf(file_name, 100, "%s/video%d_%d_%s.%s", DUMP_BUF_PATH, |
| 151 | + width, dump_info->height, get_format_str(format), |
| 152 | + "bin"); |
| 153 | + } else { |
| 154 | + width = dump_info->pitches >> 2; |
| 155 | + flags = O_RDWR | O_CREAT; |
| 156 | + snprintf(file_name, 100, "%s/win%d_area%d_%dx%d_%s%s%d.%s", |
| 157 | + DUMP_BUF_PATH, dump_info->win_id, |
| 158 | + dump_info->area_id, width, dump_info->height, |
| 159 | + get_format_str(format), dump_info->AFBC_flag ? |
| 160 | + "_AFBC_" : "_", frame_count, "bin"); |
| 161 | + } |
| 162 | + kvaddr = vmap(dump_info->pages, dump_info->num_pages, VM_MAP, |
| 163 | + pgprot_writecombine(PAGE_KERNEL)); |
| 164 | + if (!kvaddr) |
| 165 | + DRM_ERROR("failed to vmap() buffer\n"); |
| 166 | + else |
| 167 | + kvaddr += dump_info->offset; |
| 168 | + old_fs = get_fs(); |
| 169 | + set_fs(KERNEL_DS); |
| 170 | + sys_mkdir(DUMP_BUF_PATH, 0700); |
| 171 | + ptr = file_name; |
| 172 | + fd = sys_open(ptr, flags, 0644); |
| 173 | + if (fd >= 0) { |
| 174 | + sys_write(fd, kvaddr, width * dump_info->height * bits >> 3); |
| 175 | + DRM_INFO("dump file name is:%s\n", file_name); |
| 176 | + sys_close(fd); |
| 177 | + } else { |
| 178 | + DRM_INFO("writ fail fd err fd is %d\n", fd); |
| 179 | + } |
| 180 | + set_fs(old_fs); |
| 181 | + vunmap(kvaddr); |
| 182 | + return 0; |
| 183 | +} |
| 184 | + |
| 185 | +static int vop_dump_show(struct seq_file *m, void *data) |
| 186 | +{ |
| 187 | + seq_puts(m, " echo dump > dump to dump one frame\n"); |
| 188 | + seq_puts(m, " echo dumpon > dump to start vop keep dumping\n"); |
| 189 | + seq_puts(m, " echo dumpoff > dump to stop keep dumping\n"); |
| 190 | + seq_puts(m, " echo dumpn > dump n is the number of dump times\n"); |
| 191 | + seq_puts(m, " dump path is /data/vop_buf\n"); |
| 192 | + seq_puts(m, " if fd err = -3 try rm -r /data/vopbuf echo dump1 > dump can fix it\n"); |
| 193 | + seq_puts(m, " if fd err = -28 save needed data try rm -r /data/vopbuf\n"); |
| 194 | + return 0; |
| 195 | +} |
| 196 | + |
| 197 | +static int vop_dump_open(struct inode *inode, struct file *file) |
| 198 | +{ |
| 199 | + struct drm_crtc *crtc = inode->i_private; |
| 200 | + |
| 201 | + return single_open(file, vop_dump_show, crtc); |
| 202 | +} |
| 203 | + |
| 204 | +static int temp_pow(int sum, int n) |
| 205 | +{ |
| 206 | + int i; |
| 207 | + int temp = sum; |
74 | 208 |
|
| 209 | + if (n < 1) |
| 210 | + return 1; |
| 211 | + for (i = 1; i < n ; i++) |
| 212 | + sum *= temp; |
| 213 | + return sum; |
| 214 | +} |
| 215 | + |
| 216 | +static ssize_t vop_dump_write(struct file *file, const char __user *ubuf, |
| 217 | + size_t len, loff_t *offp) |
| 218 | +{ |
| 219 | + struct seq_file *m = file->private_data; |
| 220 | + struct drm_crtc *crtc = m->private; |
| 221 | + char buf[14]; |
| 222 | + int dump_times = 0; |
| 223 | + struct vop_dump_list *pos, *n; |
| 224 | + int i = 0; |
| 225 | + |
| 226 | + if (len > sizeof(buf) - 1) |
| 227 | + return -EINVAL; |
| 228 | + if (copy_from_user(buf, ubuf, len)) |
| 229 | + return -EFAULT; |
| 230 | + buf[len - 1] = '\0'; |
| 231 | + if (strncmp(buf, "dumpon", 6) == 0) { |
| 232 | + crtc->vop_dump_status = DUMP_KEEP; |
| 233 | + DRM_INFO("keep dumping\n"); |
| 234 | + } else if (strncmp(buf, "dumpoff", 7) == 0) { |
| 235 | + crtc->vop_dump_status = DUMP_DISABLE; |
| 236 | + DRM_INFO("close keep dumping\n"); |
| 237 | + } else if (strncmp(buf, "dump", 4) == 0) { |
| 238 | + if (isdigit(buf[4])) { |
| 239 | + for (i = 4; i < strlen(buf); i++) { |
| 240 | + dump_times += temp_pow(10, (strlen(buf) |
| 241 | + - i - 1)) |
| 242 | + * (buf[i] - '0'); |
| 243 | + } |
| 244 | + crtc->vop_dump_times = dump_times; |
| 245 | + } else { |
| 246 | + drm_modeset_lock_all(crtc->dev); |
| 247 | + list_for_each_entry_safe(pos, n, |
| 248 | + &crtc->vop_dump_list_head, |
| 249 | + entry) { |
| 250 | + vop_plane_dump(&pos->dump_info, |
| 251 | + crtc->frame_count); |
| 252 | + } |
| 253 | + drm_modeset_unlock_all(crtc->dev); |
| 254 | + crtc->frame_count++; |
| 255 | + } |
| 256 | + } else { |
| 257 | + return -EINVAL; |
| 258 | + } |
| 259 | + return len; |
| 260 | +} |
| 261 | + |
| 262 | +static const struct file_operations drm_vopdump_fops = { |
| 263 | + .owner = THIS_MODULE, |
| 264 | + .open = vop_dump_open, |
| 265 | + .read = seq_read, |
| 266 | + .llseek = seq_lseek, |
| 267 | + .release = single_release, |
| 268 | + .write = vop_dump_write, |
| 269 | +}; |
| 270 | + |
| 271 | +int drm_debugfs_vop_add(struct drm_crtc *crtc, struct dentry *root) |
| 272 | +{ |
| 273 | + struct dentry *vop_dump_root; |
| 274 | + struct dentry *ent; |
| 275 | + |
| 276 | + vop_dump_root = debugfs_create_dir("vop_dump", root); |
| 277 | + crtc->vop_dump_status = DUMP_DISABLE; |
| 278 | + crtc->vop_dump_list_init_flag = false; |
| 279 | + crtc->vop_dump_times = 0; |
| 280 | + crtc->frame_count = 0; |
| 281 | + ent = debugfs_create_file("dump", 0644, vop_dump_root, |
| 282 | + crtc, &drm_vopdump_fops); |
| 283 | + if (!ent) { |
| 284 | + DRM_ERROR("create vop_plane_dump err\n"); |
| 285 | + debugfs_remove_recursive(vop_dump_root); |
| 286 | + } |
| 287 | + return 0; |
| 288 | +} |
| 289 | +#endif |
75 | 290 | /** |
76 | 291 | * Initialize a given set of debugfs files for a device |
77 | 292 | * |
|
0 commit comments