author | shihong.zheng <shihong.zheng@amlogic.com> | 2019-01-08 08:55:49 (GMT) |
---|---|---|
committer | Luan Yuan <luan.yuan@amlogic.com> | 2019-01-09 12:28:22 (GMT) |
commit | 6cd5e0916bbbfab30f83ef2f34fbb8b779cfbc52 (patch) | |
tree | 4a9e4ee248fcfff3f4d1ca3bc7c4e716b8908cd1 | |
parent | 1f67eb9d58de6ea87d81d4bdae0b93ea95be3e13 (diff) | |
download | media_modules-6cd5e0916bbbfab30f83ef2f34fbb8b779cfbc52.zip media_modules-6cd5e0916bbbfab30f83ef2f34fbb8b779cfbc52.tar.gz media_modules-6cd5e0916bbbfab30f83ef2f34fbb8b779cfbc52.tar.bz2 |
media_module: frame crc32 check and dump yuv [1/2]
PD#SWPL-1738
Problem:
support frame crc32 check and dump yuv.
Solution:
1.do crc32 check for frames output from decoder, trigger
yuv dump if it is not match with preset crc32 file;
2.trigger yuv dump before play or playing.
Verify:
u212
Change-Id: I5b2374d248698c4d6a4e67bc4dc18907d50ce2ea
Signed-off-by: shihong.zheng <shihong.zheng@amlogic.com>
-rw-r--r-- | drivers/frame_provider/decoder/avs2/vavs2.c | 2 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/h264/vh264.c | 35 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/h264_multi/vmh264.c | 25 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/h265/vh265.c | 3 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/utils/Makefile | 2 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/utils/amlogic_fbc_hook.c | 104 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/utils/amlogic_fbc_hook.h | 55 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/utils/frame_check.c | 1038 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/utils/frame_check.h | 110 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/utils/vdec.c | 65 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/utils/vdec.h | 10 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/vp9/vvp9.c | 1 |
12 files changed, 1430 insertions, 20 deletions
diff --git a/drivers/frame_provider/decoder/avs2/vavs2.c b/drivers/frame_provider/decoder/avs2/vavs2.c index 275dfc2..c498b1b 100644 --- a/drivers/frame_provider/decoder/avs2/vavs2.c +++ b/drivers/frame_provider/decoder/avs2/vavs2.c @@ -4425,7 +4425,7 @@ static int avs2_prepare_display_buf(struct AVS2Decoder_s *dec) if (vf) { set_vframe(dec, vf, pic, 0); - + decoder_do_frame_check(vf, CORE_MASK_HEVC); kfifo_put(&dec->display_q, (const struct vframe_s *)vf); #ifndef CONFIG_AMLOGIC_MEDIA_MULTI_DEC diff --git a/drivers/frame_provider/decoder/h264/vh264.c b/drivers/frame_provider/decoder/h264/vh264.c index bc49465..e74af2c 100644 --- a/drivers/frame_provider/decoder/h264/vh264.c +++ b/drivers/frame_provider/decoder/h264/vh264.c @@ -242,6 +242,8 @@ static u32 max_refer_buf = 1; static u32 decoder_force_reset; static unsigned int no_idr_error_count; static unsigned int no_idr_error_max = 60; +static unsigned int canvas_mode; + #ifdef SUPPORT_BAD_MACRO_BLOCK_REDUNDANCY /* 0~128*/ static u32 bad_block_scale; @@ -328,6 +330,7 @@ static bool block_display_q; static int vh264_stop(int mode); static s32 vh264_init(void); + #define DFS_HIGH_THEASHOLD 3 static bool pts_discontinue; @@ -426,16 +429,19 @@ static inline int fifo_level(void) void spec_set_canvas(struct buffer_spec_s *spec, unsigned int width, unsigned int height) { - canvas_config(spec->y_canvas_index, + int endian; + + endian = (canvas_mode == CANVAS_BLKMODE_LINEAR)?7:0; + canvas_config_ex(spec->y_canvas_index, spec->y_addr, width, height, - CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); + CANVAS_ADDR_NOWRAP, canvas_mode, endian); + + canvas_config_ex(spec->u_canvas_index, + spec->u_addr, + width, height / 2, + CANVAS_ADDR_NOWRAP, canvas_mode, endian); - canvas_config(spec->u_canvas_index, - spec->u_addr, - width, height / 2, - CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_32X32); - return; } static void vh264_notify_work(struct work_struct *work) @@ -900,7 +906,7 @@ static void vh264_set_params(struct work_struct *work) int max_dpb_size, actual_dpb_size, max_reference_size; int i, mb_mv_byte, ret; unsigned long addr; - unsigned int post_canvas, buf_size; + unsigned int post_canvas, buf_size, endian; unsigned int frame_mbs_only_flag; unsigned int chroma_format_idc, chroma444, video_signal; unsigned int crop_infor, crop_bottom, crop_right, level_idc; @@ -1120,16 +1126,17 @@ static void vh264_set_params(struct work_struct *work) buffer_spec[i].v_canvas_width = mb_width << 4; buffer_spec[i].v_canvas_height = mb_height << 4; - canvas_config(128 + i * 2, + endian = (canvas_mode == CANVAS_BLKMODE_LINEAR)?7:0; + canvas_config_ex(128 + i * 2, buffer_spec[i].y_addr, mb_width << 4, mb_height << 4, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_32X32); - canvas_config(128 + i * 2 + 1, + canvas_mode, endian); + canvas_config_ex(128 + i * 2 + 1, buffer_spec[i].u_addr, mb_width << 4, mb_height << 3, CANVAS_ADDR_NOWRAP, - CANVAS_BLKMODE_32X32); + canvas_mode, endian); WRITE_VREG(ANC0_CANVAS_ADDR + i, spec2canvas(&buffer_spec[i])); } else { @@ -1906,6 +1913,7 @@ static void vh264_isr(void) decoder_bmmu_box_get_mem_handle( mm_blk_handle, VF_BUFFER_IDX(buffer_index)); + decoder_do_frame_check(vf, CORE_MASK_VDEC_1); if ((error_recovery_mode_use & 2) && error) { kfifo_put(&recycle_q, (const struct vframe_s *)vf); @@ -1956,6 +1964,7 @@ static void vh264_isr(void) decoder_bmmu_box_get_mem_handle( mm_blk_handle, VF_BUFFER_IDX(buffer_index)); + decoder_do_frame_check(vf, CORE_MASK_VDEC_1); if ((error_recovery_mode_use & 2) && error) { kfifo_put(&recycle_q, (const struct vframe_s *)vf); @@ -2096,6 +2105,7 @@ static void vh264_isr(void) p_last_vf = vf; pts_discontinue = false; iponly_early_mode = 1; + decoder_do_frame_check(vf, CORE_MASK_VDEC_1); kfifo_put(&delay_display_q, (const struct vframe_s *)vf); WRITE_VREG(AV_SCRATCH_0, 0); @@ -3031,6 +3041,7 @@ static int amvdec_h264_probe(struct platform_device *pdev) mutex_unlock(&vh264_mutex); return -EFAULT; } + canvas_mode = pdata->canvas_mode; tvp_flag = vdec_secure(pdata) ? CODEC_MM_FLAGS_TVP : 0; if (pdata->sys_info) vh264_amstream_dec_info = *pdata->sys_info; diff --git a/drivers/frame_provider/decoder/h264_multi/vmh264.c b/drivers/frame_provider/decoder/h264_multi/vmh264.c index b7ab3b7..d4ad7e0 100644 --- a/drivers/frame_provider/decoder/h264_multi/vmh264.c +++ b/drivers/frame_provider/decoder/h264_multi/vmh264.c @@ -809,6 +809,7 @@ struct vdec_h264_hw_s { int wait_for_udr_send; #endif u32 no_mem_count; + u32 canvas_mode; bool is_used_v4l; void *v4l2_ctx; wait_queue_head_t wait_q; @@ -1659,7 +1660,7 @@ static int alloc_one_buf_spec(struct vdec_h264_hw_s *hw, int i) hw->buffer_spec[i].canvas_config[0].height = hw->mb_height << 4; hw->buffer_spec[i].canvas_config[0].block_mode = - CANVAS_BLKMODE_32X32; + hw->canvas_mode; hw->buffer_spec[i].canvas_config[1].phy_addr = hw->buffer_spec[i].u_addr; @@ -1668,7 +1669,7 @@ static int alloc_one_buf_spec(struct vdec_h264_hw_s *hw, int i) hw->buffer_spec[i].canvas_config[1].height = hw->mb_height << 3; hw->buffer_spec[i].canvas_config[1].block_mode = - CANVAS_BLKMODE_32X32; + hw->canvas_mode; dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS, "%s, alloc buf for bufspec%d\n", __func__, i @@ -1826,8 +1827,13 @@ static int alloc_one_buf_spec_from_queue(struct vdec_h264_hw_s *hw, int idx) static void config_decode_canvas(struct vdec_h264_hw_s *hw, int i) { - int blkmode = hw->is_used_v4l ? CANVAS_BLKMODE_LINEAR : + int endian = 0; + int blkmode = ((hw->canvas_mode == CANVAS_BLKMODE_LINEAR) || + hw->is_used_v4l) ? CANVAS_BLKMODE_LINEAR : CANVAS_BLKMODE_32X32; + if (blkmode == CANVAS_BLKMODE_LINEAR) + endian = 7; + canvas_config_ex(hw->buffer_spec[i]. y_canvas_index, hw->buffer_spec[i].y_addr, @@ -1835,7 +1841,7 @@ static void config_decode_canvas(struct vdec_h264_hw_s *hw, int i) hw->mb_height << 4, CANVAS_ADDR_NOWRAP, blkmode, - hw->is_used_v4l ? 7 : 0); + endian); if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { WRITE_VREG(VDEC_ASSIST_CANVAS_BLK32, (1 << 11) | /* canvas_blk32_wr */ @@ -1852,7 +1858,7 @@ static void config_decode_canvas(struct vdec_h264_hw_s *hw, int i) hw->mb_height << 3, CANVAS_ADDR_NOWRAP, blkmode, - hw->is_used_v4l ? 7 : 0); + endian); if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) { WRITE_VREG(VDEC_ASSIST_CANVAS_BLK32, (1 << 11) | @@ -2558,6 +2564,13 @@ int prepare_display_buf(struct vdec_s *vdec, struct FrameStore *frame) vf->duration = vf->duration/2; } + if (i == 0) { + if (hw->mmu_enable) + decoder_do_frame_check(vf, CORE_MASK_VDEC_1 | CORE_MASK_HEVC); + else + decoder_do_frame_check(vf, CORE_MASK_VDEC_1); + } + kfifo_put(&hw->display_q, (const struct vframe_s *)vf); hw->vf_pre_count++; @@ -7660,6 +7673,8 @@ static int ammvdec_h264_probe(struct platform_device *pdev) /* the ctx from v4l2 driver. */ hw->v4l2_ctx = pdata->private; + hw->canvas_mode = pdata->canvas_mode; + platform_set_drvdata(pdev, pdata); hw->mmu_enable = 0; diff --git a/drivers/frame_provider/decoder/h265/vh265.c b/drivers/frame_provider/decoder/h265/vh265.c index c51c010..544c35d 100644 --- a/drivers/frame_provider/decoder/h265/vh265.c +++ b/drivers/frame_provider/decoder/h265/vh265.c @@ -3661,7 +3661,7 @@ static void hevc_config_work_space_hw(struct hevc_state_s *hevc) struct BuffInfo_s *buf_spec = hevc->work_space_buf; if (get_dbg_flag(hevc)) - hevc_print(hevc, 0, + hevc_print(hevc, H265_DEBUG_BUFMGR_MORE, "%s %x %x %x %x %x %x %x %x %x %x %x %x %x\n", __func__, buf_spec->ipp.buf_start, @@ -7520,6 +7520,7 @@ static int prepare_display_buf(struct hevc_state_s *hevc, struct PIC_s *pic) vf->type_original = vf->type; pic->vf_ref = 1; hevc->vf_pre_count++; + decoder_do_frame_check(vf, CORE_MASK_HEVC); kfifo_put(&hevc->display_q, (const struct vframe_s *)vf); if (get_dbg_flag(hevc) & H265_DEBUG_PIC_STRUCT) diff --git a/drivers/frame_provider/decoder/utils/Makefile b/drivers/frame_provider/decoder/utils/Makefile index 03f57b8..ee7dbf4 100644 --- a/drivers/frame_provider/decoder/utils/Makefile +++ b/drivers/frame_provider/decoder/utils/Makefile @@ -3,3 +3,5 @@ decoder_common-objs += utils.o vdec.o vdec_input.o amvdec.o decoder_common-objs += decoder_mmu_box.o decoder_bmmu_box.o decoder_common-objs += config_parser.o secprot.o vdec_profile.o decoder_common-objs += amstream_profile.o +decoder_common-objs += frame_check.o amlogic_fbc_hook.o + diff --git a/drivers/frame_provider/decoder/utils/amlogic_fbc_hook.c b/drivers/frame_provider/decoder/utils/amlogic_fbc_hook.c new file mode 100644 index 0000000..b6179fb --- a/dev/null +++ b/drivers/frame_provider/decoder/utils/amlogic_fbc_hook.c @@ -0,0 +1,104 @@ +/* + * drivers/amlogic/media/frame_provider/decoder/utils/amlogic_fbc_hook.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 "amlogic_fbc_hook.h" +static AMLOGIC_FBC_vframe_decoder_fun_t g_decoder_fun; +static AMLOGIC_FBC_vframe_encoder_fun_t g_encoder_fun; + + +int AMLOGIC_FBC_vframe_decoder( + void *dstyuv[4], + struct vframe_s *vf, + int out_format, + int flags) + +{ + if (g_decoder_fun) { + return g_decoder_fun(dstyuv, + vf, + out_format, + flags); + } + printk("no AMLOGIC_FBC_vframe_decoder ERRR!!\n"); + return -1; +} +EXPORT_SYMBOL(AMLOGIC_FBC_vframe_decoder); + +int AMLOGIC_FBC_vframe_encoder( + void *srcyuv[4], + void *dst_header, + void *dst_body, + int in_format, + int flags) + +{ + if (g_encoder_fun) { + return g_encoder_fun( + srcyuv, + dst_header, + dst_body, + in_format, + flags); + } + printk("no AMLOGIC_FBC_vframe_encoder ERRR!!\n"); + return -1; +} +EXPORT_SYMBOL(AMLOGIC_FBC_vframe_encoder); + +int register_amlogic_afbc_dec_fun(AMLOGIC_FBC_vframe_decoder_fun_t fn) +{ + if (g_decoder_fun) { + pr_err("error!!,AMLOGIC_FBC dec have register\n"); + return -1; + } + printk("register_amlogic_afbc_dec_fun\n"); + g_decoder_fun = fn; + return 0; +} +EXPORT_SYMBOL(register_amlogic_afbc_dec_fun); + +int register_amlogic_afbc_enc_fun(AMLOGIC_FBC_vframe_encoder_fun_t fn) +{ + if (g_encoder_fun) { + pr_err("error!!,AMLOGIC_FBC enc have register\n"); + return -1; + } + g_encoder_fun = fn; + return 0; +} +EXPORT_SYMBOL(register_amlogic_afbc_enc_fun); + +int unregister_amlogic_afbc_dec_fun(void) +{ + g_decoder_fun = NULL; + pr_err("unregister_amlogic_afbc_dec_fun\n"); + return 0; +} +EXPORT_SYMBOL(unregister_amlogic_afbc_dec_fun); + +int unregister_amlogic_afbc_enc_fun(void) +{ + g_encoder_fun = NULL; + pr_err("unregister_amlogic_afbc_dec_fun\n"); + return 0; +} +EXPORT_SYMBOL(unregister_amlogic_afbc_enc_fun); + + diff --git a/drivers/frame_provider/decoder/utils/amlogic_fbc_hook.h b/drivers/frame_provider/decoder/utils/amlogic_fbc_hook.h new file mode 100644 index 0000000..7eec4b7 --- a/dev/null +++ b/drivers/frame_provider/decoder/utils/amlogic_fbc_hook.h @@ -0,0 +1,55 @@ +/* + * drivers/amlogic/media/frame_provider/decoder/utils/amlogic_fbc_hook.h + * + * 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. + * + */ + +#ifndef AMLGIC_FBC_HEADER___ +#define AMLGIC_FBC_HEADER___ +#include <linux/amlogic/media/vfm/vframe.h> +/* +unsigned short *planes[4], + unsigned char *buf, + unsigned *v2_head_buf // v2_head_buf_size=(((frame_info->mbw + 1)>>1)*2) * (((frame_info->mbh + 15)>>4)*16) +); +*/ + +int AMLOGIC_FBC_vframe_decoder( + void *dstyuv[4], + struct vframe_s *vf, + int out_format, + int flags); +int AMLOGIC_FBC_vframe_encoder( + void *srcyuv[4], + void *dst_header, + void *dst_body, + int in_format, + int flags); + +typedef int (*AMLOGIC_FBC_vframe_decoder_fun_t)( + void **, + struct vframe_s *, + int, + int); +typedef int (*AMLOGIC_FBC_vframe_encoder_fun_t)( + void **, + void *, + void *, + int, + int); +int register_amlogic_afbc_dec_fun(AMLOGIC_FBC_vframe_decoder_fun_t fn); +int register_amlogic_afbc_enc_fun(AMLOGIC_FBC_vframe_encoder_fun_t fn); +int unregister_amlogic_afbc_dec_fun(void); +int unregister_amlogic_afbc_enc_fun(void); +#endif
\ No newline at end of file diff --git a/drivers/frame_provider/decoder/utils/frame_check.c b/drivers/frame_provider/decoder/utils/frame_check.c new file mode 100644 index 0000000..699ff7f --- a/dev/null +++ b/drivers/frame_provider/decoder/utils/frame_check.c @@ -0,0 +1,1038 @@ +/* + * 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/platform_device.h> +#include <linux/amlogic/media/canvas/canvas.h> +#include <linux/amlogic/media/canvas/canvas_mgr.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" + + +#define FC_ERROR 0x0 + +#define FC_YUV_DEBUG 0x01 +#define FC_CRC_DEBUG 0x02 +#define FC_TST_DEBUG 0x80 + +#define YUV_MASK 0x01 +#define CRC_MASK 0x02 + +#define YUV_DEF_SIZE (1920*1088*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("[FRMAE_CHECK] "__VA_ARGS__);\ + } while(0) + + +#define CRC_PATH "/data/tmp/" +#define YUV_PATH "/data/tmp/" +static char comp_crc[128] = "name"; + + +module_param_string(comp_crc, comp_crc, 128, 0664); +MODULE_PARM_DESC(comp_crc, "\n crc_filename\n"); + +module_param(fc_debug, uint, 0664); +MODULE_PARM_DESC(fc_debug, "\n frame check debug\n"); + +module_param(size_yuv_buf, uint, 0664); +MODULE_PARM_DESC(size_yuv_buf, "\n size_yuv_buf\n"); + +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 int get_frame_size(struct pic_check_mgr_t *pic, + struct vframe_s *vf) +{ + if ((vf->width < 1) || (vf->height < 1)) + return -1; + pic->size_y = vf->width* vf->height; + pic->size_uv = pic->size_y >> 1; + pic->size_pic = pic->size_y + pic->size_uv; + + if (!(vf->type & VIDTYPE_VIU_NV21)) + return 0; + + if ((vf->canvas0Addr == vf->canvas1Addr) && + (vf->canvas0Addr != 0) && + (vf->canvas0Addr != -1)) { + pic->canvas_w = + canvas_get_width(canvasY(vf->canvas0Addr)); + pic->canvas_h = + canvas_get_height(canvasY(vf->canvas0Addr)); + } else { + pic->canvas_w = vf->canvas0_config[0].width; + pic->canvas_h = vf->canvas0_config[1].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) +{ + int 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 = canvas_get_addr(canvasY(vf->canvas0Addr)); + phy_uv_addr = 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%x), uv_addr %p(0x%x)\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; + + 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)) + 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 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, 0); + if (IS_ERR(fp)) { + fp = NULL; + dbg_print(FC_ERROR, "open %s failed\n", file); + 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; + 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)) { + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + for (i = 0; dump->dump_cnt > 0; i++) { + 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; + } + dump->dump_cnt--; + } + 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[64*30]; + mm_segment_t old_fs; + struct pic_check_t *check = &mgr->pic_check; + + 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); + } + } + 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 check_schedule(struct pic_check_mgr_t *mgr) +{ + if (atomic_read(&mgr->work_inited)) + vdec_schedule_work(&mgr->frame_check_work); +} + +static int memcpy_phy_to_virt(char *to_virt, + ulong phy_from, unsigned int size) +{ + void *vaddr = NULL; + unsigned int tmp_size = 0; + + while (size > 0) { + if (size >= VMAP_STRIDE_SIZE) { + vaddr = (void *)codec_mm_vmap(phy_from, VMAP_STRIDE_SIZE); + tmp_size = VMAP_STRIDE_SIZE; + phy_from += VMAP_STRIDE_SIZE; + size -= VMAP_STRIDE_SIZE; + } else { + vaddr = (void *)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; + } + memcpy(to_virt, vaddr, tmp_size); + to_virt += tmp_size; + + codec_mm_unmap_phyaddr(vaddr); + } + return 0; +} + +static int do_yuv_dump(struct pic_check_mgr_t *mgr, struct vframe_s *vf) +{ + int i, ret = 0; + void *tmp_addr, *tmp_yaddr, *tmp_uvaddr; + ulong y_phyaddr, uv_phyaddr; + struct pic_dump_t *dump = &mgr->pic_dump; + /* + if ((vf->type & VIDTYPE_VIU_NV21) == 0) + return 0; + */ + if (dump->start > 0) { + dump->start--; + return 0; + } + + if (dump->dump_cnt >= dump->num) + return 0; + + if (mgr->size_pic > + (dump->buf_size - dump->dump_cnt * mgr->size_pic)) { + if (dump->buf_size) { + dbg_print(FC_ERROR, + "not enough buf, 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; + if ((mgr->uv_vaddr == NULL) || (mgr->y_vaddr == NULL)) { + y_phyaddr = mgr->y_phyaddr; + uv_phyaddr = mgr->uv_phyaddr; + if (vf->width == mgr->canvas_w) { + ret |= memcpy_phy_to_virt(tmp_addr, y_phyaddr, mgr->size_y); + ret |= memcpy_phy_to_virt(tmp_addr + mgr->size_y, + uv_phyaddr, mgr->size_uv); + } else { + for (i = 0; i < vf->height; i++) { + ret |= memcpy_phy_to_virt(tmp_addr, y_phyaddr, vf->width); + y_phyaddr += mgr->canvas_w; + tmp_addr += vf->width; + } + for (i = 0; i < vf->height/2; i++) { + ret |= memcpy_phy_to_virt(tmp_addr, uv_phyaddr, vf->width); + uv_phyaddr += mgr->canvas_w; + tmp_addr += vf->width; + } + } + if (ret < 0) { + dbg_print(0, "dump yuv failed, may codec_mm_vmap failed\n"); + return ret; + } + } else { + if (vf->width == mgr->canvas_w) { + memcpy(tmp_addr, mgr->y_vaddr, mgr->size_y); + memcpy(tmp_addr + mgr->size_y, + mgr->uv_vaddr, mgr->size_uv); + } else { + tmp_yaddr = mgr->y_vaddr; + tmp_uvaddr = mgr->uv_vaddr; + for (i = 0; i < vf->height; i++) { + memcpy(tmp_addr, tmp_yaddr, vf->width); + tmp_yaddr += mgr->canvas_w; + tmp_addr += vf->width; + } + for (i = 0; i < vf->height/2; i++) { + memcpy(tmp_addr, tmp_uvaddr, vf->width); + tmp_uvaddr += mgr->canvas_w; + tmp_addr += vf->width; + } + } + } + dump->dump_cnt++; + dbg_print(0, + "----->>dump frame num: %d, dump %dst, size %x\n", + mgr->frame_cnt, dump->dump_cnt, mgr->size_pic); + + if (dump->dump_cnt >= dump->num) + check_schedule(mgr); + + 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; + int comp_frame = 0, comp_crc_y, comp_crc_uv; + struct pic_check_t *check = &mgr->pic_check; + + if (kfifo_get(&check->new_chk_q, &crc_addr) == 0) { + dbg_print(0, "%08d: %08x %08x\n", + mgr->frame_cnt, crc_y, crc_uv); + 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 ((mgr->frame_cnt % 100) == 0) + comp_crc_uv = mgr->frame_cnt; + */ + if (comp_frame == mgr->frame_cnt) { + if ((comp_crc_y != crc_y) || (crc_uv != comp_crc_uv)) { + mgr->pic_dump.start = 0; + 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); + do_yuv_dump(mgr, vf); + } + } + } + + if (check->check_fp) { + 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 crc32_vmap_le(unsigned int *crc32, + ulong phyaddr, unsigned int size) +{ + void *vaddr = NULL; + unsigned int crc = 0; + unsigned int tmp_size = 0; + + while (size > 0) { + if (size >= VMAP_STRIDE_SIZE) { + vaddr = (void *)codec_mm_vmap(phyaddr, VMAP_STRIDE_SIZE); + tmp_size = VMAP_STRIDE_SIZE; + phyaddr += VMAP_STRIDE_SIZE; + size -= VMAP_STRIDE_SIZE; + } else { + vaddr = (void *)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; + } + 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 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 %x %x %x %x\n", + (u32)check->fbc_planes[0], + (u32)check->fbc_planes[1], + (u32)check->fbc_planes[2], + (u32)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 decoder_do_frame_check(struct vframe_s *vf, int core_mask) +{ + int ret = 0; + int resize = 0; + void *planes[4]; + struct pic_check_t *check = NULL; + struct pic_check_mgr_t *mgr = + (struct pic_check_mgr_t *)vdec_get_active_vfc(core_mask); + + if ((mgr == NULL) || + (vf == NULL) || + (mgr->enable == 0)) + return 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\n", + mgr->last_size_pic, mgr->size_pic); + } else + resize = 0; + mgr->last_size_pic = mgr->size_pic; + + if (vf->type & VIDTYPE_VIU_NV21) { + if (canvas_get_virt_addr(mgr, vf) < 0) + return -2; + + 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]; + AMLOGIC_FBC_vframe_decoder(planes, vf, 0, 0); + do_check_yuv16(mgr, vf, + (void *)planes[0], (void *)planes[3],//uv + (void *)planes[1], (void *)planes[2]); + } + mgr->frame_cnt++; + + return ret; +} +EXPORT_SYMBOL(decoder_do_frame_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; + + 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_WRONLY | O_CREAT, + "%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 && + (check->compare_fp != NULL); i++) { + qaddr = check->check_addr + i * SIZE_CRC; + rdret = fget_crc_str(qaddr, + SIZE_CRC, check); + if (rdret == NULL) { + dbg_print(0, "can't get compare crc string\n"); + 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; +} + +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); + } + 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 (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__); + } +} + + + +static unsigned int yuv_enable, check_enable; +static unsigned int yuv_start[MAX_INSTANCE_MUN]; +static unsigned int yuv_num[MAX_INSTANCE_MUN]; + +int vdec_frame_check_init(struct vdec_s *vdec) +{ + int ret = 0, id = 0; + + if ((vdec == NULL) || + (vdec->is_reset)) + return 0; + + 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); + 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; +} + +void vdec_frame_check_exit(struct vdec_s *vdec) +{ + if (vdec == NULL) + return; + frame_check_exit(&vdec->vfc); +} + +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_with_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"); + + return pbuf - buf; +} + + + + diff --git a/drivers/frame_provider/decoder/utils/frame_check.h b/drivers/frame_provider/decoder/utils/frame_check.h new file mode 100644 index 0000000..27f4c5c --- a/dev/null +++ b/drivers/frame_provider/decoder/utils/frame_check.h @@ -0,0 +1,110 @@ +/* + * drivers/amlogic/media/frame_provider/decoder/utils/frame_check.h + * + * 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. + * +*/ + +#ifndef __FRAME_CHECK_H__ +#define __FRAME_CHECK_H__ + + +#include <linux/fs.h> +#include <linux/uaccess.h> +#include <linux/amlogic/media/vfm/vframe.h> +#include <linux/kfifo.h> + +#define FRAME_CHECK + +#define YUV_MAX_DUMP_NUM 20 + +#define SIZE_CRC 64 +#define SIZE_CHECK_Q 128 + +struct pic_dump_t{ + struct file *yuv_fp; + loff_t yuv_pos; + unsigned int start; + unsigned int num; + unsigned int end; + unsigned int dump_cnt; + + unsigned int buf_size; + char *buf_addr; +}; + +struct pic_check_t{ + struct file *check_fp; + loff_t check_pos; + + struct file *compare_fp; + loff_t compare_pos; + unsigned int cmp_crc_cnt; + void *fbc_planes[4]; + void *check_addr; + DECLARE_KFIFO(new_chk_q, char *, SIZE_CHECK_Q); + DECLARE_KFIFO(wr_chk_q, char *, SIZE_CHECK_Q); +}; + +struct pic_check_mgr_t{ + int id; + int enable; + unsigned int frame_cnt; + /* pic info */ + unsigned int canvas_w; + unsigned int canvas_h; + unsigned int size_y; //real size + unsigned int size_uv; + unsigned int size_pic; + unsigned int last_size_pic; + void *y_vaddr; + void *uv_vaddr; + ulong y_phyaddr; + ulong uv_phyaddr; + + int file_cnt; + atomic_t work_inited; + struct work_struct frame_check_work; + + struct pic_check_t pic_check; + struct pic_dump_t pic_dump; +}; + +int dump_yuv_trig(struct pic_check_mgr_t *mgr, + int id, int start, int num); + +int decoder_do_frame_check(struct vframe_s *vf, int core_mask); + +int frame_check_init(struct pic_check_mgr_t *mgr, int id); + +void frame_check_exit(struct pic_check_mgr_t *mgr); + +ssize_t frame_check_show(struct class *class, + struct class_attribute *attr, char *buf); + +ssize_t frame_check_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t size); + +ssize_t dump_yuv_show(struct class *class, + struct class_attribute *attr, char *buf); + +ssize_t dump_yuv_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t size); + +void vdec_frame_check_exit(struct vdec_s *vdec); +int vdec_frame_check_init(struct vdec_s *vdec); + +#endif /* __FRAME_CHECK_H__ */ + diff --git a/drivers/frame_provider/decoder/utils/vdec.c b/drivers/frame_provider/decoder/utils/vdec.c index 06f4d16..97c32a6 100644 --- a/drivers/frame_provider/decoder/utils/vdec.c +++ b/drivers/frame_provider/decoder/utils/vdec.c @@ -68,6 +68,7 @@ #include <linux/amlogic/media/frame_sync/ptsserv.h> #include "secprot.h" #include "../../../common/chips/decoder_cpu_ver_info.h" +#include "frame_check.h" static DEFINE_MUTEX(vdec_mutex); @@ -88,7 +89,6 @@ static unsigned int clk_config; static unsigned int debug; static int hevc_max_reset_count; -#define MAX_INSTANCE_MUN 9 static int no_powerdown; static int parallel_decode = 1; @@ -1608,6 +1608,52 @@ static const char *get_dev_name(bool use_legacy_vdec, int format) #endif } +struct vdec_s *vdec_get_with_id(unsigned id) +{ + struct vdec_s *vdec, *ret_vdec = NULL; + struct vdec_core_s *core = vdec_core; + unsigned long flags; + + if (id >= MAX_INSTANCE_MUN) + return NULL; + + flags = vdec_core_lock(vdec_core); + if (!list_empty(&core->connected_vdec_list)) { + list_for_each_entry(vdec, &core->connected_vdec_list, list) { + if (vdec->id == id) { + pr_info("searched avaliable vdec connected, id = %d\n", id); + ret_vdec = vdec; + break; + } + } + } + vdec_core_unlock(vdec_core, flags); + + return ret_vdec; +} + +void *vdec_get_active_vfc(int core_mask) +{ + void *p = NULL; + struct vdec_s *vdec = vdec_core->last_vdec; + + if (vdec_core->parallel_dec == 1) { + if (core_mask & CORE_MASK_VDEC_1) + vdec = vdec_core->active_vdec; + else if (core_mask & CORE_MASK_HEVC) + vdec = vdec_core->active_hevc; + else + vdec = vdec_core->last_vdec; + } + + if (vdec == NULL) + return NULL; + + p = &vdec->vfc; + + return p; +} + /* *register vdec_device * create output, vfm or create ionvideo output @@ -1666,6 +1712,12 @@ s32 vdec_init(struct vdec_s *vdec, int is_4k) id = vdec->id; p->parallel_dec = parallel_decode; vdec_core->parallel_dec = parallel_decode; + vdec->canvas_mode = CANVAS_BLKMODE_32X32; +#ifdef FRAME_CHECK + if (vdec_single(vdec)) + vdec_core->last_vdec = vdec; + vdec_frame_check_init(vdec); +#endif p->dev = platform_device_register_data( &vdec_core->vdec_core_platform_device->dev, dev_name, @@ -1903,6 +1955,11 @@ void vdec_release(struct vdec_s *vdec) || (atomic_read(&vdec->inirq_thread_flag) > 0)) schedule(); +#ifdef FRAME_CHECK + vdec_frame_check_exit(vdec); + if (vdec_single(vdec)) + vdec_core->active_vdec = NULL; +#endif platform_device_unregister(vdec->dev); pr_debug("vdec_release instance %p, total %d\n", vdec, atomic_read(&vdec_core->vdec_nr)); @@ -4019,6 +4076,12 @@ static struct class_attribute vdec_class_attrs[] = { __ATTR(debug, S_IRUGO | S_IWUSR | S_IWGRP, show_debug, store_debug), #endif +#ifdef FRAME_CHECK + __ATTR(dump_yuv, S_IRUGO | S_IWUSR | S_IWGRP, + dump_yuv_show, dump_yuv_store), + __ATTR(frame_check, S_IRUGO | S_IWUSR | S_IWGRP, + frame_check_show, frame_check_store), +#endif __ATTR_NULL }; diff --git a/drivers/frame_provider/decoder/utils/vdec.h b/drivers/frame_provider/decoder/utils/vdec.h index 358b979..e3fa681 100644 --- a/drivers/frame_provider/decoder/utils/vdec.h +++ b/drivers/frame_provider/decoder/utils/vdec.h @@ -32,6 +32,7 @@ /*#define CONFIG_AM_VDEC_DV*/ #include "vdec_input.h" +#include "frame_check.h" s32 vdec_dev_register(void); s32 vdec_dev_unregister(void); @@ -43,6 +44,8 @@ struct device *get_vdec_device(void); int vdec_module_init(void); void vdec_module_exit(void); +#define MAX_INSTANCE_MUN 9 + #define VDEC_DEBUG_SUPPORT #define DEC_FLAG_HEVC_WORKAROUND 0x01 @@ -180,6 +183,7 @@ struct vdec_s { int flag; int sched; int need_more_data; + u32 canvas_mode; struct completion inactive_done; @@ -197,6 +201,8 @@ struct vdec_s { /* input */ struct vdec_input_s input; + struct pic_check_mgr_t vfc; + /* mc cache */ u32 mc[4096 * 4]; bool mc_loaded; @@ -431,4 +437,8 @@ int vdec_get_status(struct vdec_s *vdec); void vdec_set_timestamp(struct vdec_s *vdec, u64 timestamp); +struct vdec_s *vdec_get_with_id(unsigned id); + +void *vdec_get_active_vfc(int core_mask); + #endif /* VDEC_H */ diff --git a/drivers/frame_provider/decoder/vp9/vvp9.c b/drivers/frame_provider/decoder/vp9/vvp9.c index be64a0d..eedaed6 100644 --- a/drivers/frame_provider/decoder/vp9/vvp9.c +++ b/drivers/frame_provider/decoder/vp9/vvp9.c @@ -6878,6 +6878,7 @@ static int prepare_display_buf(struct VP9Decoder_s *pbi, && (debug & VP9_DEBUG_NO_TRIGGER_FRAME) == 0 )) { inc_vf_ref(pbi, pic_config->index); + decoder_do_frame_check(vf, CORE_MASK_HEVC); kfifo_put(&pbi->display_q, (const struct vframe_s *)vf); pbi->vf_pre_count++; #ifndef CONFIG_AMLOGIC_MEDIA_MULTI_DEC |