summaryrefslogtreecommitdiff
authorshihong.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)
commit6cd5e0916bbbfab30f83ef2f34fbb8b779cfbc52 (patch)
tree4a9e4ee248fcfff3f4d1ca3bc7c4e716b8908cd1
parent1f67eb9d58de6ea87d81d4bdae0b93ea95be3e13 (diff)
downloadmedia_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>
Diffstat
-rw-r--r--drivers/frame_provider/decoder/avs2/vavs2.c2
-rw-r--r--drivers/frame_provider/decoder/h264/vh264.c35
-rw-r--r--drivers/frame_provider/decoder/h264_multi/vmh264.c25
-rw-r--r--drivers/frame_provider/decoder/h265/vh265.c3
-rw-r--r--drivers/frame_provider/decoder/utils/Makefile2
-rw-r--r--drivers/frame_provider/decoder/utils/amlogic_fbc_hook.c104
-rw-r--r--drivers/frame_provider/decoder/utils/amlogic_fbc_hook.h55
-rw-r--r--drivers/frame_provider/decoder/utils/frame_check.c1038
-rw-r--r--drivers/frame_provider/decoder/utils/frame_check.h110
-rw-r--r--drivers/frame_provider/decoder/utils/vdec.c65
-rw-r--r--drivers/frame_provider/decoder/utils/vdec.h10
-rw-r--r--drivers/frame_provider/decoder/vp9/vvp9.c1
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