summaryrefslogtreecommitdiff
path: root/drivers/frame_provider/decoder/utils/frame_check.c (plain)
blob: 95d260959b8a22180b377dc407c048c84f61f067
1/*
2 * drivers/amlogic/media/frame_provider/decoder/utils/frame_check.c
3 *
4 * Copyright (C) 2016 Amlogic, Inc. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 */
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/types.h>
20#include <linux/errno.h>
21#include <linux/kfifo.h>
22#include <linux/interrupt.h>
23#include <linux/semaphore.h>
24#include <linux/delay.h>
25#include <linux/timer.h>
26#include <linux/kfifo.h>
27#include <linux/kthread.h>
28#include <linux/platform_device.h>
29#include <linux/amlogic/media/canvas/canvas.h>
30#include <linux/amlogic/media/canvas/canvas_mgr.h>
31#include <linux/amlogic/media/vfm/vframe.h>
32#include <linux/amlogic/media/codec_mm/codec_mm.h>
33#include <linux/dma-mapping.h>
34#include <linux/dma-contiguous.h>
35#include <asm-generic/checksum.h>
36#include <linux/amlogic/media/codec_mm/configs.h>
37#include <linux/crc32.h>
38#include <linux/fs.h>
39#include "vdec.h"
40#include "frame_check.h"
41#include "amlogic_fbc_hook.h"
42#include <linux/highmem.h>
43#include <linux/page-flags.h>
44#include "../../../common/chips/decoder_cpu_ver_info.h"
45#include <asm/cacheflush.h>
46
47#define FC_ERROR 0x0
48
49#define FC_YUV_DEBUG 0x01
50#define FC_CRC_DEBUG 0x02
51#define FC_TST_DEBUG 0x80
52#define FC_ERR_CRC_BLOCK_MODE 0x10
53#define FC_CHECK_CRC_LOOP_MODE 0x20
54
55#define YUV_MASK 0x01
56#define CRC_MASK 0x02
57
58#define MAX_YUV_SIZE (4096 * 2304)
59#define YUV_DEF_SIZE (MAX_YUV_SIZE * 3 / 2)
60#define YUV_DEF_NUM 1
61
62#define MAX_SIZE_AFBC_PLANES (4096 * 2048)
63
64#define VMAP_STRIDE_SIZE (1024*1024)
65
66static unsigned int fc_debug;
67static unsigned int size_yuv_buf = (YUV_DEF_SIZE * YUV_DEF_NUM);
68
69#define dbg_print(mask, ...) do { \
70 if ((fc_debug & mask) || \
71 (mask == FC_ERROR)) \
72 printk("[FRMAE_CHECK] "__VA_ARGS__);\
73 } while(0)
74
75
76#define CRC_PATH "/data/tmp/"
77#define YUV_PATH "/data/tmp/"
78static char comp_crc[128] = "name";
79
80static struct vdec_s *single_mode_vdec = NULL;
81
82static unsigned int yuv_enable, check_enable;
83static unsigned int yuv_start[MAX_INSTANCE_MUN];
84static unsigned int yuv_num[MAX_INSTANCE_MUN];
85
86
87static inline void set_enable(struct pic_check_mgr_t *p, int mask)
88{
89 p->enable |= mask;
90}
91
92static inline void set_disable(struct pic_check_mgr_t *p, int mask)
93{
94 p->enable &= (~mask);
95}
96
97static inline void check_schedule(struct pic_check_mgr_t *mgr)
98{
99 if (atomic_read(&mgr->work_inited))
100 vdec_schedule_work(&mgr->frame_check_work);
101}
102
103static bool is_oversize(int w, int h)
104{
105 if (w <= 0 || h <= 0)
106 return true;
107
108 if (h != 0 && (w > (MAX_YUV_SIZE / h)))
109 return true;
110
111 return false;
112}
113
114
115static int get_frame_size(struct pic_check_mgr_t *pic,
116 struct vframe_s *vf)
117{
118 if (is_oversize(vf->width, vf->height)) {
119 dbg_print(FC_ERROR, "vf size err: w=%d, h=%d\n",
120 vf->width, vf->height);
121 return -1;
122 }
123
124 pic->size_y = vf->width * vf->height;
125 pic->size_uv = pic->size_y >> 1;
126 pic->size_pic = pic->size_y + pic->size_uv;
127
128 if (!(vf->type & VIDTYPE_VIU_NV21))
129 return 0;
130
131 if ((vf->canvas0Addr == vf->canvas1Addr) &&
132 (vf->canvas0Addr != 0) &&
133 (vf->canvas0Addr != -1)) {
134 pic->canvas_w =
135 canvas_get_width(canvasY(vf->canvas0Addr));
136 pic->canvas_h =
137 canvas_get_height(canvasY(vf->canvas0Addr));
138 } else {
139 pic->canvas_w = vf->canvas0_config[0].width;
140 pic->canvas_h = vf->canvas0_config[0].height;
141 }
142
143 if ((pic->canvas_h < 1) || (pic->canvas_w < 1)) {
144 dbg_print(FC_ERROR, "(canvas,pic) w(%d,%d), h(%d,%d)\n",
145 pic->canvas_w, vf->width, pic->canvas_h, vf->height);
146 return -1;
147 }
148/*
149 int blkmod;
150 blkmod = canvas_get_blkmode(canvasY(vf->canvas0Addr));
151 if (blkmod != CANVAS_BLKMODE_LINEAR) {
152 dbg_print(0, "WARN: canvas blkmod %x\n", blkmod);
153 }
154*/
155 return 0;
156}
157
158static int canvas_get_virt_addr(struct pic_check_mgr_t *pic,
159 struct vframe_s *vf)
160{
161 int phy_y_addr, phy_uv_addr;
162 void *vaddr_y, *vaddr_uv;
163
164 if ((vf->canvas0Addr == vf->canvas1Addr) &&
165 (vf->canvas0Addr != 0) &&
166 (vf->canvas0Addr != -1)) {
167 phy_y_addr = canvas_get_addr(canvasY(vf->canvas0Addr));
168 phy_uv_addr = canvas_get_addr(canvasUV(vf->canvas0Addr));
169 } else {
170 phy_y_addr = vf->canvas0_config[0].phy_addr;
171 phy_uv_addr = vf->canvas0_config[1].phy_addr;
172 }
173 vaddr_y = codec_mm_phys_to_virt(phy_y_addr);
174 vaddr_uv = codec_mm_phys_to_virt(phy_uv_addr);
175
176 if (((!vaddr_y) || (!vaddr_uv)) && ((!phy_y_addr) || (!phy_uv_addr))) {
177 dbg_print(FC_ERROR, "%s, y_addr %p(0x%x), uv_addr %p(0x%x)\n",
178 __func__, vaddr_y, phy_y_addr, vaddr_uv, phy_uv_addr);
179 return -1;
180 }
181 pic->y_vaddr = vaddr_y;
182 pic->uv_vaddr = vaddr_uv;
183 pic->y_phyaddr = phy_y_addr;
184 pic->uv_phyaddr = phy_uv_addr;
185
186 return 0;
187}
188
189static int str_strip(char *str)
190{
191 char *s = str;
192 int i = 0;
193
194 while (s[i]) {
195 if (s[i] == '\n')
196 s[i] = 0;
197 else if (s[i] == ' ')
198 s[i] = '_';
199 i++;
200 }
201
202 return i;
203}
204
205static char *fget_crc_str(char *buf,
206 unsigned int size, struct pic_check_t *fc)
207{
208 unsigned int c = 0, sz, ret, index, crc1, crc2;
209 mm_segment_t old_fs;
210 char *cs;
211
212 if (!fc->compare_fp)
213 return NULL;
214
215 old_fs = get_fs();
216 set_fs(KERNEL_DS);
217
218 do {
219 cs = buf;
220 sz = size;
221 while (--sz && (c = vfs_read(fc->compare_fp,
222 cs, 1, &fc->compare_pos) != 0)) {
223 if (*cs++ == '\n')
224 break;
225 }
226 *cs = '\0';
227 if ((c == 0) && (cs == buf)) {
228 set_fs(old_fs);
229 return NULL;
230 }
231 ret = sscanf(buf, "%08u: %8x %8x", &index, &crc1, &crc2);
232 dbg_print(FC_CRC_DEBUG, "%s, index = %d, cmp = %d\n",
233 __func__, index, fc->cmp_crc_cnt);
234 }while(ret != 3 || index != fc->cmp_crc_cnt);
235
236 set_fs(old_fs);
237 fc->cmp_crc_cnt++;
238
239 return buf;
240}
241
242static struct file* file_open(int mode, const char *str, ...)
243{
244 char file[256] = {0};
245 struct file* fp = NULL;
246 va_list args;
247
248 va_start(args, str);
249 vsnprintf(file, sizeof(file), str, args);
250
251 fp = filp_open(file, mode, (mode&O_CREAT)?0666:0);
252 if (IS_ERR(fp)) {
253 fp = NULL;
254 dbg_print(FC_ERROR, "open %s failed\n", file);
255 return fp;
256 }
257 dbg_print(FC_ERROR, "open %s success\n", file);
258 va_end(args);
259
260 return fp;
261}
262
263static int write_yuv_work(struct pic_check_mgr_t *mgr)
264{
265 mm_segment_t old_fs;
266 unsigned int i, wr_size, pic_num;
267 struct pic_dump_t *dump = &mgr->pic_dump;
268
269 if (dump->dump_cnt > 0) {
270 if (!dump->yuv_fp) {
271 dump->yuv_fp = file_open(O_CREAT | O_WRONLY | O_TRUNC,
272 "%s%s-%d-%d.yuv", YUV_PATH, comp_crc, mgr->id, mgr->file_cnt);
273 dump->yuv_pos = 0;
274 }
275
276 if ((mgr->enable & YUV_MASK) &&
277 (dump->yuv_fp != NULL) &&
278 (dump->dump_cnt >= dump->num)) {
279
280 i = 0;
281 pic_num = dump->dump_cnt;
282 old_fs = get_fs();
283 set_fs(KERNEL_DS);
284 while (pic_num > 0) {
285 wr_size = vfs_write(dump->yuv_fp,
286 (dump->buf_addr + i * mgr->size_pic),
287 mgr->size_pic, &dump->yuv_pos);
288 if (mgr->size_pic != wr_size) {
289 dbg_print(FC_ERROR, "buf failed to write yuv file\n");
290 break;
291 }
292 pic_num--;
293 i++;
294 }
295 set_fs(old_fs);
296 vfs_fsync(dump->yuv_fp, 0);
297
298 filp_close(dump->yuv_fp, current->files);
299 dump->yuv_pos = 0;
300 dump->yuv_fp = NULL;
301 set_disable(mgr, YUV_MASK);
302 dbg_print(FC_YUV_DEBUG,
303 "closed yuv file, dump yuv exit\n");
304 dump->num = 0;
305 dump->dump_cnt = 0;
306 if (dump->buf_addr != NULL)
307 vfree(dump->buf_addr);
308 dump->buf_addr = NULL;
309 dump->buf_size = 0;
310 }
311 }
312
313 return 0;
314}
315
316static int write_crc_work(struct pic_check_mgr_t *mgr)
317{
318 unsigned int wr_size;
319 char *crc_buf, crc_tmp[64*30];
320 mm_segment_t old_fs;
321 struct pic_check_t *check = &mgr->pic_check;
322
323 if (mgr->enable & CRC_MASK) {
324 wr_size = 0;
325 while (kfifo_get(&check->wr_chk_q, &crc_buf) != 0) {
326 wr_size += sprintf(&crc_tmp[wr_size], "%s", crc_buf);
327 if (check->compare_fp != NULL) {
328 if (!fget_crc_str(crc_buf, SIZE_CRC, check)) {
329 dbg_print(0, "%s, can't get more compare crc\n", __func__);
330 filp_close(check->compare_fp, current->files);
331 check->compare_fp = NULL;
332 }
333 }
334 kfifo_put(&check->new_chk_q, crc_buf);
335 }
336 if (check->check_fp && (wr_size != 0)) {
337 old_fs = get_fs();
338 set_fs(KERNEL_DS);
339 if (wr_size != vfs_write(check->check_fp,
340 crc_tmp, wr_size, &check->check_pos)) {
341 dbg_print(FC_ERROR, "failed to check_dump_filp\n");
342 }
343 set_fs(old_fs);
344 }
345 }
346 return 0;
347}
348
349static void do_check_work(struct work_struct *work)
350{
351 struct pic_check_mgr_t *mgr = container_of(work,
352 struct pic_check_mgr_t, frame_check_work);
353
354 write_yuv_work(mgr);
355
356 write_crc_work(mgr);
357}
358
359static int memcpy_phy_to_virt(char *to_virt,
360 ulong phy_from, unsigned int size)
361{
362 void *vaddr = NULL;
363 unsigned int tmp_size = 0;
364
365 if (single_mode_vdec != NULL) {
366 unsigned int offset = phy_from & (~PAGE_MASK);
367 while (size > 0) {
368 if (offset + size >= PAGE_SIZE) {
369 vaddr = kmap_atomic(phys_to_page(phy_from));
370 tmp_size = (PAGE_SIZE - offset);
371 phy_from += tmp_size;
372 size -= tmp_size;
373 vaddr += offset;
374 } else {
375 vaddr = kmap_atomic(phys_to_page(phy_from));
376 vaddr += offset;
377 tmp_size = size;
378 size = 0;
379 }
380 if (vaddr == NULL) {
381 dbg_print(FC_CRC_DEBUG, "%s: kmap_atomic failed phy: 0x%x\n",
382 __func__, (unsigned int)phy_from);
383 return -1;
384 }
385 /*Fixed frame error in random position of avs code stream.
386 Called in an interrupt.*/
387 flush_dcache_page(phys_to_page(phy_from));
388 /*
389 codec_mm_dma_flush(vaddr,
390 tmp_size, DMA_FROM_DEVICE);
391 */
392 memcpy(to_virt, vaddr, tmp_size);
393
394 kunmap_atomic(vaddr - offset);
395 offset = 0;
396 }
397 } else {
398 while (size > 0) {
399 if (size >= VMAP_STRIDE_SIZE) {
400 vaddr = codec_mm_vmap(phy_from, VMAP_STRIDE_SIZE);
401 tmp_size = VMAP_STRIDE_SIZE;
402 phy_from += VMAP_STRIDE_SIZE;
403 size -= VMAP_STRIDE_SIZE;
404 } else {
405 vaddr = codec_mm_vmap(phy_from, size);
406 tmp_size = size;
407 size = 0;
408 }
409 if (vaddr == NULL) {
410 dbg_print(FC_YUV_DEBUG, "%s: codec_mm_vmap failed phy: 0x%x\n",
411 __func__, (unsigned int)phy_from);
412 return -1;
413 }
414 codec_mm_dma_flush(vaddr,
415 tmp_size, DMA_FROM_DEVICE);
416 memcpy(to_virt, vaddr, tmp_size);
417 to_virt += tmp_size;
418
419 codec_mm_unmap_phyaddr(vaddr);
420 }
421 }
422 return 0;
423}
424
425static int do_yuv_dump(struct pic_check_mgr_t *mgr, struct vframe_s *vf)
426{
427 int i, ret = 0;
428 void *tmp_addr, *tmp_yaddr, *tmp_uvaddr;
429 ulong y_phyaddr, uv_phyaddr;
430 struct pic_dump_t *dump = &mgr->pic_dump;
431 /*
432 if ((vf->type & VIDTYPE_VIU_NV21) == 0)
433 return 0;
434 */
435 if (dump->start > 0) {
436 dump->start--;
437 return 0;
438 }
439
440 if (dump->dump_cnt >= dump->num)
441 return 0;
442
443 if (single_mode_vdec != NULL) {
444 if (mgr->size_pic >
445 (dump->buf_size - dump->dump_cnt * mgr->size_pic)) {
446 if (dump->buf_size) {
447 dbg_print(FC_ERROR,
448 "not enough buf, force dump less\n");
449 dump->num = dump->dump_cnt;
450 check_schedule(mgr);
451 } else
452 set_disable(mgr, YUV_MASK);
453 return -1;
454 }
455 tmp_addr = dump->buf_addr +
456 mgr->size_pic * dump->dump_cnt;
457 } else {
458 if (mgr->size_pic > dump->buf_size) {
459 dbg_print(FC_ERROR,
460 "not enough size, pic/buf size: 0x%x/0x%x\n",
461 mgr->size_pic, dump->buf_size);
462 return -1;
463 }
464 tmp_addr = dump->buf_addr;
465 }
466
467 if ((mgr->uv_vaddr == NULL) || (mgr->y_vaddr == NULL)) {
468 y_phyaddr = mgr->y_phyaddr;
469 uv_phyaddr = mgr->uv_phyaddr;
470 if (vf->width == mgr->canvas_w) {
471 ret |= memcpy_phy_to_virt(tmp_addr, y_phyaddr, mgr->size_y);
472 ret |= memcpy_phy_to_virt(tmp_addr + mgr->size_y,
473 uv_phyaddr, mgr->size_uv);
474 } else {
475 for (i = 0; i < vf->height; i++) {
476 ret |= memcpy_phy_to_virt(tmp_addr, y_phyaddr, vf->width);
477 y_phyaddr += mgr->canvas_w;
478 tmp_addr += vf->width;
479 }
480 for (i = 0; i < vf->height/2; i++) {
481 ret |= memcpy_phy_to_virt(tmp_addr, uv_phyaddr, vf->width);
482 uv_phyaddr += mgr->canvas_w;
483 tmp_addr += vf->width;
484 }
485 }
486 if (ret < 0) {
487 dbg_print(0, "dump yuv failed, may codec_mm_vmap failed\n");
488 return ret;
489 }
490 } else {
491 if (vf->width == mgr->canvas_w) {
492 memcpy(tmp_addr, mgr->y_vaddr, mgr->size_y);
493 memcpy(tmp_addr + mgr->size_y,
494 mgr->uv_vaddr, mgr->size_uv);
495 } else {
496 tmp_yaddr = mgr->y_vaddr;
497 tmp_uvaddr = mgr->uv_vaddr;
498 for (i = 0; i < vf->height; i++) {
499 memcpy(tmp_addr, tmp_yaddr, vf->width);
500 tmp_yaddr += mgr->canvas_w;
501 tmp_addr += vf->width;
502 }
503 for (i = 0; i < vf->height/2; i++) {
504 memcpy(tmp_addr, tmp_uvaddr, vf->width);
505 tmp_uvaddr += mgr->canvas_w;
506 tmp_addr += vf->width;
507 }
508 }
509 }
510 dump->dump_cnt++;
511 dbg_print(0, "----->dump %dst, size %x (%d x %d), dec total %d\n",
512 dump->dump_cnt, mgr->size_pic, vf->width, vf->height, mgr->frame_cnt);
513
514 if (single_mode_vdec != NULL) {
515 /* single mode need schedule work to write*/
516 if (dump->dump_cnt >= dump->num)
517 check_schedule(mgr);
518 } else {
519 int wr_size;
520 mm_segment_t old_fs;
521
522 /* dump for dec pic not in isr */
523 if (dump->yuv_fp == NULL) {
524 dump->yuv_fp = file_open(O_CREAT | O_WRONLY | O_TRUNC,
525 "%s%s-%d-%d.yuv", YUV_PATH, comp_crc, mgr->id, mgr->file_cnt);
526 if (dump->yuv_fp == NULL)
527 return -1;
528 }
529 old_fs = get_fs();
530 set_fs(KERNEL_DS);
531 wr_size = vfs_write(dump->yuv_fp, dump->buf_addr,
532 mgr->size_pic, &dump->yuv_pos);
533 if (mgr->size_pic != wr_size) {
534 dbg_print(FC_ERROR, "buf failed to write yuv file\n");
535 }
536 set_fs(old_fs);
537 vfs_fsync(dump->yuv_fp, 0);
538 }
539
540 return 0;
541}
542
543static int crc_store(struct pic_check_mgr_t *mgr, struct vframe_s *vf,
544 int crc_y, int crc_uv)
545{
546 int ret = 0;
547 char *crc_addr = NULL;
548 int comp_frame = 0, comp_crc_y, comp_crc_uv;
549 struct pic_check_t *check = &mgr->pic_check;
550
551 if (kfifo_get(&check->new_chk_q, &crc_addr) == 0) {
552 dbg_print(0, "%08d: %08x %08x\n",
553 mgr->frame_cnt, crc_y, crc_uv);
554 if (check->check_fp) {
555 dbg_print(0, "crc32 dropped\n");
556 } else {
557 dbg_print(0, "no opened file to write crc32\n");
558 }
559 return -1;
560 }
561 if (check->cmp_crc_cnt > mgr->frame_cnt) {
562 sscanf(crc_addr, "%08u: %8x %8x",
563 &comp_frame, &comp_crc_y, &comp_crc_uv);
564
565 dbg_print(0, "%08d: %08x %08x <--> %08d: %08x %08x\n",
566 mgr->frame_cnt, crc_y, crc_uv,
567 comp_frame, comp_crc_y, comp_crc_uv);
568
569 if (comp_frame == mgr->frame_cnt) {
570 if ((comp_crc_y != crc_y) || (crc_uv != comp_crc_uv)) {
571 mgr->pic_dump.start = 0;
572 if (fc_debug || mgr->pic_dump.num < 3)
573 mgr->pic_dump.num++;
574 dbg_print(0, "\n\nError: %08d: %08x %08x != %08x %08x\n\n",
575 mgr->frame_cnt, crc_y, crc_uv, comp_crc_y, comp_crc_uv);
576 do_yuv_dump(mgr, vf);
577 if (fc_debug & FC_ERR_CRC_BLOCK_MODE)
578 mgr->err_crc_block = 1;
579 mgr->usr_cmp_result = -mgr->frame_cnt;
580 }
581 } else {
582 mgr->usr_cmp_result = -mgr->frame_cnt;
583 dbg_print(0, "frame num error: frame_cnt(%d) frame_comp(%d)\n",
584 mgr->frame_cnt, comp_frame);
585 }
586 } else {
587 dbg_print(0, "%08d: %08x %08x\n", mgr->frame_cnt, crc_y, crc_uv);
588 }
589
590 if ((check->check_fp) && (crc_addr != NULL)) {
591 ret = snprintf(crc_addr, SIZE_CRC,
592 "%08d: %08x %08x\n", mgr->frame_cnt, crc_y, crc_uv);
593
594 kfifo_put(&check->wr_chk_q, crc_addr);
595 if ((mgr->frame_cnt & 0xf) == 0)
596 check_schedule(mgr);
597 }
598 return ret;
599}
600
601
602static int crc32_vmap_le(unsigned int *crc32,
603 ulong phyaddr, unsigned int size)
604{
605 void *vaddr = NULL;
606 unsigned int crc = *crc32;
607 unsigned int tmp_size = 0;
608
609 /*single mode cannot use codec_mm_vmap*/
610 if (single_mode_vdec != NULL) {
611 unsigned int offset = phyaddr & (~PAGE_MASK);
612 while (size > 0) {
613 if (offset + size >= PAGE_SIZE) {
614 vaddr = kmap_atomic(phys_to_page(phyaddr));
615 tmp_size = (PAGE_SIZE - offset);
616 phyaddr += tmp_size;
617 size -= tmp_size;
618 vaddr += offset;
619 } else {
620 vaddr = kmap_atomic(phys_to_page(phyaddr));
621 tmp_size = size;
622 vaddr += offset;
623 size = 0;
624 }
625 if (vaddr == NULL) {
626 dbg_print(FC_CRC_DEBUG, "%s: kmap_atomic failed phy: 0x%x\n",
627 __func__, (unsigned int)phyaddr);
628 return -1;
629 }
630 /*Fixed frame error in random position of avs code stream.
631 Called in an interrupt.*/
632 flush_dcache_page(phys_to_page(phyaddr));
633 /*
634 codec_mm_dma_flush(vaddr,
635 tmp_size, DMA_FROM_DEVICE);
636 */
637 crc = crc32_le(crc, vaddr, tmp_size);
638
639 kunmap_atomic(vaddr - offset);
640 offset = 0;
641 }
642 } else {
643 while (size > 0) {
644 if (size >= VMAP_STRIDE_SIZE) {
645 vaddr = codec_mm_vmap(phyaddr, VMAP_STRIDE_SIZE);
646 tmp_size = VMAP_STRIDE_SIZE;
647 phyaddr += VMAP_STRIDE_SIZE;
648 size -= VMAP_STRIDE_SIZE;
649 } else {
650 vaddr = codec_mm_vmap(phyaddr, size);
651 tmp_size = size;
652 size = 0;
653 }
654 if (vaddr == NULL) {
655 dbg_print(FC_CRC_DEBUG, "%s: codec_mm_vmap failed phy: 0x%x\n",
656 __func__, (unsigned int)phyaddr);
657 return -1;
658 }
659 codec_mm_dma_flush(vaddr,
660 tmp_size, DMA_FROM_DEVICE);
661
662 crc = crc32_le(crc, vaddr, tmp_size);
663
664 codec_mm_unmap_phyaddr(vaddr);
665 }
666 }
667 *crc32 = crc;
668
669 return 0;
670}
671
672static int do_check_nv21(struct pic_check_mgr_t *mgr, struct vframe_s *vf)
673{
674 int i;
675 unsigned int crc_y = 0, crc_uv = 0;
676 void *p_yaddr, *p_uvaddr;
677 ulong y_phyaddr, uv_phyaddr;
678 int ret = 0;
679
680 p_yaddr = mgr->y_vaddr;
681 p_uvaddr = mgr->uv_vaddr;
682 y_phyaddr = mgr->y_phyaddr;
683 uv_phyaddr = mgr->uv_phyaddr;
684 if ((p_yaddr == NULL) || (p_uvaddr == NULL))
685 {
686 if (vf->width == mgr->canvas_w) {
687 ret = crc32_vmap_le(&crc_y, y_phyaddr, mgr->size_y);
688 ret |= crc32_vmap_le(&crc_uv, uv_phyaddr, mgr->size_uv);
689 } else {
690 for (i = 0; i < vf->height; i++) {
691 ret |= crc32_vmap_le(&crc_y, y_phyaddr, vf->width);
692 y_phyaddr += mgr->canvas_w;
693 }
694 for (i = 0; i < vf->height/2; i++) {
695 ret |= crc32_vmap_le(&crc_uv, uv_phyaddr, vf->width);
696 uv_phyaddr += mgr->canvas_w;
697 }
698 }
699 if (ret < 0) {
700 dbg_print(0, "calc crc failed, may codec_mm_vmap failed\n");
701 return ret;
702 }
703 } else {
704 if (mgr->frame_cnt == 0) {
705 unsigned int *p = mgr->y_vaddr;
706 dbg_print(0, "YUV0000: %08x-%08x-%08x-%08x\n",
707 p[0], p[1], p[2], p[3]);
708 }
709 if (vf->width == mgr->canvas_w) {
710 crc_y = crc32_le(crc_y, p_yaddr, mgr->size_y);
711 crc_uv = crc32_le(crc_uv, p_uvaddr, mgr->size_uv);
712 } else {
713 for (i = 0; i < vf->height; i++) {
714 crc_y = crc32_le(crc_y, p_yaddr, vf->width);
715 p_yaddr += mgr->canvas_w;
716 }
717 for (i = 0; i < vf->height/2; i++) {
718 crc_uv = crc32_le(crc_uv, p_uvaddr, vf->width);
719 p_uvaddr += mgr->canvas_w;
720 }
721 }
722 }
723
724 crc_store(mgr, vf, crc_y, crc_uv);
725
726 return 0;
727}
728
729static int do_check_yuv16(struct pic_check_mgr_t *mgr,
730 struct vframe_s *vf, char *ybuf, char *uvbuf,
731 char *ubuf, char *vbuf)
732{
733 unsigned int crc1, crc2, crc3, crc4;
734 int w, h;
735
736 w = vf->width;
737 h = vf->height;
738 crc1 = 0;
739 crc2 = 0;
740 crc3 = 0;
741 crc4 = 0;
742
743 crc1 = crc32_le(0, ybuf, w * h *2);
744 crc2 = crc32_le(0, ubuf, w * h/2);
745 crc3 = crc32_le(0, vbuf, w * h/2);
746 crc4 = crc32_le(0, uvbuf, w * h*2/2);
747 /*
748 printk("%08d: %08x %08x %08x %08x\n",
749 mgr->frame_cnt, crc1, crc4, crc2, crc3);
750 */
751 mgr->size_y = w * h * 2;
752 mgr->size_uv = w * h;
753 mgr->size_pic = mgr->size_y + mgr->size_uv;
754 mgr->y_vaddr = ybuf;
755 mgr->uv_vaddr = uvbuf;
756 mgr->canvas_w = w;
757 mgr->canvas_h = h;
758 crc_store(mgr, vf, crc1, crc4);
759
760 return 0;
761}
762
763static int fbc_check_prepare(struct pic_check_t *check,
764 int resize, int y_size)
765{
766 int i = 0;
767
768 if (y_size > MAX_SIZE_AFBC_PLANES)
769 return -1;
770
771 if (((!check->fbc_planes[0]) ||
772 (!check->fbc_planes[1]) ||
773 (!check->fbc_planes[2]) ||
774 (!check->fbc_planes[3])) &&
775 (!resize))
776 return -1;
777
778 if (resize) {
779 dbg_print(0, "size changed to 0x%x(y_size)\n", y_size);
780 for (i = 0; i < ARRAY_SIZE(check->fbc_planes); i++) {
781 if (check->fbc_planes[i]) {
782 vfree(check->fbc_planes[i]);
783 check->fbc_planes[i] = NULL;
784 }
785 }
786 }
787 for (i = 0; i < ARRAY_SIZE(check->fbc_planes); i++) {
788 if (!check->fbc_planes[i])
789 check->fbc_planes[i] =
790 vmalloc(y_size * sizeof(short));
791 }
792 if ((!check->fbc_planes[0]) ||
793 (!check->fbc_planes[1]) ||
794 (!check->fbc_planes[2]) ||
795 (!check->fbc_planes[3])) {
796 dbg_print(0, "vmalloc staicplanes failed %lx %lx %lx %lx\n",
797 (ulong)check->fbc_planes[0],
798 (ulong)check->fbc_planes[1],
799 (ulong)check->fbc_planes[2],
800 (ulong)check->fbc_planes[3]);
801 for (i = 0; i < ARRAY_SIZE(check->fbc_planes); i++) {
802 if (check->fbc_planes[i]) {
803 vfree(check->fbc_planes[i]);
804 check->fbc_planes[i] = NULL;
805 }
806 }
807 return -1;
808 } else
809 dbg_print(FC_CRC_DEBUG, "vmalloc staicplanes sucessed\n");
810
811 return 0;
812}
813
814int load_user_cmp_crc(struct pic_check_mgr_t *mgr)
815{
816 int i;
817 struct pic_check_t *chk;
818 void *qaddr;
819
820 if (mgr == NULL ||
821 (mgr->cmp_pool == NULL)||
822 (mgr->usr_cmp_num == 0))
823 return 0;
824
825 chk = &mgr->pic_check;
826
827 if (chk->cmp_crc_cnt > 0) {
828 pr_info("cmp crc32 data is ready\n");
829 return -1;
830 }
831
832 if (chk->check_addr == NULL) {
833 pr_info("no cmp crc buf\n"); /* vmalloc again or return */
834 return -1;
835 }
836
837 if (mgr->usr_cmp_num >= USER_CMP_POOL_MAX_SIZE)
838 mgr->usr_cmp_num = USER_CMP_POOL_MAX_SIZE - 1;
839
840 for (i = 0; i < mgr->usr_cmp_num; i++) {
841 qaddr = chk->check_addr + i * SIZE_CRC;
842 dbg_print(FC_CRC_DEBUG, "%s, %8d: %08x %08x\n", __func__,
843 mgr->cmp_pool[i].pic_num,
844 mgr->cmp_pool[i].y_crc,
845 mgr->cmp_pool[i].uv_crc);
846 sprintf(qaddr, "%8d: %08x %08x\n",
847 mgr->cmp_pool[i].pic_num,
848 mgr->cmp_pool[i].y_crc,
849 mgr->cmp_pool[i].uv_crc);
850
851 kfifo_put(&chk->new_chk_q, qaddr);
852 chk->cmp_crc_cnt++;
853 }
854
855 mgr->usr_cmp_result = 0;
856
857 vfree(mgr->cmp_pool);
858 mgr->cmp_pool = NULL;
859
860 return 0;
861}
862
863
864int decoder_do_frame_check(struct vdec_s *vdec, struct vframe_s *vf)
865{
866 int resize = 0;
867 void *planes[4];
868 struct pic_check_t *check = NULL;
869 struct pic_check_mgr_t *mgr = NULL;
870 int ret = 0;
871
872 if (vdec == NULL) {
873 if (single_mode_vdec == NULL)
874 return 0;
875 mgr = &single_mode_vdec->vfc;
876 } else {
877 mgr = &vdec->vfc;
878 single_mode_vdec = NULL;
879 }
880
881 if ((mgr == NULL) ||
882 (vf == NULL) ||
883 (mgr->enable == 0))
884 return 0;
885
886 if (get_frame_size(mgr, vf) < 0)
887 return -1;
888
889 if (mgr->last_size_pic != mgr->size_pic) {
890 resize = 1;
891 dbg_print(0, "size changed, %x-->%x [%d x %d]\n",
892 mgr->last_size_pic, mgr->size_pic,
893 vf->width, vf->height);
894 /* for slt, if no compare crc file, use the
895 * cmp crc from amstream ioctl write */
896 load_user_cmp_crc(mgr);
897 } else
898 resize = 0;
899 mgr->last_size_pic = mgr->size_pic;
900
901 if (vf->type & VIDTYPE_VIU_NV21) {
902 if (canvas_get_virt_addr(mgr, vf) < 0)
903 return -2;
904 if ((mgr->y_vaddr) && (mgr->uv_vaddr)) {
905 codec_mm_dma_flush(mgr->y_vaddr,
906 mgr->canvas_w * mgr->canvas_h, DMA_FROM_DEVICE);
907 codec_mm_dma_flush(mgr->uv_vaddr,
908 ((mgr->canvas_w * mgr->canvas_h) >> 1), DMA_FROM_DEVICE);
909 }
910 if (mgr->enable & CRC_MASK)
911 ret = do_check_nv21(mgr, vf);
912 if (mgr->enable & YUV_MASK)
913 do_yuv_dump(mgr, vf);
914
915 } else if (vf->type & VIDTYPE_SCATTER) {
916 check = &mgr->pic_check;
917
918 if (mgr->pic_dump.buf_addr != NULL) {
919 dbg_print(0, "scatter free yuv buf\n");
920 vfree(mgr->pic_dump.buf_addr);
921 mgr->pic_dump.buf_addr = NULL;
922 }
923 if (fbc_check_prepare(check,
924 resize, mgr->size_y) < 0)
925 return -3;
926 planes[0] = check->fbc_planes[0];
927 planes[1] = check->fbc_planes[1];
928 planes[2] = check->fbc_planes[2];
929 planes[3] = check->fbc_planes[3];
930 ret = AMLOGIC_FBC_vframe_decoder(planes, vf, 0, 0);
931 if (ret < 0) {
932 dbg_print(0, "amlogic_fbc_lib.ko error %d\n", ret);
933 } else {
934 do_check_yuv16(mgr, vf,
935 (void *)planes[0], (void *)planes[3],//uv
936 (void *)planes[1], (void *)planes[2]);
937 }
938 }
939 mgr->frame_cnt++;
940
941 if (mgr->usr_cmp_num > 0) {
942 mgr->usr_cmp_num -= 1;
943 }
944
945 return ret;
946}
947EXPORT_SYMBOL(decoder_do_frame_check);
948
949static int dump_buf_alloc(struct pic_dump_t *dump)
950{
951 if ((dump->buf_addr != NULL) &&
952 (dump->buf_size != 0))
953 return 0;
954
955 dump->buf_addr =
956 (char *)vmalloc(size_yuv_buf);
957 if (!dump->buf_addr) {
958 dump->buf_size = 0;
959 dbg_print(0, "vmalloc yuv buf failed\n");
960 return -ENOMEM;
961 }
962 dump->buf_size = size_yuv_buf;
963
964 dbg_print(0, "%s: buf for yuv is alloced\n", __func__);
965
966 return 0;
967}
968
969int dump_yuv_trig(struct pic_check_mgr_t *mgr,
970 int id, int start, int num)
971{
972 struct pic_dump_t *dump = &mgr->pic_dump;
973
974 if (!dump->num) {
975 mgr->id = id;
976 dump->start = start;
977 dump->num = num;
978 dump->end = start + num;
979 dump->dump_cnt = 0;
980 dump->yuv_fp = NULL;
981 if (!atomic_read(&mgr->work_inited)) {
982 INIT_WORK(&mgr->frame_check_work, do_check_work);
983 atomic_set(&mgr->work_inited, 1);
984 }
985 dump_buf_alloc(dump);
986 str_strip(comp_crc);
987 set_enable(mgr, YUV_MASK);
988 } else {
989 dbg_print(FC_ERROR, "yuv dump now, trig later\n");
990 return -EBUSY;
991 }
992 dbg_print(0, "dump yuv trigger, from %d to %d frame\n",
993 dump->start, dump->end);
994 return 0;
995}
996
997int frame_check_init(struct pic_check_mgr_t *mgr, int id)
998{
999 int i;
1000 struct pic_dump_t *dump = &mgr->pic_dump;
1001 struct pic_check_t *check = &mgr->pic_check;
1002
1003 mgr->frame_cnt = 0;
1004 mgr->size_pic = 0;
1005 mgr->last_size_pic = 0;
1006 mgr->id = id;
1007
1008 dump->num = 0;
1009 dump->dump_cnt = 0;
1010 dump->yuv_fp = NULL;
1011 check->check_pos = 0;
1012 check->compare_pos = 0;
1013
1014 if (!atomic_read(&mgr->work_inited)) {
1015 INIT_WORK(&mgr->frame_check_work, do_check_work);
1016 atomic_set(&mgr->work_inited, 1);
1017 }
1018 /* for dump error yuv prepare. */
1019 dump_buf_alloc(dump);
1020
1021 /* try to open compare crc32 file */
1022 str_strip(comp_crc);
1023 check->compare_fp = file_open(O_RDONLY,
1024 "%s%s", CRC_PATH, comp_crc);
1025
1026 /* create crc32 log file */
1027 check->check_fp = file_open(O_CREAT| O_WRONLY | O_TRUNC,
1028 "%s%s-%d-%d.crc", CRC_PATH, comp_crc, id, mgr->file_cnt);
1029
1030 INIT_KFIFO(check->new_chk_q);
1031 INIT_KFIFO(check->wr_chk_q);
1032 check->check_addr = vmalloc(SIZE_CRC * SIZE_CHECK_Q);
1033 if (check->check_addr == NULL) {
1034 dbg_print(FC_ERROR, "vmalloc qbuf fail\n");
1035 } else {
1036 void *qaddr = NULL, *rdret = NULL;
1037 check->cmp_crc_cnt = 0;
1038 for (i = 0; i < SIZE_CHECK_Q; i++) {
1039 qaddr = check->check_addr + i * SIZE_CRC;
1040 rdret = fget_crc_str(qaddr,
1041 SIZE_CRC, check);
1042 if (rdret == NULL) {
1043 if (i < 3)
1044 dbg_print(0, "can't get compare crc string\n");
1045 if (check->compare_fp) {
1046 filp_close(check->compare_fp, current->files);
1047 check->compare_fp = NULL;
1048 }
1049 }
1050
1051 kfifo_put(&check->new_chk_q, qaddr);
1052 }
1053 }
1054 set_enable(mgr, CRC_MASK);
1055 dbg_print(0, "%s end\n", __func__);
1056
1057 return 0;
1058}
1059
1060void frame_check_exit(struct pic_check_mgr_t *mgr)
1061{
1062 int i;
1063 struct pic_dump_t *dump = &mgr->pic_dump;
1064 struct pic_check_t *check = &mgr->pic_check;
1065
1066 if (mgr->enable != 0) {
1067 if (dump->dump_cnt != 0) {
1068 dbg_print(0, "%s, cnt = %d, num = %d\n",
1069 __func__, dump->dump_cnt, dump->num);
1070 set_enable(mgr, YUV_MASK);
1071 }
1072 if (atomic_read(&mgr->work_inited)) {
1073 cancel_work_sync(&mgr->frame_check_work);
1074 atomic_set(&mgr->work_inited, 0);
1075 }
1076 if (single_mode_vdec != NULL)
1077 write_yuv_work(mgr);
1078 write_crc_work(mgr);
1079
1080 for (i = 0; i < ARRAY_SIZE(check->fbc_planes); i++) {
1081 if (check->fbc_planes[i]) {
1082 vfree(check->fbc_planes[i]);
1083 check->fbc_planes[i] = NULL;
1084 }
1085 }
1086 if (check->check_addr) {
1087 vfree(check->check_addr);
1088 check->check_addr = NULL;
1089 }
1090
1091 if (mgr->cmp_pool) {
1092 vfree(mgr->cmp_pool);
1093 mgr->cmp_pool = NULL;
1094 }
1095
1096 if (check->check_fp) {
1097 filp_close(check->check_fp, current->files);
1098 check->check_fp = NULL;
1099 }
1100 if (check->compare_fp) {
1101 filp_close(check->compare_fp, current->files);
1102 check->compare_fp = NULL;
1103 }
1104 if (dump->yuv_fp) {
1105 filp_close(dump->yuv_fp, current->files);
1106 dump->yuv_fp = NULL;
1107 }
1108 if (dump->buf_addr) {
1109 vfree(dump->buf_addr);
1110 dump->buf_addr = NULL;
1111 }
1112 mgr->file_cnt++;
1113 set_disable(mgr, YUV_MASK | CRC_MASK);
1114 dbg_print(0, "%s end\n", __func__);
1115 }
1116}
1117
1118
1119int vdec_frame_check_init(struct vdec_s *vdec)
1120{
1121 int ret = 0, id = 0;
1122
1123 if (vdec == NULL)
1124 return 0;
1125
1126 if ((vdec->is_reset) &&
1127 (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_GXL))
1128 return 0;
1129
1130 vdec->vfc.err_crc_block = 0;
1131 if (!check_enable && !yuv_enable)
1132 return 0;
1133
1134 if (vdec_single(vdec))
1135 single_mode_vdec = vdec;
1136
1137 vdec->canvas_mode = CANVAS_BLKMODE_LINEAR;
1138 id = vdec->id;
1139
1140 if (check_enable & (0x01 << id)) {
1141 frame_check_init(&vdec->vfc, id);
1142 /*repeat check one video crc32, not clear enable*/
1143 if ((fc_debug & FC_CHECK_CRC_LOOP_MODE) == 0)
1144 check_enable &= ~(0x01 << id);
1145 }
1146
1147 if (yuv_enable & (0x01 << id)) {
1148 ret = dump_yuv_trig(&vdec->vfc,
1149 id, yuv_start[id], yuv_num[id]);
1150 if (ret < 0)
1151 pr_info("dump yuv init failed\n");
1152 else {
1153 pr_info("dump yuv init ok, total %d\n",
1154 yuv_num[id]);
1155 vdec->canvas_mode = CANVAS_BLKMODE_LINEAR;
1156 }
1157 yuv_num[id] = 0;
1158 yuv_start[id] = 0;
1159 yuv_enable &= ~(0x01 << id);
1160 }
1161
1162 return ret;
1163}
1164
1165void vdec_frame_check_exit(struct vdec_s *vdec)
1166{
1167 if (vdec == NULL)
1168 return;
1169 frame_check_exit(&vdec->vfc);
1170
1171 single_mode_vdec = NULL;
1172}
1173
1174ssize_t dump_yuv_store(struct class *class,
1175 struct class_attribute *attr,
1176 const char *buf, size_t size)
1177{
1178 struct vdec_s *vdec = NULL;
1179 unsigned int id = 0, num = 0, start = 0;
1180 int ret = -1;
1181
1182 ret = sscanf(buf, "%d %d %d", &id, &start, &num);
1183 if (ret < 0) {
1184 pr_info("%s, parse failed\n", buf);
1185 return size;
1186 }
1187 if ((num == 0) || (num > YUV_MAX_DUMP_NUM)) {
1188 pr_info("requred yuv num %d, max %d\n",
1189 num, YUV_MAX_DUMP_NUM);
1190 return size;
1191 }
1192 vdec = vdec_get_vdec_by_id(id);
1193 if (vdec == NULL) {
1194 yuv_start[id] = start;
1195 yuv_num[id] = num;
1196 yuv_enable |= (1 << id);
1197 pr_info("no connected vdec.%d now, set dump ok\n", id);
1198 return size;
1199 }
1200
1201 ret = dump_yuv_trig(&vdec->vfc, id, start, num);
1202 if (ret < 0)
1203 pr_info("trigger dump yuv failed\n");
1204 else
1205 pr_info("trigger dump yuv init ok, total %d frames\n", num);
1206
1207 return size;
1208}
1209
1210ssize_t dump_yuv_show(struct class *class,
1211 struct class_attribute *attr, char *buf)
1212{
1213 int i;
1214 char *pbuf = buf;
1215
1216 for (i = 0; i < MAX_INSTANCE_MUN; i++) {
1217 pbuf += pr_info("vdec.%d, start: %d, total: %d frames\n",
1218 i, yuv_start[i], yuv_num[i]);
1219 }
1220 pbuf += sprintf(pbuf,
1221 "\nUsage: echo [id] [start] [num] > dump_yuv\n\n");
1222 return pbuf - buf;
1223}
1224
1225
1226ssize_t frame_check_store(struct class *class,
1227 struct class_attribute *attr,
1228 const char *buf, size_t size)
1229{
1230 int ret = -1;
1231 int on_off, id;
1232
1233 ret = sscanf(buf, "%d %d", &id, &on_off);
1234 if (ret < 0) {
1235 pr_info("%s, parse failed\n", buf);
1236 return size;
1237 }
1238 if (id >= MAX_INSTANCE_MUN) {
1239 pr_info("%d out of max vdec id\n", id);
1240 return size;
1241 }
1242 if (on_off)
1243 check_enable |= (1 << id);
1244 else
1245 check_enable &= ~(1 << id);
1246
1247 return size;
1248}
1249
1250ssize_t frame_check_show(struct class *class,
1251 struct class_attribute *attr, char *buf)
1252{
1253 int i;
1254 char *pbuf = buf;
1255
1256 for (i = 0; i < MAX_INSTANCE_MUN; i++) {
1257 pbuf += sprintf(pbuf,
1258 "vdec.%d\tcrc: %s\n", i,
1259 (check_enable & (0x01 << i))?"enabled":"--");
1260 }
1261 pbuf += sprintf(pbuf,
1262 "\nUsage:\techo [id] [1:on/0:off] > frame_check\n\n");
1263
1264 if (fc_debug & FC_ERR_CRC_BLOCK_MODE) {
1265 /* cat frame_check to next frame when block */
1266 struct vdec_s *vdec = NULL;
1267 vdec = vdec_get_vdec_by_id(__ffs(check_enable));
1268 if (vdec)
1269 vdec->vfc.err_crc_block = 0;
1270 }
1271
1272 return pbuf - buf;
1273}
1274
1275
1276module_param_string(comp_crc, comp_crc, 128, 0664);
1277MODULE_PARM_DESC(comp_crc, "\n crc_filename\n");
1278
1279module_param(fc_debug, uint, 0664);
1280MODULE_PARM_DESC(fc_debug, "\n frame check debug\n");
1281
1282module_param(size_yuv_buf, uint, 0664);
1283MODULE_PARM_DESC(size_yuv_buf, "\n size_yuv_buf\n");
1284
1285