| /* |
| * drivers/amlogic/media/frame_provider/decoder/utils/frame_check.c |
| * |
| * Copyright (C) 2016 Amlogic, Inc. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * 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. |
| * |
| */ |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/types.h> |
| #include <linux/errno.h> |
| #include <linux/kfifo.h> |
| #include <linux/interrupt.h> |
| #include <linux/semaphore.h> |
| #include <linux/delay.h> |
| #include <linux/timer.h> |
| #include <linux/kfifo.h> |
| #include <linux/kthread.h> |
| #include <linux/vmalloc.h> |
| #include <linux/platform_device.h> |
| #include <linux/amlogic/media/vfm/vframe.h> |
| #include <linux/amlogic/media/codec_mm/codec_mm.h> |
| #include <linux/dma-mapping.h> |
| #include <linux/dma-contiguous.h> |
| #include <asm-generic/checksum.h> |
| #include <linux/amlogic/media/codec_mm/configs.h> |
| #include <linux/crc32.h> |
| #include <linux/fs.h> |
| #include "vdec.h" |
| #include "frame_check.h" |
| #include "amlogic_fbc_hook.h" |
| #include <linux/highmem.h> |
| #include <linux/page-flags.h> |
| #include "../../../common/chips/decoder_cpu_ver_info.h" |
| #include <asm/cacheflush.h> |
| |
| #define FC_ERROR 0x0 |
| |
| #define FC_YUV_DEBUG 0x01 |
| #define FC_CRC_DEBUG 0x02 |
| #define FC_TST_DEBUG 0x80 |
| #define FC_ERR_CRC_BLOCK_MODE 0x10 |
| #define FC_CHECK_CRC_LOOP_MODE 0x20 |
| #define AD_CHECK_CRC_LOOP_MODE 0x40 |
| |
| #define YUV_MASK 0x01 |
| #define CRC_MASK 0x02 |
| #define AUX_MASK 0x04 |
| |
| |
| #define MAX_YUV_SIZE (4096 * 2304) |
| #define YUV_DEF_SIZE (MAX_YUV_SIZE * 3 / 2) |
| #define YUV_DEF_NUM 1 |
| |
| #define MAX_SIZE_AFBC_PLANES (4096 * 2048) |
| |
| #define VMAP_STRIDE_SIZE (1024*1024) |
| |
| static unsigned int fc_debug; |
| static unsigned int size_yuv_buf = (YUV_DEF_SIZE * YUV_DEF_NUM); |
| |
| #define dbg_print(mask, ...) do { \ |
| if ((fc_debug & mask) || \ |
| (mask == FC_ERROR)) \ |
| printk("[FRAME_CHECK] "__VA_ARGS__);\ |
| } while(0) |
| |
| |
| #define CRC_PATH "/data/tmp/" |
| #define YUV_PATH "/data/tmp/" |
| static char comp_crc[128] = "name"; |
| static char aux_comp_crc[128] = "aux"; |
| |
| static struct vdec_s *single_mode_vdec = NULL; |
| |
| static unsigned int yuv_enable, check_enable; |
| static unsigned int aux_enable; |
| static unsigned int yuv_start[MAX_INSTANCE_MUN]; |
| static unsigned int yuv_num[MAX_INSTANCE_MUN]; |
| |
| #define CHECKSUM_PATH "/data/local/tmp/" |
| static char checksum_info[128] = "checksum info"; |
| static char checksum_filename[128] = "checksum"; |
| static unsigned int checksum_enable; |
| static unsigned int checksum_start_count; |
| |
| static const char * const format_name[] = { |
| "MPEG12", |
| "MPEG4", |
| "H264", |
| "MJPEG", |
| "REAL", |
| "JPEG", |
| "VC1", |
| "AVS", |
| "YUV", |
| "H264MVC", |
| "H264_4K2K", |
| "HEVC", |
| "H264_ENC", |
| "JPEG_ENC", |
| "VP9", |
| "AVS2", |
| "AV1", |
| }; |
| |
| static const char *get_format_name(int format) |
| { |
| if (format < 17 && format >= 0) |
| return format_name[format]; |
| else |
| return "Unknow"; |
| } |
| |
| |
| static inline void set_enable(struct pic_check_mgr_t *p, int mask) |
| { |
| p->enable |= mask; |
| } |
| |
| static inline void set_disable(struct pic_check_mgr_t *p, int mask) |
| { |
| p->enable &= (~mask); |
| } |
| |
| static inline void aux_set_enable(struct aux_data_check_mgr_t *p, int mask) |
| { |
| p->enable |= mask; |
| } |
| |
| static inline void aux_set_disable(struct aux_data_check_mgr_t *p, int mask) |
| { |
| p->enable &= (~mask); |
| } |
| |
| |
| static inline void check_schedule(struct pic_check_mgr_t *mgr) |
| { |
| if (atomic_read(&mgr->work_inited)) |
| vdec_schedule_work(&mgr->frame_check_work); |
| } |
| |
| static inline void aux_data_check_schedule(struct aux_data_check_mgr_t *mgr) |
| { |
| if (atomic_read(&mgr->work_inited)) |
| vdec_schedule_work(&mgr->aux_data_check_work); |
| } |
| |
| static bool is_oversize(int w, int h) |
| { |
| if (w <= 0 || h <= 0) |
| return true; |
| |
| if (h != 0 && (w > (MAX_YUV_SIZE / h))) |
| return true; |
| |
| return false; |
| } |
| |
| unsigned long vdec_cav_get_addr(int index); |
| unsigned int vdec_cav_get_width(int index); |
| unsigned int vdec_cav_get_height(int index); |
| #define canvas_0(v) ((v) & 0xff) |
| #define canvas_1(v) (((v) >> 8) & 0xff) |
| #define canvas_2(v) (((v) >> 16) & 0xff) |
| #define canvas_3(v) (((v) >> 24) & 0xff) |
| |
| #define canvasY(v) canvas_0(v) |
| #define canvasU(v) canvas_1(v) |
| #define canvasV(v) canvas_2(v) |
| #define canvasUV(v) canvas_1(v) |
| |
| static int get_frame_size(struct pic_check_mgr_t *pic, |
| struct vframe_s *vf) |
| { |
| if (is_oversize(vf->width, vf->height)) { |
| dbg_print(FC_ERROR, "vf size err: w=%d, h=%d\n", |
| vf->width, vf->height); |
| return -1; |
| } |
| pic->height = vf->height; |
| pic->width = vf->width; |
| pic->size_y = vf->width * vf->height; |
| pic->size_uv = pic->size_y >> (1 + pic->mjpeg_flag); |
| pic->size_pic = pic->size_y + (pic->size_y >> 1); |
| |
| if ((!(vf->type & VIDTYPE_VIU_NV21)) && (!pic->mjpeg_flag)) |
| return 0; |
| |
| if ((vf->canvas0Addr == vf->canvas1Addr) && |
| (vf->canvas0Addr != 0) && |
| (vf->canvas0Addr != -1)) { |
| pic->canvas_w = vdec_cav_get_width(canvasY(vf->canvas0Addr)); |
| //canvas_get_width(canvasY(vf->canvas0Addr)); |
| pic->canvas_h = vdec_cav_get_height(canvasY(vf->canvas0Addr)); |
| //canvas_get_height(canvasY(vf->canvas0Addr)); |
| } else { |
| pic->canvas_w = vf->canvas0_config[0].width; |
| pic->canvas_h = vf->canvas0_config[0].height; |
| } |
| |
| if ((pic->canvas_h < 1) || (pic->canvas_w < 1)) { |
| dbg_print(FC_ERROR, "(canvas,pic) w(%d,%d), h(%d,%d)\n", |
| pic->canvas_w, vf->width, pic->canvas_h, vf->height); |
| return -1; |
| } |
| /* |
| int blkmod; |
| blkmod = canvas_get_blkmode(canvasY(vf->canvas0Addr)); |
| if (blkmod != CANVAS_BLKMODE_LINEAR) { |
| dbg_print(0, "WARN: canvas blkmod %x\n", blkmod); |
| } |
| */ |
| return 0; |
| } |
| |
| static int canvas_get_virt_addr(struct pic_check_mgr_t *pic, |
| struct vframe_s *vf) |
| { |
| unsigned long phy_y_addr, phy_uv_addr; |
| void *vaddr_y, *vaddr_uv; |
| |
| if ((vf->canvas0Addr == vf->canvas1Addr) && |
| (vf->canvas0Addr != 0) && |
| (vf->canvas0Addr != -1)) { |
| phy_y_addr = vdec_cav_get_addr(canvasY(vf->canvas0Addr)); //canvas_get_addr(canvasY(vf->canvas0Addr)); |
| phy_uv_addr = vdec_cav_get_addr(canvasUV(vf->canvas0Addr)); //canvas_get_addr(canvasUV(vf->canvas0Addr)); |
| } else { |
| phy_y_addr = vf->canvas0_config[0].phy_addr; |
| phy_uv_addr = vf->canvas0_config[1].phy_addr; |
| } |
| vaddr_y = codec_mm_phys_to_virt(phy_y_addr); |
| vaddr_uv = codec_mm_phys_to_virt(phy_uv_addr); |
| |
| if (((!vaddr_y) || (!vaddr_uv)) && ((!phy_y_addr) || (!phy_uv_addr))) { |
| dbg_print(FC_ERROR, "%s, y_addr %p(0x%lx), uv_addr %p(0x%lx)\n", |
| __func__, vaddr_y, phy_y_addr, vaddr_uv, phy_uv_addr); |
| return -1; |
| } |
| pic->y_vaddr = vaddr_y; |
| pic->uv_vaddr = vaddr_uv; |
| pic->y_phyaddr = phy_y_addr; |
| pic->uv_phyaddr = phy_uv_addr; |
| |
| if (pic->mjpeg_flag) { |
| if ((vf->canvas0Addr == vf->canvas1Addr) && |
| (vf->canvas0Addr != 0) && |
| (vf->canvas0Addr != -1)) { |
| pic->extra_v_phyaddr = canvas_get_addr(canvasV(vf->canvas0Addr)); |
| } else { |
| pic->extra_v_phyaddr = vf->canvas0_config[2].phy_addr; |
| } |
| pic->extra_v_vaddr = codec_mm_phys_to_virt(phy_uv_addr); |
| |
| if (!pic->extra_v_vaddr && !pic->extra_v_phyaddr) |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| static int str_strip(char *str) |
| { |
| char *s = str; |
| int i = 0; |
| |
| while (s[i]) { |
| if (s[i] == '\n') |
| s[i] = 0; |
| else if (s[i] == ' ') |
| s[i] = '_'; |
| i++; |
| } |
| |
| return i; |
| } |
| |
| static char *fget_crc_str(char *buf, |
| unsigned int size, struct pic_check_t *fc) |
| { |
| unsigned int c = 0, sz, ret, index, crc1, crc2; |
| mm_segment_t old_fs; |
| char *cs; |
| |
| if (!fc->compare_fp) |
| return NULL; |
| |
| old_fs = get_fs(); |
| set_fs(KERNEL_DS); |
| |
| do { |
| cs = buf; |
| sz = size; |
| while (--sz && (c = vfs_read(fc->compare_fp, |
| cs, 1, &fc->compare_pos) != 0)) { |
| if (*cs++ == '\n') |
| break; |
| } |
| *cs = '\0'; |
| if ((c == 0) && (cs == buf)) { |
| set_fs(old_fs); |
| return NULL; |
| } |
| ret = sscanf(buf, "%08u: %8x %8x", &index, &crc1, &crc2); |
| dbg_print(FC_CRC_DEBUG, "%s, index = %d, cmp = %d\n", |
| __func__, index, fc->cmp_crc_cnt); |
| }while(ret != 3 || index != fc->cmp_crc_cnt); |
| |
| set_fs(old_fs); |
| fc->cmp_crc_cnt++; |
| |
| return buf; |
| } |
| |
| static char *fget_aux_data_crc_str(char *buf, |
| unsigned int size, struct aux_data_check_t *fc) |
| { |
| unsigned int c = 0, sz, ret, index, crc; |
| mm_segment_t old_fs; |
| char *cs; |
| |
| if (!fc->compare_fp) |
| return NULL; |
| |
| old_fs = get_fs(); |
| set_fs(KERNEL_DS); |
| |
| do { |
| cs = buf; |
| sz = size; |
| while (--sz && (c = vfs_read(fc->compare_fp, |
| cs, 1, &fc->compare_pos) != 0)) { |
| if (*cs++ == '\n') |
| break; |
| } |
| *cs = '\0'; |
| if ((c == 0) && (cs == buf)) { |
| set_fs(old_fs); |
| return NULL; |
| } |
| ret = sscanf(buf, "%08u: %8x", &index, &crc); |
| dbg_print(FC_CRC_DEBUG, "%s, index = %d, cmp = %d\n", |
| __func__, index, fc->cmp_crc_cnt); |
| }while(ret != 2 || index != fc->cmp_crc_cnt); |
| |
| set_fs(old_fs); |
| fc->cmp_crc_cnt++; |
| |
| return buf; |
| } |
| |
| |
| static struct file* file_open(int mode, const char *str, ...) |
| { |
| char file[256] = {0}; |
| struct file* fp = NULL; |
| va_list args; |
| |
| va_start(args, str); |
| vsnprintf(file, sizeof(file), str, args); |
| |
| fp = filp_open(file, mode, (mode&O_CREAT)?0666:0); |
| if (IS_ERR(fp)) { |
| fp = NULL; |
| dbg_print(FC_ERROR, "open %s failed\n", file); |
| va_end(args); |
| return fp; |
| } |
| dbg_print(FC_ERROR, "open %s success\n", file); |
| va_end(args); |
| |
| return fp; |
| } |
| |
| static int write_yuv_work(struct pic_check_mgr_t *mgr) |
| { |
| mm_segment_t old_fs; |
| unsigned int i, wr_size, pic_num; |
| struct pic_dump_t *dump = &mgr->pic_dump; |
| |
| if (dump->dump_cnt > 0) { |
| if (!dump->yuv_fp) { |
| dump->yuv_fp = file_open(O_CREAT | O_WRONLY | O_TRUNC, |
| "%s%s-%d-%d.yuv", YUV_PATH, comp_crc, mgr->id, mgr->file_cnt); |
| dump->yuv_pos = 0; |
| } |
| |
| if ((mgr->enable & YUV_MASK) && |
| (dump->yuv_fp != NULL) && |
| (dump->dump_cnt >= dump->num)) { |
| |
| i = 0; |
| pic_num = dump->dump_cnt; |
| old_fs = get_fs(); |
| set_fs(KERNEL_DS); |
| while (pic_num > 0) { |
| wr_size = vfs_write(dump->yuv_fp, |
| (dump->buf_addr + i * mgr->size_pic), |
| mgr->size_pic, &dump->yuv_pos); |
| if (mgr->size_pic != wr_size) { |
| dbg_print(FC_ERROR, "buf failed to write yuv file\n"); |
| break; |
| } |
| pic_num--; |
| i++; |
| } |
| set_fs(old_fs); |
| vfs_fsync(dump->yuv_fp, 0); |
| |
| filp_close(dump->yuv_fp, current->files); |
| dump->yuv_pos = 0; |
| dump->yuv_fp = NULL; |
| set_disable(mgr, YUV_MASK); |
| dbg_print(FC_YUV_DEBUG, |
| "closed yuv file, dump yuv exit\n"); |
| dump->num = 0; |
| dump->dump_cnt = 0; |
| if (dump->buf_addr != NULL) |
| vfree(dump->buf_addr); |
| dump->buf_addr = NULL; |
| dump->buf_size = 0; |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int write_crc_work(struct pic_check_mgr_t *mgr) |
| { |
| unsigned int wr_size; |
| char *crc_buf, *crc_tmp = NULL; |
| mm_segment_t old_fs; |
| struct pic_check_t *check = &mgr->pic_check; |
| |
| crc_tmp = (char *)vzalloc(64 * 30); |
| if (!crc_tmp) |
| return -1; |
| |
| if (mgr->enable & CRC_MASK) { |
| wr_size = 0; |
| while (kfifo_get(&check->wr_chk_q, &crc_buf) != 0) { |
| wr_size += sprintf(&crc_tmp[wr_size], "%s", crc_buf); |
| if (check->compare_fp != NULL) { |
| if (!fget_crc_str(crc_buf, SIZE_CRC, check)) { |
| dbg_print(0, "%s, can't get more compare crc\n", __func__); |
| filp_close(check->compare_fp, current->files); |
| check->compare_fp = NULL; |
| } |
| } |
| kfifo_put(&check->new_chk_q, crc_buf); |
| } |
| if (check->check_fp && (wr_size != 0)) { |
| old_fs = get_fs(); |
| set_fs(KERNEL_DS); |
| if (wr_size != vfs_write(check->check_fp, |
| crc_tmp, wr_size, &check->check_pos)) { |
| dbg_print(FC_ERROR, "failed to check_dump_filp\n"); |
| } |
| set_fs(old_fs); |
| } |
| } |
| |
| vfree(crc_tmp); |
| return 0; |
| } |
| |
| static int write_aux_data_crc_work(struct aux_data_check_mgr_t *mgr) |
| { |
| unsigned int wr_size; |
| char *crc_buf, crc_tmp[64*30]; |
| mm_segment_t old_fs; |
| struct aux_data_check_t *check = &mgr->aux_data_check; |
| |
| if (mgr->enable & AUX_MASK) { |
| wr_size = 0; |
| while (kfifo_get(&check->wr_chk_q, &crc_buf) != 0) { |
| wr_size += sprintf(&crc_tmp[wr_size], "%s", crc_buf); |
| if (check->compare_fp != NULL) { |
| if (!fget_aux_data_crc_str(crc_buf, SIZE_CRC, check)) { |
| dbg_print(0, "%s, can't get more compare crc\n", __func__); |
| filp_close(check->compare_fp, current->files); |
| check->compare_fp = NULL; |
| } |
| } |
| kfifo_put(&check->new_chk_q, crc_buf); |
| } |
| if (check->check_fp && (wr_size != 0)) { |
| old_fs = get_fs(); |
| set_fs(KERNEL_DS); |
| if (wr_size != vfs_write(check->check_fp, |
| crc_tmp, wr_size, &check->check_pos)) { |
| dbg_print(FC_ERROR, "failed to check_dump_filp\n"); |
| } |
| set_fs(old_fs); |
| } |
| } |
| return 0; |
| } |
| |
| static void do_check_work(struct work_struct *work) |
| { |
| struct pic_check_mgr_t *mgr = container_of(work, |
| struct pic_check_mgr_t, frame_check_work); |
| |
| write_yuv_work(mgr); |
| |
| write_crc_work(mgr); |
| } |
| |
| static void do_aux_data_check_work(struct work_struct *work) |
| { |
| struct aux_data_check_mgr_t *mgr = container_of(work, |
| struct aux_data_check_mgr_t, aux_data_check_work); |
| |
| write_aux_data_crc_work(mgr); |
| } |
| |
| |
| static int memcpy_phy_to_virt(char *to_virt, |
| ulong phy_from, unsigned int size) |
| { |
| void *vaddr = NULL; |
| unsigned int tmp_size = 0; |
| |
| if (single_mode_vdec != NULL) { |
| unsigned int offset = phy_from & (~PAGE_MASK); |
| while (size > 0) { |
| /* flush dcache in isr. */ |
| flush_dcache_page(phys_to_page(phy_from)); |
| |
| if (offset + size >= PAGE_SIZE) { |
| vaddr = kmap_atomic(phys_to_page(phy_from)); |
| tmp_size = (PAGE_SIZE - offset); |
| phy_from += tmp_size; //for next loop; |
| size -= tmp_size; |
| vaddr += offset; |
| } else { |
| vaddr = kmap_atomic(phys_to_page(phy_from)); |
| vaddr += offset; |
| tmp_size = size; |
| size = 0; |
| } |
| if (vaddr == NULL) { |
| dbg_print(FC_CRC_DEBUG, "%s: kmap_atomic failed phy: 0x%x\n", |
| __func__, (unsigned int)phy_from); |
| return -1; |
| } |
| |
| memcpy(to_virt, vaddr, tmp_size); |
| to_virt += tmp_size; |
| |
| kunmap_atomic(vaddr - offset); |
| offset = 0; |
| } |
| } else { |
| while (size > 0) { |
| if (size >= VMAP_STRIDE_SIZE) { |
| vaddr = codec_mm_vmap(phy_from, VMAP_STRIDE_SIZE); |
| tmp_size = VMAP_STRIDE_SIZE; |
| phy_from += VMAP_STRIDE_SIZE; |
| size -= VMAP_STRIDE_SIZE; |
| } else { |
| vaddr = codec_mm_vmap(phy_from, size); |
| tmp_size = size; |
| size = 0; |
| } |
| if (vaddr == NULL) { |
| dbg_print(FC_YUV_DEBUG, "%s: codec_mm_vmap failed phy: 0x%x\n", |
| __func__, (unsigned int)phy_from); |
| return -1; |
| } |
| codec_mm_dma_flush(vaddr, |
| tmp_size, DMA_FROM_DEVICE); |
| memcpy(to_virt, vaddr, tmp_size); |
| to_virt += tmp_size; |
| |
| codec_mm_unmap_phyaddr(vaddr); |
| } |
| } |
| return 0; |
| } |
| |
| |
| static int do_yuv_unit_cp(void **addr, ulong phy, void *virt, |
| int h, int w, int stride) |
| { |
| int ret = 0, i; |
| void *tmp = *addr; |
| |
| if ((phy != 0) && (virt == NULL)) { |
| for (i = 0; i < h; i++) { |
| ret |= memcpy_phy_to_virt(tmp, phy, w); |
| phy += stride; |
| tmp += w; |
| } |
| } else { |
| for (i = 0; i < h; i++) { |
| memcpy(tmp, virt, w); |
| virt += stride; |
| tmp += w; |
| } |
| } |
| *addr = tmp; |
| |
| return ret; |
| } |
| |
| static int do_yuv_dump(struct pic_check_mgr_t *mgr, struct vframe_s *vf) |
| { |
| int ret = 0; |
| void *tmp_addr; |
| struct pic_dump_t *dump = &mgr->pic_dump; |
| |
| if (dump->start > 0) { |
| dump->start--; |
| return 0; |
| } |
| |
| if (dump->dump_cnt >= dump->num) { |
| mgr->enable &= (~YUV_MASK); |
| dump->num = 0; |
| dump->dump_cnt = 0; |
| return 0; |
| } |
| |
| if (single_mode_vdec != NULL) { |
| if (mgr->size_pic > |
| (dump->buf_size - dump->dump_cnt * mgr->size_pic)) { |
| if (dump->buf_size) { |
| dbg_print(FC_ERROR, |
| "not enough buf for single mode, force dump less\n"); |
| dump->num = dump->dump_cnt; |
| check_schedule(mgr); |
| } else |
| set_disable(mgr, YUV_MASK); |
| return -1; |
| } |
| tmp_addr = dump->buf_addr + |
| mgr->size_pic * dump->dump_cnt; |
| } else { |
| if (mgr->size_pic > dump->buf_size) { |
| dbg_print(FC_ERROR, |
| "not enough size, pic/buf size: 0x%x/0x%x\n", |
| mgr->size_pic, dump->buf_size); |
| return -1; |
| } |
| tmp_addr = dump->buf_addr; |
| } |
| |
| if (vf->width == mgr->canvas_w) { |
| if ((mgr->uv_vaddr == NULL) || (mgr->y_vaddr == NULL)) { |
| ret |= memcpy_phy_to_virt(tmp_addr, mgr->y_phyaddr, mgr->size_y); |
| ret |= memcpy_phy_to_virt(tmp_addr + mgr->size_y, |
| mgr->uv_phyaddr, mgr->size_uv); |
| if (mgr->mjpeg_flag) /*mjpeg yuv420 u v is separate */ |
| ret |= memcpy_phy_to_virt(tmp_addr + mgr->size_y + mgr->size_uv, |
| mgr->extra_v_phyaddr, mgr->size_uv); |
| } else { |
| memcpy(tmp_addr, mgr->y_vaddr, mgr->size_y); |
| memcpy(tmp_addr + mgr->size_y, mgr->uv_vaddr, mgr->size_uv); |
| if (mgr->mjpeg_flag) /*mjpeg u v is separate */ |
| memcpy(tmp_addr + mgr->size_y + mgr->size_uv, |
| mgr->extra_v_vaddr, mgr->size_uv); |
| } |
| } else { |
| u32 uv_stride, uv_cpsize; |
| ret |= do_yuv_unit_cp(&tmp_addr, mgr->y_phyaddr, mgr->y_vaddr, |
| vf->height, vf->width, mgr->canvas_w); |
| |
| uv_stride = (mgr->mjpeg_flag) ? (mgr->canvas_w >> 1) : mgr->canvas_w; |
| uv_cpsize = (mgr->mjpeg_flag) ? (vf->width >> 1) : vf->width; |
| ret |= do_yuv_unit_cp(&tmp_addr, mgr->uv_phyaddr, mgr->uv_vaddr, |
| vf->height >> 1, uv_cpsize, uv_stride); |
| |
| if (mgr->mjpeg_flag) { |
| ret |= do_yuv_unit_cp(&tmp_addr, mgr->extra_v_phyaddr, mgr->extra_v_vaddr, |
| vf->height >> 1, uv_cpsize, uv_stride); |
| } |
| } |
| |
| dump->dump_cnt++; |
| dbg_print(0, "----->dump %dst, size %x (%d x %d), dec total %d\n", |
| dump->dump_cnt, mgr->size_pic, vf->width, vf->height, mgr->frame_cnt); |
| |
| if (single_mode_vdec != NULL) { |
| /* single mode need schedule work to write*/ |
| if (dump->dump_cnt >= dump->num) |
| check_schedule(mgr); |
| } else { |
| int wr_size; |
| mm_segment_t old_fs; |
| |
| /* dump for dec pic not in isr */ |
| if (dump->yuv_fp == NULL) { |
| dump->yuv_fp = file_open(O_CREAT | O_WRONLY | O_TRUNC, |
| "%s%s-%d-%d.yuv", YUV_PATH, comp_crc, mgr->id, mgr->file_cnt); |
| if (dump->yuv_fp == NULL) |
| return -1; |
| mgr->file_cnt++; |
| } |
| old_fs = get_fs(); |
| set_fs(KERNEL_DS); |
| wr_size = vfs_write(dump->yuv_fp, dump->buf_addr, |
| mgr->size_pic, &dump->yuv_pos); |
| if (mgr->size_pic != wr_size) { |
| dbg_print(FC_ERROR, "buf failed to write yuv file\n"); |
| } |
| set_fs(old_fs); |
| vfs_fsync(dump->yuv_fp, 0); |
| } |
| |
| return 0; |
| } |
| |
| static int crc_store(struct pic_check_mgr_t *mgr, struct vframe_s *vf, |
| int crc_y, int crc_uv) |
| { |
| int ret = 0; |
| char *crc_addr = NULL; |
| int comp_frame = 0, comp_crc_y, comp_crc_uv; |
| struct pic_check_t *check = &mgr->pic_check; |
| |
| mgr->yuvsum += crc_uv; |
| mgr->yuvsum += crc_y; |
| |
| if (kfifo_get(&check->new_chk_q, &crc_addr) == 0) { |
| dbg_print(0, "%08d: %08x %08x\n", |
| mgr->frame_cnt, crc_y, crc_uv); |
| if (check->check_fp) { |
| dbg_print(0, "crc32 dropped\n"); |
| } else { |
| dbg_print(0, "no opened file to write crc32\n"); |
| } |
| return -1; |
| } |
| if (check->cmp_crc_cnt > mgr->frame_cnt) { |
| sscanf(crc_addr, "%08u: %8x %8x", |
| &comp_frame, &comp_crc_y, &comp_crc_uv); |
| |
| dbg_print(0, "%08d: %08x %08x <--> %08d: %08x %08x\n", |
| mgr->frame_cnt, crc_y, crc_uv, |
| comp_frame, comp_crc_y, comp_crc_uv); |
| |
| if (comp_frame == mgr->frame_cnt) { |
| if ((comp_crc_y != crc_y) || (crc_uv != comp_crc_uv)) { |
| mgr->pic_dump.start = 0; |
| if (fc_debug || mgr->pic_dump.num < 3) |
| mgr->pic_dump.num++; |
| dbg_print(0, "\n\nError: %08d: %08x %08x != %08x %08x\n\n", |
| mgr->frame_cnt, crc_y, crc_uv, comp_crc_y, comp_crc_uv); |
| if (!(vf->type & VIDTYPE_SCATTER)) |
| do_yuv_dump(mgr, vf); |
| if (fc_debug & FC_ERR_CRC_BLOCK_MODE) |
| mgr->err_crc_block = 1; |
| mgr->usr_cmp_result = -1; |
| } |
| } else { |
| mgr->usr_cmp_result = -1; |
| dbg_print(0, "frame num error: frame_cnt(%d) frame_comp(%d)\n", |
| mgr->frame_cnt, comp_frame); |
| } |
| } else { |
| dbg_print(0, "%08d: %08x %08x\n", mgr->frame_cnt, crc_y, crc_uv); |
| } |
| |
| if ((check->check_fp) && (crc_addr != NULL)) { |
| ret = snprintf(crc_addr, SIZE_CRC, |
| "%08d: %08x %08x\n", mgr->frame_cnt, crc_y, crc_uv); |
| |
| kfifo_put(&check->wr_chk_q, crc_addr); |
| if ((mgr->frame_cnt & 0xf) == 0) |
| check_schedule(mgr); |
| } |
| return ret; |
| } |
| |
| static int aux_data_crc_store(struct aux_data_check_mgr_t *mgr,int crc) |
| { |
| int ret = 0; |
| char *crc_addr = NULL; |
| int comp_frame = 0, comp_crc; |
| struct aux_data_check_t *check = &mgr->aux_data_check; |
| |
| if (kfifo_get(&check->new_chk_q, &crc_addr) == 0) { |
| dbg_print(0, "%08d: %08x\n", |
| mgr->frame_cnt, crc); |
| if (check->check_fp) { |
| dbg_print(0, "crc32 dropped\n"); |
| } else { |
| dbg_print(0, "no opened file to write crc32\n"); |
| } |
| return -1; |
| } |
| if (check->cmp_crc_cnt > mgr->frame_cnt) { |
| sscanf(crc_addr, "%08u: %8x", |
| &comp_frame, &comp_crc); |
| |
| dbg_print(0, "%08d: %08x <--> %08d: %08x\n", |
| mgr->frame_cnt, crc, |
| comp_frame, comp_crc); |
| if (comp_frame == mgr->frame_cnt) { |
| if (comp_crc != crc) { |
| dbg_print(0, "\n\nError: %08d: %08x != %08x \n\n", |
| mgr->frame_cnt, crc, comp_crc); |
| } |
| } else { |
| dbg_print(0, "frame num error: frame_cnt(%d) frame_comp(%d)\n", |
| mgr->frame_cnt, comp_frame); |
| } |
| } else { |
| dbg_print(0, "%08d: %08x\n", mgr->frame_cnt, crc); |
| } |
| |
| if ((check->check_fp) && (crc_addr != NULL)) { |
| ret = snprintf(crc_addr, SIZE_CRC, |
| "%08d: %08x\n", mgr->frame_cnt, crc); |
| |
| kfifo_put(&check->wr_chk_q, crc_addr); |
| if ((mgr->frame_cnt & 0xf) == 0) |
| aux_data_check_schedule(mgr); |
| } |
| return ret; |
| } |
| |
| |
| |
| static int crc32_vmap_le(unsigned int *crc32, |
| ulong phyaddr, unsigned int size) |
| { |
| void *vaddr = NULL; |
| unsigned int crc = *crc32; |
| unsigned int tmp_size = 0; |
| |
| /*single mode cannot use codec_mm_vmap*/ |
| if (single_mode_vdec != NULL) { |
| unsigned int offset = phyaddr & (~PAGE_MASK); |
| while (size > 0) { |
| /*flush dcache in isr.*/ |
| flush_dcache_page(phys_to_page(phyaddr)); |
| |
| if (offset + size >= PAGE_SIZE) { |
| vaddr = kmap_atomic(phys_to_page(phyaddr)); |
| tmp_size = (PAGE_SIZE - offset); |
| phyaddr += tmp_size; |
| size -= tmp_size; |
| vaddr += offset; |
| } else { |
| vaddr = kmap_atomic(phys_to_page(phyaddr)); |
| tmp_size = size; |
| vaddr += offset; |
| size = 0; |
| } |
| if (vaddr == NULL) { |
| dbg_print(FC_CRC_DEBUG, "%s: kmap_atomic failed phy: 0x%x\n", |
| __func__, (unsigned int)phyaddr); |
| return -1; |
| } |
| |
| crc = crc32_le(crc, vaddr, tmp_size); |
| |
| kunmap_atomic(vaddr - offset); |
| offset = 0; |
| } |
| } else { |
| while (size > 0) { |
| if (size >= VMAP_STRIDE_SIZE) { |
| vaddr = codec_mm_vmap(phyaddr, VMAP_STRIDE_SIZE); |
| tmp_size = VMAP_STRIDE_SIZE; |
| phyaddr += VMAP_STRIDE_SIZE; |
| size -= VMAP_STRIDE_SIZE; |
| } else { |
| vaddr = codec_mm_vmap(phyaddr, size); |
| tmp_size = size; |
| size = 0; |
| } |
| if (vaddr == NULL) { |
| dbg_print(FC_CRC_DEBUG, "%s: codec_mm_vmap failed phy: 0x%x\n", |
| __func__, (unsigned int)phyaddr); |
| return -1; |
| } |
| codec_mm_dma_flush(vaddr, |
| tmp_size, DMA_FROM_DEVICE); |
| |
| crc = crc32_le(crc, vaddr, tmp_size); |
| |
| codec_mm_unmap_phyaddr(vaddr); |
| } |
| } |
| *crc32 = crc; |
| |
| return 0; |
| } |
| |
| static int do_check_nv21(struct pic_check_mgr_t *mgr, struct vframe_s *vf) |
| { |
| int i; |
| unsigned int crc_y = 0, crc_uv = 0; |
| void *p_yaddr, *p_uvaddr; |
| ulong y_phyaddr, uv_phyaddr; |
| int ret = 0; |
| |
| p_yaddr = mgr->y_vaddr; |
| p_uvaddr = mgr->uv_vaddr; |
| y_phyaddr = mgr->y_phyaddr; |
| uv_phyaddr = mgr->uv_phyaddr; |
| if ((p_yaddr == NULL) || (p_uvaddr == NULL)) |
| { |
| if (vf->width == mgr->canvas_w) { |
| ret = crc32_vmap_le(&crc_y, y_phyaddr, mgr->size_y); |
| ret |= crc32_vmap_le(&crc_uv, uv_phyaddr, mgr->size_uv); |
| } else { |
| for (i = 0; i < vf->height; i++) { |
| ret |= crc32_vmap_le(&crc_y, y_phyaddr, vf->width); |
| y_phyaddr += mgr->canvas_w; |
| } |
| for (i = 0; i < vf->height/2; i++) { |
| ret |= crc32_vmap_le(&crc_uv, uv_phyaddr, vf->width); |
| uv_phyaddr += mgr->canvas_w; |
| } |
| } |
| if (ret < 0) { |
| dbg_print(0, "calc crc failed, may codec_mm_vmap failed\n"); |
| return ret; |
| } |
| } else { |
| if (mgr->frame_cnt == 0) { |
| unsigned int *p = mgr->y_vaddr; |
| dbg_print(0, "YUV0000: %08x-%08x-%08x-%08x\n", |
| p[0], p[1], p[2], p[3]); |
| } |
| if (vf->width == mgr->canvas_w) { |
| crc_y = crc32_le(crc_y, p_yaddr, mgr->size_y); |
| crc_uv = crc32_le(crc_uv, p_uvaddr, mgr->size_uv); |
| } else { |
| for (i = 0; i < vf->height; i++) { |
| crc_y = crc32_le(crc_y, p_yaddr, vf->width); |
| p_yaddr += mgr->canvas_w; |
| } |
| for (i = 0; i < vf->height/2; i++) { |
| crc_uv = crc32_le(crc_uv, p_uvaddr, vf->width); |
| p_uvaddr += mgr->canvas_w; |
| } |
| } |
| } |
| |
| crc_store(mgr, vf, crc_y, crc_uv); |
| |
| return 0; |
| } |
| |
| static int do_check_yuv16(struct pic_check_mgr_t *mgr, |
| struct vframe_s *vf, char *ybuf, char *uvbuf, |
| char *ubuf, char *vbuf) |
| { |
| unsigned int crc1, crc2, crc3, crc4; |
| int w, h; |
| |
| w = vf->width; |
| h = vf->height; |
| crc1 = 0; |
| crc2 = 0; |
| crc3 = 0; |
| crc4 = 0; |
| |
| crc1 = crc32_le(0, ybuf, w * h *2); |
| crc2 = crc32_le(0, ubuf, w * h/2); |
| crc3 = crc32_le(0, vbuf, w * h/2); |
| crc4 = crc32_le(0, uvbuf, w * h*2/2); |
| /* |
| printk("%08d: %08x %08x %08x %08x\n", |
| mgr->frame_cnt, crc1, crc4, crc2, crc3); |
| */ |
| mgr->size_y = w * h * 2; |
| mgr->size_uv = w * h; |
| mgr->size_pic = mgr->size_y + mgr->size_uv; |
| mgr->y_vaddr = ybuf; |
| mgr->uv_vaddr = uvbuf; |
| mgr->canvas_w = w; |
| mgr->canvas_h = h; |
| crc_store(mgr, vf, crc1, crc4); |
| |
| return 0; |
| } |
| |
| static int do_check_aux_data_crc(struct aux_data_check_mgr_t *mgr, |
| char *aux_buf, int size) |
| { |
| unsigned int crc = 0; |
| |
| crc = crc32_le(0, aux_buf, size); |
| |
| //pr_info("%s:crc = %08x\n",crc); |
| aux_data_crc_store(mgr,crc); |
| |
| return 0; |
| } |
| |
| |
| static int fbc_check_prepare(struct pic_check_t *check, |
| int resize, int y_size) |
| { |
| int i = 0; |
| |
| if (y_size > MAX_SIZE_AFBC_PLANES) |
| return -1; |
| |
| if (((!check->fbc_planes[0]) || |
| (!check->fbc_planes[1]) || |
| (!check->fbc_planes[2]) || |
| (!check->fbc_planes[3])) && |
| (!resize)) |
| return -1; |
| |
| if (resize) { |
| dbg_print(0, "size changed to 0x%x(y_size)\n", y_size); |
| for (i = 0; i < ARRAY_SIZE(check->fbc_planes); i++) { |
| if (check->fbc_planes[i]) { |
| vfree(check->fbc_planes[i]); |
| check->fbc_planes[i] = NULL; |
| } |
| } |
| } |
| for (i = 0; i < ARRAY_SIZE(check->fbc_planes); i++) { |
| if (!check->fbc_planes[i]) |
| check->fbc_planes[i] = |
| vmalloc(y_size * sizeof(short)); |
| } |
| if ((!check->fbc_planes[0]) || |
| (!check->fbc_planes[1]) || |
| (!check->fbc_planes[2]) || |
| (!check->fbc_planes[3])) { |
| dbg_print(0, "vmalloc staicplanes failed %lx %lx %lx %lx\n", |
| (ulong)check->fbc_planes[0], |
| (ulong)check->fbc_planes[1], |
| (ulong)check->fbc_planes[2], |
| (ulong)check->fbc_planes[3]); |
| for (i = 0; i < ARRAY_SIZE(check->fbc_planes); i++) { |
| if (check->fbc_planes[i]) { |
| vfree(check->fbc_planes[i]); |
| check->fbc_planes[i] = NULL; |
| } |
| } |
| return -1; |
| } else |
| dbg_print(FC_CRC_DEBUG, "vmalloc staicplanes sucessed\n"); |
| |
| return 0; |
| } |
| |
| int load_user_cmp_crc(struct pic_check_mgr_t *mgr) |
| { |
| int i; |
| struct pic_check_t *chk; |
| void *qaddr; |
| |
| if (mgr == NULL || |
| (mgr->cmp_pool == NULL)|| |
| (mgr->usr_cmp_num == 0)) |
| return 0; |
| |
| chk = &mgr->pic_check; |
| |
| if (chk->cmp_crc_cnt > 0) { |
| pr_info("cmp crc32 data is ready\n"); |
| return -1; |
| } |
| |
| if (chk->check_addr == NULL) { |
| pr_info("no cmp crc buf\n"); /* vmalloc again or return */ |
| return -1; |
| } |
| |
| if (mgr->usr_cmp_num >= USER_CMP_POOL_MAX_SIZE) |
| mgr->usr_cmp_num = USER_CMP_POOL_MAX_SIZE - 1; |
| |
| for (i = 0; i < mgr->usr_cmp_num; i++) { |
| qaddr = chk->check_addr + i * SIZE_CRC; |
| dbg_print(FC_CRC_DEBUG, "%s, %8d: %08x %08x\n", __func__, |
| mgr->cmp_pool[i].pic_num, |
| mgr->cmp_pool[i].y_crc, |
| mgr->cmp_pool[i].uv_crc); |
| sprintf(qaddr, "%8d: %08x %08x\n", |
| mgr->cmp_pool[i].pic_num, |
| mgr->cmp_pool[i].y_crc, |
| mgr->cmp_pool[i].uv_crc); |
| |
| kfifo_put(&chk->new_chk_q, qaddr); |
| chk->cmp_crc_cnt++; |
| } |
| |
| mgr->usr_cmp_result = 0; |
| |
| vfree(mgr->cmp_pool); |
| mgr->cmp_pool = NULL; |
| |
| return 0; |
| } |
| |
| |
| int decoder_do_frame_check(struct vdec_s *vdec, struct vframe_s *vf) |
| { |
| int resize = 0; |
| void *planes[4]; |
| struct pic_check_t *check = NULL; |
| struct pic_check_mgr_t *mgr = NULL; |
| int ret = 0; |
| |
| if (vdec == NULL) { |
| if (single_mode_vdec == NULL) |
| return 0; |
| mgr = &single_mode_vdec->vfc; |
| } else { |
| mgr = &vdec->vfc; |
| single_mode_vdec = NULL; |
| } |
| |
| if (!single_mode_vdec && |
| unlikely(in_interrupt())) |
| return 0; |
| |
| if ((mgr == NULL) || (vf == NULL) || |
| (mgr->enable == 0)) |
| return 0; |
| |
| mgr->mjpeg_flag = ((vdec) && |
| (vdec->format == VFORMAT_MJPEG)) ? 1 : 0; |
| |
| if (get_frame_size(mgr, vf) < 0) |
| return -1; |
| |
| if (mgr->last_size_pic != mgr->size_pic) { |
| resize = 1; |
| dbg_print(0, "size changed, %x-->%x [%d x %d]\n", |
| mgr->last_size_pic, mgr->size_pic, |
| vf->width, vf->height); |
| /* for slt, if no compare crc file, use the |
| * cmp crc from amstream ioctl write */ |
| load_user_cmp_crc(mgr); |
| } else |
| resize = 0; |
| mgr->last_size_pic = mgr->size_pic; |
| |
| if ((vf->type & VIDTYPE_VIU_NV21) || (mgr->mjpeg_flag) || |
| (vf->type & VIDTYPE_VIU_NV12)) { |
| int flush_size; |
| |
| if (canvas_get_virt_addr(mgr, vf) < 0) |
| return -2; |
| |
| /* flush */ |
| flush_size = mgr->mjpeg_flag ? |
| ((mgr->canvas_w * mgr->canvas_h) >> 2) : |
| ((mgr->canvas_w * mgr->canvas_h) >> 1); |
| if (mgr->y_vaddr) |
| codec_mm_dma_flush(mgr->y_vaddr, |
| mgr->canvas_w * mgr->canvas_h, DMA_FROM_DEVICE); |
| if (mgr->uv_vaddr) |
| codec_mm_dma_flush(mgr->uv_vaddr, |
| flush_size, DMA_FROM_DEVICE); |
| if ((mgr->mjpeg_flag) && (mgr->extra_v_vaddr)) |
| codec_mm_dma_flush(mgr->extra_v_vaddr, |
| flush_size, DMA_FROM_DEVICE); |
| |
| if (mgr->enable & CRC_MASK) |
| ret = do_check_nv21(mgr, vf); |
| |
| if (mgr->enable & YUV_MASK) |
| do_yuv_dump(mgr, vf); |
| |
| } else if (vf->type & VIDTYPE_SCATTER) { |
| check = &mgr->pic_check; |
| |
| if (mgr->pic_dump.buf_addr != NULL) { |
| dbg_print(0, "scatter free yuv buf\n"); |
| vfree(mgr->pic_dump.buf_addr); |
| mgr->pic_dump.buf_addr = NULL; |
| } |
| if (fbc_check_prepare(check, |
| resize, mgr->size_y) < 0) |
| return -3; |
| planes[0] = check->fbc_planes[0]; |
| planes[1] = check->fbc_planes[1]; |
| planes[2] = check->fbc_planes[2]; |
| planes[3] = check->fbc_planes[3]; |
| ret = AMLOGIC_FBC_vframe_decoder(planes, vf, 0, 0); |
| if (ret < 0) { |
| dbg_print(0, "amlogic_fbc_lib.ko error %d\n", ret); |
| } else { |
| do_check_yuv16(mgr, vf, |
| (void *)planes[0], (void *)planes[3],//uv |
| (void *)planes[1], (void *)planes[2]); |
| } |
| } |
| mgr->frame_cnt++; |
| |
| if (mgr->usr_cmp_num > 0) { |
| mgr->usr_cmp_num -= 1; |
| } |
| |
| return ret; |
| } |
| EXPORT_SYMBOL(decoder_do_frame_check); |
| |
| int decoder_do_aux_data_check(struct vdec_s *vdec, char *aux_buffer, int size) |
| { |
| struct aux_data_check_mgr_t *mgr = NULL; |
| int ret = 0; |
| |
| if (vdec == NULL) { |
| return 0; |
| } else { |
| mgr = &vdec->adc; |
| } |
| |
| if ((mgr == NULL) || (mgr->enable == 0)) |
| return 0; |
| |
| if (mgr->enable & AUX_MASK) |
| ret = do_check_aux_data_crc(mgr,aux_buffer,size); |
| |
| mgr->frame_cnt++; |
| |
| return ret; |
| } |
| EXPORT_SYMBOL(decoder_do_aux_data_check); |
| |
| static int dump_buf_alloc(struct pic_dump_t *dump) |
| { |
| if ((dump->buf_addr != NULL) && |
| (dump->buf_size != 0)) |
| return 0; |
| |
| dump->buf_addr = |
| (char *)vmalloc(size_yuv_buf); |
| if (!dump->buf_addr) { |
| dump->buf_size = 0; |
| dbg_print(0, "vmalloc yuv buf failed\n"); |
| return -ENOMEM; |
| } |
| dump->buf_size = size_yuv_buf; |
| |
| dbg_print(0, "%s: buf for yuv is alloced\n", __func__); |
| |
| return 0; |
| } |
| |
| int dump_yuv_trig(struct pic_check_mgr_t *mgr, |
| int id, int start, int num) |
| { |
| struct pic_dump_t *dump = &mgr->pic_dump; |
| |
| if (!dump->num) { |
| mgr->id = id; |
| dump->start = start; |
| dump->num = num; |
| dump->end = start + num; |
| dump->dump_cnt = 0; |
| dump->yuv_fp = NULL; |
| if (!atomic_read(&mgr->work_inited)) { |
| INIT_WORK(&mgr->frame_check_work, do_check_work); |
| atomic_set(&mgr->work_inited, 1); |
| } |
| dump_buf_alloc(dump); |
| str_strip(comp_crc); |
| set_enable(mgr, YUV_MASK); |
| } else { |
| dbg_print(FC_ERROR, "yuv dump now, trig later\n"); |
| return -EBUSY; |
| } |
| dbg_print(0, "dump yuv trigger, from %d to %d frame\n", |
| dump->start, dump->end); |
| return 0; |
| } |
| |
| int frame_check_init(struct pic_check_mgr_t *mgr, int id) |
| { |
| int i; |
| struct pic_dump_t *dump = &mgr->pic_dump; |
| struct pic_check_t *check = &mgr->pic_check; |
| |
| mgr->frame_cnt = 0; |
| mgr->size_pic = 0; |
| mgr->last_size_pic = 0; |
| mgr->id = id; |
| mgr->yuvsum = 0; |
| mgr->height = 0; |
| mgr->width = 0; |
| |
| dump->num = 0; |
| dump->dump_cnt = 0; |
| dump->yuv_fp = NULL; |
| check->check_pos = 0; |
| check->compare_pos = 0; |
| |
| if (!atomic_read(&mgr->work_inited)) { |
| INIT_WORK(&mgr->frame_check_work, do_check_work); |
| atomic_set(&mgr->work_inited, 1); |
| } |
| /* for dump error yuv prepare. */ |
| dump_buf_alloc(dump); |
| |
| /* try to open compare crc32 file */ |
| str_strip(comp_crc); |
| check->compare_fp = file_open(O_RDONLY, |
| "%s%s", CRC_PATH, comp_crc); |
| |
| /* create crc32 log file */ |
| check->check_fp = file_open(O_CREAT| O_WRONLY | O_TRUNC, |
| "%s%s-%d-%d.crc", CRC_PATH, comp_crc, id, mgr->file_cnt); |
| |
| INIT_KFIFO(check->new_chk_q); |
| INIT_KFIFO(check->wr_chk_q); |
| check->check_addr = vmalloc(SIZE_CRC * SIZE_CHECK_Q); |
| if (check->check_addr == NULL) { |
| dbg_print(FC_ERROR, "vmalloc qbuf fail\n"); |
| } else { |
| void *qaddr = NULL, *rdret = NULL; |
| check->cmp_crc_cnt = 0; |
| for (i = 0; i < SIZE_CHECK_Q; i++) { |
| qaddr = check->check_addr + i * SIZE_CRC; |
| rdret = fget_crc_str(qaddr, |
| SIZE_CRC, check); |
| if (rdret == NULL) { |
| if (i < 3) |
| dbg_print(0, "can't get compare crc string\n"); |
| if (check->compare_fp) { |
| filp_close(check->compare_fp, current->files); |
| check->compare_fp = NULL; |
| } |
| } |
| |
| kfifo_put(&check->new_chk_q, qaddr); |
| } |
| } |
| set_enable(mgr, CRC_MASK); |
| dbg_print(0, "%s end\n", __func__); |
| |
| return 0; |
| } |
| |
| |
| int aux_data_check_init(struct aux_data_check_mgr_t *mgr, int id) |
| { |
| int i; |
| struct aux_data_check_t *check = &mgr->aux_data_check; |
| |
| mgr->frame_cnt = 0; |
| mgr->id = id; |
| |
| check->check_pos = 0; |
| check->compare_pos = 0; |
| |
| if (!atomic_read(&mgr->work_inited)) { |
| INIT_WORK(&mgr->aux_data_check_work, do_aux_data_check_work); |
| atomic_set(&mgr->work_inited, 1); |
| } |
| |
| /* try to open compare meta crc32 file */ |
| str_strip(aux_comp_crc); |
| check->compare_fp = file_open(O_RDONLY, |
| "%s%s", CRC_PATH, aux_comp_crc); |
| |
| /* create meta crc log file */ |
| check->check_fp = file_open(O_CREAT| O_WRONLY | O_TRUNC, |
| "%s%s-%d-%d.crc", CRC_PATH, aux_comp_crc, id, mgr->file_cnt); |
| |
| INIT_KFIFO(check->new_chk_q); |
| INIT_KFIFO(check->wr_chk_q); |
| check->check_addr = vmalloc(SIZE_CRC * SIZE_CHECK_Q); |
| if (check->check_addr == NULL) { |
| dbg_print(FC_ERROR, "vmalloc qbuf fail\n"); |
| } else { |
| void *qaddr = NULL, *rdret = NULL; |
| check->cmp_crc_cnt = 0; |
| for (i = 0; i < SIZE_CHECK_Q; i++) { |
| qaddr = check->check_addr + i * SIZE_CRC; |
| rdret = fget_aux_data_crc_str(qaddr, |
| SIZE_CRC, check); |
| if (rdret == NULL) { |
| if (i < 3) |
| dbg_print(0, "can't get compare crc string\n"); |
| if (check->compare_fp) { |
| filp_close(check->compare_fp, current->files); |
| check->compare_fp = NULL; |
| } |
| } |
| |
| kfifo_put(&check->new_chk_q, qaddr); |
| } |
| } |
| aux_set_enable(mgr, AUX_MASK); |
| dbg_print(0, "%s end\n", __func__); |
| |
| return 0; |
| } |
| |
| |
| void frame_check_exit(struct pic_check_mgr_t *mgr) |
| { |
| int i; |
| struct pic_dump_t *dump = &mgr->pic_dump; |
| struct pic_check_t *check = &mgr->pic_check; |
| |
| if (mgr->enable != 0) { |
| if (dump->dump_cnt != 0) { |
| dbg_print(0, "%s, cnt = %d, num = %d\n", |
| __func__, dump->dump_cnt, dump->num); |
| set_enable(mgr, YUV_MASK); |
| } |
| if (atomic_read(&mgr->work_inited)) { |
| cancel_work_sync(&mgr->frame_check_work); |
| atomic_set(&mgr->work_inited, 0); |
| } |
| if (single_mode_vdec != NULL) |
| write_yuv_work(mgr); |
| write_crc_work(mgr); |
| |
| for (i = 0; i < ARRAY_SIZE(check->fbc_planes); i++) { |
| if (check->fbc_planes[i]) { |
| vfree(check->fbc_planes[i]); |
| check->fbc_planes[i] = NULL; |
| } |
| } |
| if (check->check_addr) { |
| vfree(check->check_addr); |
| check->check_addr = NULL; |
| } |
| |
| if (mgr->cmp_pool) { |
| vfree(mgr->cmp_pool); |
| mgr->cmp_pool = NULL; |
| } |
| |
| if (check->check_fp) { |
| filp_close(check->check_fp, current->files); |
| check->check_fp = NULL; |
| } |
| if (check->compare_fp) { |
| filp_close(check->compare_fp, current->files); |
| check->compare_fp = NULL; |
| } |
| if (dump->yuv_fp) { |
| filp_close(dump->yuv_fp, current->files); |
| dump->yuv_fp = NULL; |
| } |
| if (dump->buf_addr) { |
| vfree(dump->buf_addr); |
| dump->buf_addr = NULL; |
| } |
| mgr->file_cnt++; |
| set_disable(mgr, YUV_MASK | CRC_MASK); |
| dbg_print(0, "%s end\n", __func__); |
| } |
| } |
| |
| void aux_data_check_exit(struct aux_data_check_mgr_t *mgr) |
| { |
| //struct pic_dump_t *dump = &mgr->pic_dump; |
| struct aux_data_check_t *check = &mgr->aux_data_check; |
| |
| if (mgr->enable != 0) { |
| if (atomic_read(&mgr->work_inited)) { |
| cancel_work_sync(&mgr->aux_data_check_work); |
| atomic_set(&mgr->work_inited, 0); |
| } |
| |
| write_aux_data_crc_work(mgr); |
| |
| if (check->check_addr) { |
| vfree(check->check_addr); |
| check->check_addr = NULL; |
| } |
| |
| if (check->check_fp) { |
| filp_close(check->check_fp, current->files); |
| check->check_fp = NULL; |
| } |
| if (check->compare_fp) { |
| filp_close(check->compare_fp, current->files); |
| check->compare_fp = NULL; |
| } |
| |
| mgr->file_cnt++; |
| aux_set_disable(mgr, AUX_MASK); |
| dbg_print(0, "%s end\n", __func__); |
| } |
| } |
| |
| |
| |
| int vdec_frame_check_init(struct vdec_s *vdec) |
| { |
| int ret = 0, id = 0; |
| |
| if (vdec == NULL) |
| return 0; |
| |
| if ((vdec->is_reset) && |
| (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_GXL)) |
| return 0; |
| |
| vdec->vfc.err_crc_block = 0; |
| single_mode_vdec = (vdec_single(vdec))? vdec : NULL; |
| |
| if (!check_enable && !yuv_enable) |
| return 0; |
| |
| vdec->canvas_mode = CANVAS_BLKMODE_LINEAR; |
| id = vdec->id; |
| |
| if (check_enable & (0x01 << id)) { |
| frame_check_init(&vdec->vfc, id); |
| /*repeat check one video crc32, not clear enable*/ |
| if ((fc_debug & FC_CHECK_CRC_LOOP_MODE) == 0) |
| check_enable &= ~(0x01 << id); |
| } |
| |
| if (yuv_enable & (0x01 << id)) { |
| ret = dump_yuv_trig(&vdec->vfc, |
| id, yuv_start[id], yuv_num[id]); |
| if (ret < 0) |
| pr_info("dump yuv init failed\n"); |
| else { |
| pr_info("dump yuv init ok, total %d\n", |
| yuv_num[id]); |
| vdec->canvas_mode = CANVAS_BLKMODE_LINEAR; |
| } |
| yuv_num[id] = 0; |
| yuv_start[id] = 0; |
| yuv_enable &= ~(0x01 << id); |
| } |
| |
| return ret; |
| } |
| |
| int print_decoder_info(struct vdec_s *vdec) |
| { |
| if (vdec->vfc.enable & CRC_MASK) { |
| const char *format_name; |
| |
| format_name = get_format_name(vdec->format); |
| if (format_name == NULL) |
| return -1; |
| |
| dbg_print(0, "Decoder-Summary:Type:%10s,framesize:%04dx%04d;out-nums:%08d,yuvsum:%08x\n", |
| format_name, vdec->vfc.width, vdec->vfc.height, |
| vdec->vfc.frame_cnt, vdec->vfc.yuvsum); |
| sprintf(checksum_info, "Type:%10s,framesize:%04dx%04d,out-nums:%08d,yuvsum:%08x", |
| format_name, vdec->vfc.width, vdec->vfc.height, |
| vdec->vfc.frame_cnt, vdec->vfc.yuvsum); |
| if (checksum_enable) { |
| struct file *checksum_fp; |
| static loff_t checksum_pos; |
| mm_segment_t old_fs; |
| char checksum_buf[128]="\n"; |
| static int num; |
| static char file_name[128]; |
| |
| if (strcmp(checksum_filename,file_name) != 0) { |
| num = 0; |
| checksum_pos = 0; |
| strcpy(file_name,checksum_filename); |
| } |
| if (checksum_start_count == 1) { |
| num = 0; |
| checksum_start_count = 0; |
| } |
| |
| str_strip(checksum_filename); |
| checksum_fp = file_open(O_CREAT| O_WRONLY | O_APPEND, |
| "%s%s.txt", CHECKSUM_PATH,checksum_filename); |
| if (checksum_fp == NULL) { |
| return -1; |
| } |
| sprintf(checksum_buf, "%08d (Type:%10s, framesize:%04dx%04d, out-nums:%08d, yuvsum:%08x)\n", |
| num,format_name, vdec->vfc.width, vdec->vfc.height, |
| vdec->vfc.frame_cnt, vdec->vfc.yuvsum); |
| |
| old_fs = get_fs(); |
| set_fs(KERNEL_DS); |
| |
| vfs_write(checksum_fp, checksum_buf, |
| strlen(checksum_buf), &checksum_pos); |
| |
| set_fs(old_fs); |
| |
| filp_close(checksum_fp, current->files); |
| checksum_fp = NULL; |
| num++; |
| } |
| } |
| |
| return 0; |
| } |
| |
| int vdec_aux_data_check_init(struct vdec_s *vdec) |
| { |
| int ret = 0, id = 0; |
| |
| if (vdec == NULL) |
| return 0; |
| |
| if ((vdec->is_reset) && |
| (get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_GXL)) |
| return 0; |
| |
| if (!aux_enable) |
| return 0; |
| |
| id = vdec->id; |
| |
| if (aux_enable & (0x01 << id)) { |
| aux_data_check_init(&vdec->adc, id); |
| /*repeat check one video meta crc32, not clear enable*/ |
| if ((fc_debug & AD_CHECK_CRC_LOOP_MODE) == 0) |
| aux_enable &= ~(0x01 << id); |
| } |
| |
| return ret; |
| } |
| EXPORT_SYMBOL(vdec_aux_data_check_init); |
| |
| |
| void vdec_aux_data_check_exit(struct vdec_s *vdec) |
| { |
| if (vdec == NULL) |
| return; |
| aux_data_check_exit(&vdec->adc); |
| } |
| EXPORT_SYMBOL(vdec_aux_data_check_exit); |
| |
| |
| void vdec_frame_check_exit(struct vdec_s *vdec) |
| { |
| if (vdec == NULL) |
| return; |
| print_decoder_info(vdec); |
| frame_check_exit(&vdec->vfc); |
| |
| single_mode_vdec = NULL; |
| } |
| |
| ssize_t dump_yuv_store(struct class *class, |
| struct class_attribute *attr, |
| const char *buf, size_t size) |
| { |
| struct vdec_s *vdec = NULL; |
| unsigned int id = 0, num = 0, start = 0; |
| int ret = -1; |
| |
| ret = sscanf(buf, "%d %d %d", &id, &start, &num); |
| if (ret < 0) { |
| pr_info("%s, parse failed\n", buf); |
| return size; |
| } |
| if ((num == 0) || (num > YUV_MAX_DUMP_NUM)) { |
| pr_info("requred yuv num %d, max %d\n", |
| num, YUV_MAX_DUMP_NUM); |
| return size; |
| } |
| vdec = vdec_get_vdec_by_id(id); |
| if (vdec == NULL) { |
| yuv_start[id] = start; |
| yuv_num[id] = num; |
| yuv_enable |= (1 << id); |
| pr_info("no connected vdec.%d now, set dump ok\n", id); |
| return size; |
| } |
| |
| ret = dump_yuv_trig(&vdec->vfc, id, start, num); |
| if (ret < 0) |
| pr_info("trigger dump yuv failed\n"); |
| else |
| pr_info("trigger dump yuv init ok, total %d frames\n", num); |
| |
| return size; |
| } |
| |
| ssize_t dump_yuv_show(struct class *class, |
| struct class_attribute *attr, char *buf) |
| { |
| int i; |
| char *pbuf = buf; |
| |
| for (i = 0; i < MAX_INSTANCE_MUN; i++) { |
| pbuf += pr_info("vdec.%d, start: %d, total: %d frames\n", |
| i, yuv_start[i], yuv_num[i]); |
| } |
| pbuf += sprintf(pbuf, |
| "\nUsage: echo [id] [start] [num] > dump_yuv\n\n"); |
| return pbuf - buf; |
| } |
| |
| |
| ssize_t frame_check_store(struct class *class, |
| struct class_attribute *attr, |
| const char *buf, size_t size) |
| { |
| int ret = -1; |
| int on_off, id; |
| |
| ret = sscanf(buf, "%d %d", &id, &on_off); |
| if (ret < 0) { |
| pr_info("%s, parse failed\n", buf); |
| return size; |
| } |
| if (id >= MAX_INSTANCE_MUN) { |
| pr_info("%d out of max vdec id\n", id); |
| return size; |
| } |
| if (on_off) |
| check_enable |= (1 << id); |
| else |
| check_enable &= ~(1 << id); |
| |
| return size; |
| } |
| |
| ssize_t frame_check_show(struct class *class, |
| struct class_attribute *attr, char *buf) |
| { |
| int i; |
| char *pbuf = buf; |
| |
| for (i = 0; i < MAX_INSTANCE_MUN; i++) { |
| pbuf += sprintf(pbuf, |
| "vdec.%d\tcrc: %s\n", i, |
| (check_enable & (0x01 << i))?"enabled":"--"); |
| } |
| pbuf += sprintf(pbuf, |
| "\nUsage:\techo [id] [1:on/0:off] > frame_check\n\n"); |
| |
| if (fc_debug & FC_ERR_CRC_BLOCK_MODE) { |
| /* cat frame_check to next frame when block */ |
| struct vdec_s *vdec = NULL; |
| vdec = vdec_get_vdec_by_id(__ffs(check_enable)); |
| if (vdec) |
| vdec->vfc.err_crc_block = 0; |
| } |
| |
| return pbuf - buf; |
| } |
| |
| |
| module_param_string(comp_crc, comp_crc, 128, 0664); |
| MODULE_PARM_DESC(comp_crc, "\n crc_filename\n"); |
| |
| module_param_string(aux_comp_crc, aux_comp_crc, 128, 0664); |
| MODULE_PARM_DESC(aux_comp_crc, "\n aux crc_filename\n"); |
| |
| |
| module_param(fc_debug, uint, 0664); |
| MODULE_PARM_DESC(fc_debug, "\n frame check debug\n"); |
| |
| module_param(aux_enable, uint, 0664); |
| MODULE_PARM_DESC(aux_enable, "\n aux data check debug\n"); |
| |
| module_param(size_yuv_buf, uint, 0664); |
| MODULE_PARM_DESC(size_yuv_buf, "\n size_yuv_buf\n"); |
| |
| module_param_string(checksum_info, checksum_info, 128, 0664); |
| MODULE_PARM_DESC(checksum_info, "\n checksum_info\n"); |
| |
| module_param_string(checksum_filename, checksum_filename, 128, 0664); |
| MODULE_PARM_DESC(checksum_filename, "\n checksum_filename\n"); |
| |
| module_param(checksum_start_count, uint, 0664); |
| MODULE_PARM_DESC(checksum_start_count, "\n checksum_start_count\n"); |
| |
| module_param(checksum_enable, uint, 0664); |
| MODULE_PARM_DESC(checksum_enable, "\n checksum_enable\n"); |